写在前面:
前面的文章我们的SPI是用的STM32的资源,IIC也有STM32的硬IIC,本文不用,而是自己写时序来模拟IIC通讯。
读写AT24C02。
做IIC准备2个问题 A微秒级别的延时怎么做?B器件的地址你怎么确定。
开始:
用clubeMX软件看到 STM32芯片的IIC1用的是PB7 PB6
短接跳线帽 PB7--SDA PB6--SCL
原子的风格:
//IO方向设置
#define SDA_IN() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}
等待有空再研究。暂时搁浅。
做IIC思考2个问题1延时函数怎么做?(我用TIMER4)2器件地址
所以 我的地址和刘洋的是一样的,全部接地那就是0呀
写地址0x1010 000 0 0XA0
读地址0x1010 000 1 0XA1
开始代码吧
特地:写之前可以不用擦除会自动覆盖,可以一个bit的写。
测试代码
void Initialise(void)
{
TIM4_Init();//us延时的
I2C_Init();//软件IIC起来
TIMDelay_Nms(1);//工作之前需要延时
AT24Cxx_WriteTwoByte(0,0x7897);//写入EEPROM
dt=AT24Cxx_ReadTwoByte(0);//读出来
}
软件IIC
#ifndef __SOFTIIC_H
#define __SOFTIIC_H
#include "sys.h"
//如果移植程序时只要改一下三个地方就行了
#define I2C_SCL GPIO_Pin_6
#define I2C_SDA GPIO_Pin_7
#define GPIO_I2C GPIOB
#define I2C_SCL_H GPIO_SetBits(GPIO_I2C,I2C_SCL)
#define I2C_SCL_L GPIO_ResetBits(GPIO_I2C,I2C_SCL)
#define I2C_SDA_H GPIO_SetBits(GPIO_I2C,I2C_SDA)
#define I2C_SDA_L GPIO_ResetBits(GPIO_I2C,I2C_SDA)
void I2C_Init(void);
void I2C_SDA_OUT(void);
void I2C_SDA_IN(void);
void I2C_Start(void);
void I2C_Stop(void);
void I2C_Ack(void);
void I2C_NAck(void);
u8 I2C_Wait_Ack(void);
void I2C_Send_Byte(u8 txd);
u8 I2C_Read_Byte(u8 ack);
#endif
#include "softiic.h"
#include "TIM4er.h"
#define delay_us TIMDelay_Nus
//2脚的初始化
void I2C_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=I2C_SCL|I2C_SDA;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(GPIO_I2C,&GPIO_InitStructure);
I2C_SCL_H;
I2C_SDA_H;
}
//SDA脚设置为OUT
void I2C_SDA_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=I2C_SDA;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(GPIO_I2C,&GPIO_InitStructure);
}
//SDA脚设置为IN
void I2C_SDA_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=I2C_SDA;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Init(GPIO_I2C,&GPIO_InitStructure);
}
//产生起始信号
void I2C_Start(void)
{
I2C_SDA_OUT();
I2C_SDA_H;
I2C_SCL_H;
delay_us(5);
I2C_SDA_L;
delay_us(6);
I2C_SCL_L;
}
//产生停止信号
void I2C_Stop(void)
{
I2C_SDA_OUT();
I2C_SCL_L;
I2C_SDA_L;
I2C_SCL_H;
delay_us(6);
I2C_SDA_H;
delay_us(6);
}
//主机产生应答信号ACK
void I2C_Ack(void)
{
I2C_SCL_L;
I2C_SDA_OUT();
I2C_SDA_L;
delay_us(2);
I2C_SCL_H;
delay_us(5);
I2C_SCL_L;
}
//主机不产生应答信号NACK
void I2C_NAck(void)
{
I2C_SCL_L;
I2C_SDA_OUT();
I2C_SDA_H;
delay_us(2);
I2C_SCL_H;
delay_us(5);
I2C_SCL_L;
}
//等待从机应答信号
//返回值:1 接收应答失败
// 0 接收应答成功
u8 I2C_Wait_Ack(void)
{
u8 tempTime=0;
I2C_SDA_IN();
I2C_SDA_H;
delay_us(1);
I2C_SCL_H;
delay_us(1);
while(GPIO_ReadInputDataBit(GPIO_I2C,I2C_SDA))
{
tempTime++;
if(tempTime>250)
{
I2C_Stop();
return 1;
}
}
I2C_SCL_L;
return 0;
}
//I2C 发送一个字节
void I2C_Send_Byte(u8 txd)
{
u8 i=0;
I2C_SDA_OUT();
I2C_SCL_L;//拉低时钟开始数据传输
for(i=0;i<8;i++)
{
if((txd&0x80)>0) //0x80 1000 0000
I2C_SDA_H;
else
I2C_SDA_L;
txd<<=1;
I2C_SCL_H;
delay_us(2); //发送数据
I2C_SCL_L;
delay_us(2);
}
}
//I2C 读取一个字节
u8 I2C_Read_Byte(u8 ack)
{
u8 i=0,receive=0;
I2C_SDA_IN();
for(i=0;i<8;i++)
{
I2C_SCL_L;
delay_us(2);
I2C_SCL_H;
receive<<=1;
if(GPIO_ReadInputDataBit(GPIO_I2C,I2C_SDA))
receive++;
delay_us(1);
}
if(ack==0)
I2C_NAck();
else
I2C_Ack();
return receive;
}
#include "AT24C02.h"
#include "TIM4er.h"
#define delay_ms TIMDelay_Nms
#define IICADDR_W 0xA0
#define IICADDR_R 0xA1
u8 AT24Cxx_ReadOneByte(u16 addr)
{
u8 temp=0;
I2C_Start();
if(EE_TYPE>AT24C16)
{
I2C_Send_Byte(IICADDR_W);
I2C_Wait_Ack();
I2C_Send_Byte(addr>>8); //发送数据地址高位
}
else
{
I2C_Send_Byte(IICADDR_W+((addr/256)<<1));//器件地址+数据地址
}
I2C_Wait_Ack();
I2C_Send_Byte(addr%256);//双字节是数据地址低位
//单字节是数据地址低位
I2C_Wait_Ack();
I2C_Start();
I2C_Send_Byte(IICADDR_R);
I2C_Wait_Ack();
temp=I2C_Read_Byte(0); // 0 代表 NACK
I2C_Stop();
return temp;
}
u16 AT24Cxx_ReadTwoByte(u16 addr)
{
u16 temp=0;
I2C_Start();
if(EE_TYPE>AT24C16)
{
I2C_Send_Byte(IICADDR_W);
I2C_Wait_Ack();
I2C_Send_Byte(addr>>8); //发送数据地址高位
}
else
{
I2C_Send_Byte(IICADDR_W+((addr/256)<<1));//器件地址+数据地址
}
I2C_Wait_Ack();
I2C_Send_Byte(addr%256);//双字节是数据地址低位
//单字节是数据地址低位
I2C_Wait_Ack();
I2C_Start();
I2C_Send_Byte(IICADDR_R);
I2C_Wait_Ack();
temp=I2C_Read_Byte(1); // 1 代表 ACK
temp<<=8;
temp|=I2C_Read_Byte(0); // 0 代表 NACK
I2C_Stop();
return temp;
}
void AT24Cxx_WriteOneByte(u16 addr,u8 dt)
{
I2C_Start();
if(EE_TYPE>AT24C16)
{
I2C_Send_Byte(IICADDR_W);
I2C_Wait_Ack();
I2C_Send_Byte(addr>>8); //发送数据地址高位
}
else
{
I2C_Send_Byte(IICADDR_W+((addr/256)<<1));//器件地址+数据地址
}
I2C_Wait_Ack();
I2C_Send_Byte(addr%256);//双字节是数据地址低位
//单字节是数据地址低位
I2C_Wait_Ack();
I2C_Send_Byte(dt);
I2C_Wait_Ack();
I2C_Stop();
delay_ms(10);
}
void AT24Cxx_WriteTwoByte(u16 addr,u16 dt)
{
I2C_Start();
if(EE_TYPE>AT24C16)
{
I2C_Send_Byte(IICADDR_W);
I2C_Wait_Ack();
I2C_Send_Byte(addr>>8); //发送数据地址高位
}
else
{
I2C_Send_Byte(IICADDR_W+((addr/256)<<1));//器件地址+数据地址
}
I2C_Wait_Ack();
I2C_Send_Byte(addr%256);//双字节是数据地址低位
//单字节是数据地址低位
I2C_Wait_Ack();
I2C_Send_Byte(dt>>8);
I2C_Wait_Ack();
I2C_Send_Byte(dt&0xFF);
I2C_Wait_Ack();
I2C_Stop();
delay_ms(10);
}
#ifndef _AT24C02_H
#define _AT24C02_H
#include "softiic.h"
#define AT24C01 127
#define AT24C02 255
#define AT24C04 511
#define AT24C08 1023
#define AT24C16 2047
#define AT24C32 4095
#define AT24C64 8191
#define AT24C128 16383
#define AT24C256 32767
#define EE_TYPE AT24C02
u8 AT24Cxx_ReadOneByte(u16 addr);
u16 AT24Cxx_ReadTwoByte(u16 addr);
void AT24Cxx_WriteOneByte(u16 addr,u8 dt);
void AT24Cxx_WriteTwoByte(u16 addr,u16 dt);
#endif