记录使用模拟 I2C 所遇到的问题

首先贴上代码,我所经常使用的模拟I2C代码

#include "myiic.h"
#define device_addr 0x52
/* 模拟IIC引脚方向配置,这里用的是华大的单片机,根据需要更改 */ void Analog_IIC_Pin_Init(void) { stc_gpio_cfg_t stcGpioCfg; ///< 打开GPIO外设时钟门控 Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE); ///< 端口方向配置->输出(其它参数与以上(输入)配置参数一致) stcGpioCfg.enDir = GpioDirOut; ///< 端口上下拉配置-> stcGpioCfg.enPu = GpioPuDisable; stcGpioCfg.enPd = GpioPdDisable; ///< GPIO IO 端口初始化 Gpio_Init(SDA_GPIO_PORT, SDA_GPIO_PIN, &stcGpioCfg); Gpio_Init(SCL_GPIO_PORT, SCL_GPIO_PIN, &stcGpioCfg); ///< 端口方向配置->输出(其它参数与以上(输入)配置参数一致) stcGpioCfg.enDir = GpioDirIn; ///< 端口驱动能力配置->高驱动能力 stcGpioCfg.enDrv = GpioDrvL; ///< 端口上下拉配置-> stcGpioCfg.enPu = GpioPuEnable;//Enable stcGpioCfg.enPd = GpioPdDisable; ///< 端口开漏输出配置->开漏输出关闭 stcGpioCfg.enOD = GpioOdDisable; ///< 端口输入/输出值寄存器总线控制模式配置->AHB stcGpioCfg.enCtrlMode = GpioAHB; Gpio_Init(INTN_GPIO_PORT, INTN_GPIO_PIN, &stcGpioCfg); ///< 打开并配置GPIO2为上升沿中断 Gpio_EnableIrq(INTN_GPIO_PORT, INTN_GPIO_PIN, GpioIrqFalling);//GpioIrqRising GpioIrqFalling ///< 使能端口PORTA系统中断 EnableNvic(PORTA_IRQn, IrqLevel0, TRUE); IIC_SCL_1; //拉高时钟线 IIC_SDA_1; //拉高数据线 } void IIC_SDA_Dir(unsigned char d) { stc_gpio_cfg_t stcGpioCfg; if (d == 1) //输出 { ///< 端口方向配置->输出(其它参数与以上(输入)配置参数一致) stcGpioCfg.enDir = GpioDirOut; ///< 端口上下拉配置-> stcGpioCfg.enPu = GpioPuDisable; stcGpioCfg.enPd = GpioPdDisable; ///< GPIO IO 端口初始化 Gpio_Init(SDA_GPIO_PORT, SDA_GPIO_PIN, &stcGpioCfg); } else if (d == 0) //输入 { ///< 端口方向配置->输出(其它参数与以上(输入)配置参数一致) stcGpioCfg.enDir = GpioDirIn; ///< 端口上下拉配置-> stcGpioCfg.enPu = GpioPuDisable; stcGpioCfg.enPd = GpioPdDisable; ///< GPIO IO 端口初始化 Gpio_Init(SDA_GPIO_PORT, SDA_GPIO_PIN, &stcGpioCfg); } } //产生IIC起始信号 void IIC_Start(void) { IIC_SDA_Dir(1);//IIC_SDA线输出 IIC_SDA_1; //拉高数据线 IIC_SCL_1; //拉高时钟线 delay10us(2); IIC_SDA_0; //拉低数据线 delay10us(2); IIC_SCL_0; //拉低时钟线 发送IIC总线开始信号 } //产生IIC停止信号 void IIC_Stop(void) { IIC_SDA_Dir(1);//IIC_SDA线输出 IIC_SCL_0; //拉低时钟线 IIC_SDA_0; //拉低数据线 delay10us(2); IIC_SCL_1; //拉高时钟线 delay10us(2); IIC_SDA_1; //拉高数据线 发送IIC总线停止信号 delay10us(2); } //产生ACK应答 void IIC_Ack(void) { IIC_SCL_0; //拉低时钟线 IIC_SDA_Dir(1);//IIC_SDA线输出 IIC_SDA_0; //拉低数据线 delay10us(2); IIC_SCL_1; //拉高时钟线 delay10us(2); IIC_SCL_0; //拉低时钟线 } //不产生ACK应答 void IIC_NAck(void) { IIC_SCL_0; //拉低时钟线 IIC_SDA_Dir(1);//IIC_SDA线输出 IIC_SDA_1; //拉高数据线 delay10us(2); IIC_SCL_1; //拉高时钟线 delay10us(2); 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; //拉高数据线 delay10us(2); IIC_SCL_1; //拉高时钟线 等待应答信号 delay10us(2); 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; //数据移位 delay10us(2); IIC_SCL_1; //拉高时钟线 delay10us(2); IIC_SCL_0; //拉低时钟线 准备开始传送数据位 delay10us(2); } } //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; //拉低时钟线 准备开始传送数据位 delay10us(2); IIC_SCL_1; //拉高时钟线 RByte <<= 1; //数据移位 if (IIC_SDA) { RByte++; } delay10us(2); } 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停止信号 }

 


 

 ①

https://www.cnblogs.com/KingZhan/p/16330358.html

在一次使用颜色传感器TCS3472的过程中,发现怎么都通信不了。最后在网上找到说明,规格书上有特别说明

 

 即输入的所有地址,最后一位都得是1

也就是说,我上面的模拟I2C的代码中,最后的四个函数,都要加上使寄存器的地址最高为置1,这样才能正常通信。

好吧,规格书还是要好好看的,每个传感器都有自己的特点

posted @ 2022-08-30 10:02  kingzhan  阅读(157)  评论(0编辑  收藏  举报