I2C上地址的使用问题
#include "myiic.h" /* 模拟IIC引脚方向配置 */ void Analog_IIC_Pin_Init(void)//IO初始化
{ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE); GPIO_InitStructure.GPIO_Pin = I2C_SCL | I2C_SDA; //选择端口号 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择IO接口工作方式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO接口速度(2/10/50MHz) GPIO_Init(I2CPORT, &GPIO_InitStructure); IIC_SDA_1; //拉高数据线 IIC_SCL_1; //拉高时钟线 } void IIC_SDA_Dir(unsigned char d) { GPIO_InitTypeDef GPIO_InitStructure; if (d == 1) //输出 { GPIO_InitStructure.GPIO_Pin = I2C_SDA; //选择端口号 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择IO接口工作方式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO接口速度(2/10/50MHz) GPIO_Init(I2CPORT, &GPIO_InitStructure); } else if (d == 0) //输入 { GPIO_InitStructure.GPIO_Pin = I2C_SDA; //选择端口号 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //选择IO接口工作方式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO接口速度(2/10/50MHz) GPIO_Init(I2CPORT, &GPIO_InitStructure); } } //产生IIC起始信号 void IIC_Start(void) { IIC_SDA_Dir(1);//IIC_SDA线输出 IIC_SDA_1; //拉高数据线 IIC_SCL_1; //拉高时钟线 delay_us(40); IIC_SDA_0; //拉低数据线 delay_us(40); IIC_SCL_0; //拉低时钟线 发送IIC总线开始信号 } //产生IIC停止信号 void IIC_Stop(void) { IIC_SDA_Dir(1);//IIC_SDA线输出 IIC_SCL_0; //拉低时钟线 IIC_SDA_0; //拉低数据线 delay_us(40); IIC_SCL_1; //拉高时钟线 delay_us(40); IIC_SDA_1; //拉高数据线 发送IIC总线停止信号 delay_us(40); } //产生ACK应答 void IIC_Ack(void) { IIC_SCL_0; //拉低时钟线 IIC_SDA_Dir(1);//IIC_SDA线输出 IIC_SDA_0; //拉低数据线 delay_us(40); IIC_SCL_1; //拉高时钟线 delay_us(40); IIC_SCL_0; //拉低时钟线 } //不产生ACK应答 void IIC_NAck(void) { IIC_SCL_0; //拉低时钟线 IIC_SDA_Dir(1);//IIC_SDA线输出 IIC_SDA_1; //拉高数据线 delay_us(40); IIC_SCL_1; //拉高时钟线 delay_us(40); IIC_SCL_0; //拉低时钟线 } //等待应答信号到来 //返回值:1 接收应答失败 // 0 接收应答成功 unsigned char IIC_Wait_Ack(void) { unsigned char Wait_TOut_Cnt = 0;//设置等待应答信号超时计数 IIC_SDA_Dir(0); //IIC_SDA线输入 IIC_SDA_1; //拉高数据线 delay_us(40); IIC_SCL_1; //拉高时钟线 等待应答信号 delay_us(40); while (IIC_SDA) { Wait_TOut_Cnt++; if (Wait_TOut_Cnt > 250) { IIC_Stop(); //等待应答信号超时 发送IIC总线停止信号 return 1; } } IIC_SCL_0; //拉低时钟线 结束应答信号 return 0; } //IIC发送一个字节 void IIC_Write_Byte(unsigned char WByte) { unsigned char Wb_Cnt = 0; //写数据位计数 IIC_SDA_Dir(1);//IIC_SDA线输出 IIC_SCL_0; //拉低时钟线 开始数据传输 for (Wb_Cnt = 0; Wb_Cnt < 8; Wb_Cnt++) { if (WByte & 0x80) { IIC_SDA_1; } else { IIC_SDA_0; } WByte <<= 1; //数据移位 delay_us(40); IIC_SCL_1; //拉高时钟线 delay_us(40); IIC_SCL_0; //拉低时钟线 准备开始传送数据位 delay_us(40); } } //IIC读取一个字节 //参数值:1 发送Ack // 0 不发送Ack unsigned char IIC_Read_Byte(unsigned char SF_Ack) { unsigned char Rb_Cnt = 0; //读数据位计数 unsigned char RByte = 0; //读字节 IIC_SDA_Dir(0);//SDA设置为输入 for (Rb_Cnt = 0; Rb_Cnt < 8; Rb_Cnt++) { IIC_SCL_0; //拉低时钟线 准备开始传送数据位 delay_us(40); IIC_SCL_1; //拉高时钟线 RByte <<= 1; //数据移位 if (IIC_SDA) { RByte++; } delay_us(40); } if (!SF_Ack) //0 不发送Ack { IIC_NAck(); //发送NAck } else //1 发送Ack { IIC_Ack(); //发送Ack } return RByte; } /* 写一个字节 */ void Sensor_Write_Byte(unsigned char sensor_addr, unsigned char RAddr, unsigned char* WData) { IIC_Start(); //发送IIC起始信号 IIC_Write_Byte(sensor_addr);//发送IIC写地址 IIC_Wait_Ack(); //等待IIC应答信号 IIC_Write_Byte(RAddr); //发送IIC寄存器地址 IIC_Wait_Ack(); //等待IIC应答信号 IIC_Write_Byte(*WData); //发送写入寄存器的数据 IIC_Wait_Ack(); //等待IIC应答信号 IIC_Stop(); //发送IIC停止信号 } /* 写N个字节 */ void Sensor_Write_NByte(unsigned char sensor_addr, unsigned char RAddr, unsigned char* WData, unsigned char WLen) { unsigned char WB_Cnt = 0; IIC_Start(); //发送IIC起始信号 IIC_Write_Byte(sensor_addr);//发送IIC写地址 IIC_Wait_Ack(); //等待IIC应答信号 IIC_Write_Byte(RAddr); //发送IIC寄存器地址 IIC_Wait_Ack(); //等待IIC应答信号 for (WB_Cnt = 0; WB_Cnt < WLen; WB_Cnt++) { IIC_Write_Byte(WData[WB_Cnt]);//连续读取寄存器的数据 等待应答信号 IIC_Wait_Ack(); //等待IIC应答信号 } IIC_Stop(); //发送IIC停止信号 } /* 读一个字节 */ void Sensor_Read_Byte(unsigned char sensor_addr, unsigned char RAddr, unsigned char* RData) { IIC_Start(); //发送IIC起始信号 IIC_Write_Byte(sensor_addr); //发送IIC写地址 IIC_Wait_Ack(); //等待IIC应答信号 IIC_Write_Byte(RAddr); //发送IIC寄存器地址 IIC_Wait_Ack(); //等待IIC应答信号 IIC_Start(); //发送IIC起始信号 IIC_Write_Byte(sensor_addr + 1);//发送IIC读地址 IIC_Wait_Ack(); //等待IIC应答信号 *RData = IIC_Read_Byte(0); //读取寄存器的数据 IIC_Stop(); //发送IIC停止信号 } /* 读N个字节 */ void Sensor_Read_NByte(unsigned char sensor_addr, unsigned char RAddr, unsigned char* RData, unsigned char RLen) { unsigned char RB_Cnt = 0; //读字节计数 IIC_Start(); //发送IIC起始信号 IIC_Write_Byte(sensor_addr); //发送IIC写地址 IIC_Wait_Ack(); //等待IIC应答信号 IIC_Write_Byte(RAddr); //发送IIC寄存器地址 IIC_Wait_Ack(); //等待IIC应答信号 IIC_Start(); //发送IIC起始信号 IIC_Write_Byte(sensor_addr + 1); //发送IIC读地址 IIC_Wait_Ack(); //等待IIC应答信号 for (RB_Cnt = 0; RB_Cnt < (RLen - 1); RB_Cnt++) { RData[RB_Cnt] = IIC_Read_Byte(1);//连续读取寄存器的数据 等待应答信号 } RData[RB_Cnt] = IIC_Read_Byte(0); //读取寄存器最后一个数据 不等待应答信号 IIC_Stop(); //发送IIC停止信号 }
myiic.h
#ifndef __MYIIC_H #define __MYIIC_H #include "usart.h" #include "delay.h" #include "sys.h" #define I2CPORT GPIOB //定义IO接口 #define I2C_SCL GPIO_Pin_6 //定义IO接口 #define I2C_SDA GPIO_Pin_7 //定义IO接口 //IO方向设置 #define IIC_SDA_0 GPIO_WriteBit(I2CPORT,I2C_SDA,(BitAction)(0)) //接口输出高电平0 #define IIC_SDA_1 GPIO_WriteBit(I2CPORT,I2C_SDA,(BitAction)(1)) //接口输出高电平1 #define IIC_SDA GPIO_ReadInputDataBit(I2CPORT,I2C_SDA) #define IIC_SCL_0 GPIO_WriteBit(I2CPORT,I2C_SCL,(BitAction)(0)) //接口输出高电平0 #define IIC_SCL_1 GPIO_WriteBit(I2CPORT,I2C_SCL,(BitAction)(1)) //接口输出高电平1 extern void Analog_IIC_Pin_Init(void); extern void IIC_SDA_Dir(unsigned char d); extern void IIC_Start(void); extern void IIC_Stop(void); extern void IIC_Ack(void); extern void IIC_NAck(void); extern unsigned char IIC_Wait_Ack(void); extern void IIC_Write_Byte(unsigned char WByte); extern unsigned char IIC_Read_Byte(unsigned char SF_Ack); extern void Sensor_Write_Byte(unsigned char sensor_addr, unsigned char RAddr, unsigned char* WData); extern void Sensor_Write_NByte(unsigned char sensor_addr, unsigned char RAddr, unsigned char* WData, unsigned char WLen); extern void Sensor_Read_Byte(unsigned char sensor_addr, unsigned char RAddr, unsigned char* RData); extern void Sensor_Read_NByte(unsigned char sensor_addr, unsigned char RAddr, unsigned char* RData, unsigned char RLen); #endif
上面是我的软件I2C的代码
这是某个传感器规格书上的I2C协议,地址为0x44
若是我原来的想法,写寄存器,读寄存器如下
Sensor_Read_Byte(0x44,addr,&data_buf);传感器地址,寄存器地址,变量
Sensor_Write_Byte(0x44,addr,&data);传感器地址,寄存器地址,寄存器数值
可逻辑分析仪上是这样的
虽说我函数里填进去的数值为 01000100(0x44) 但显示出传输的地址为0x22,并不是想象中的0x44
这是因为函数里默认将传进去的数据最后一位当作读写位,结果就是前面一位自动补0,就成了0x22
其实规格书里说的意思是,这个传感器的地址是7bit的,在7bit的情况下,为0x44。
所以在使用的时候,因为第8bit代表着读写位,如果是读,那传进去的地址为0x44<<1|1=0x89,如果是写,那传进去的地址为0x44<<1=0x88
我上面说的传进去的地址是指放在我那个函数里面的数值。如果用逻辑分析仪测到的地址当然就是0x44了
如下:
Sensor_Read_Byte(0x88,0x01,&a); printf("1为:0x%x\n",a);
读操作是先发了一次传感器地址和要读的寄存器,再次发了一遍传感器地址(这次第8bit为1),然后收到数据