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),然后收到数据

 

posted @ 2022-05-31 14:32  kingzhan  阅读(221)  评论(0编辑  收藏  举报