最近项目用到了二氧化碳气体检测,选择了奥松二氧化碳传感器模块(模块资料,可在文章最后连接下载),该模块有串口通信和IIC通信,由于项目中串口被其他资源占用,于是只能使用IIC通信读取二氧化碳数据。
本篇文章做个项目记录,程序为项目实测验证,有需求网友可以借阅!
二氧化碳传感器IIC通信IO口使用的是PA0与PA1,其配置如下:
1、IO口配置
PA1---SDA
PA0---SCL
#define SDA_OUT {GPIOA->CRL &= 0XFFFFFF0F; GPIOA->CRL |= 0X00000070;} //配置GPIOA 1 为开漏输出
#define SDA_IN {GPIOA->CRL &= 0XFFFFFF0F; GPIOA->CRL |= 0X00000040;} //配置GPIOA 1 为浮空输入
#define SCL_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET) //PA0
#define SCL_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET)
#define SDA_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET) //PA1
#define SDA_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET)
2、 程序
//注意这里的延时IIC_delay() 要让IIC频率低于100Khz
void IIC_Start(void)
{
SDA_OUT;
SDA_H;
IIC_delay();
SCL_H;
IIC_delay();
SDA_L;
IIC_delay();
SCL_L;
IIC_delay();
}
void IIC_WriteByte(uint8_t data)
{
uint8_t i=0;
SDA_OUT;
for(i=0;i<8;i++)
{
SCL_L;
IIC_delay();
if(data&0x80)
{
SDA_H;
}
else
{
SDA_L;
}
SCL_H;
IIC_delay();
data<<=1;
}
SCL_L;
IIC_delay();
SDA_IN;
IIC_delay();
}
uint8_t IIC_ReadByte()
{
uint8_t Byte,i,a;
Byte = 0;
SCL_L;
SDA_IN;
IIC_delay();
for(i=0;i<8;i++)
{
SCL_H;
IIC_delay();
a = 0;
if((GPIOA->IDR&0x0002)==0x0002)
a=1;
Byte = (Byte << 1) | a;
SCL_L;
IIC_delay();
}
SDA_IN;
IIC_delay();
return Byte;
}
uint8_t Receive_ACK()
{
uint8_t CNT;
CNT = 0;
SCL_L;
SDA_IN;
IIC_delay();
SCL_H;
IIC_delay();
while((((GPIOA->IDR&0x0002)==0x0002))&& CNT < 200) //(GPIOA->IDR&0x0020)==0x0020
{
CNT++;
}
if(CNT >= 200)
{
return 1;//无应答
}
SCL_L;
IIC_delay();
return 0;
}
void Send_ACK()//主机回复应答信号
{
SDA_OUT;
SCL_L;
IIC_delay();
SDA_L;
IIC_delay();
SCL_H;
IIC_delay();
SCL_L;
IIC_delay();
}
void Send_NOT_ACK()//主机不应答
{
SDA_OUT;
SCL_L;
IIC_delay();
SDA_H;
IIC_delay();
SCL_H;
IIC_delay();
SCL_L;
IIC_delay();
SDA_L;
IIC_delay();
}
void IIC_Stop(void)//SLK高电平,DIO变高 为停止信号
{
SDA_OUT;
SDA_L;
IIC_delay();
SCL_H;
IIC_delay();
SDA_H;
IIC_delay();
}
uint8_t Calc_CRC8(uint8_t *dat, uint8_t Num)
{
uint8_t i,byte,crc=0xFF;
for(byte=0; byte<Num; byte++)
{
crc^=(dat[byte]);
for(i=0;i<8;i++)
{
if(crc & 0x80) crc=(crc<<1)^0x31;
else crc=(crc<<1);
}
}
return crc;
}
uint32_t ACD10_Read_Data(void)
{
uint8_t Byte[6],CRC_Byte[3];
IIC_Start();
IIC_WriteByte(0X54);
if(Receive_ACK()==1)
return 1;
IIC_WriteByte(0X03);
if(Receive_ACK()==1)
return 1;
IIC_WriteByte(0X00);
if(Receive_ACK()==1)
return 1;
IIC_Stop();
HAL_Delay(10);
IIC_Start();
IIC_WriteByte(0X55);
if(Receive_ACK()==1)
return 1;
Byte[0] = IIC_ReadByte();
Send_ACK();
Byte[1] = IIC_ReadByte();
Send_ACK();
CRC_Byte[0] = IIC_ReadByte();
Send_ACK();
Byte[2]=IIC_ReadByte();
Send_ACK();
Byte[3]=IIC_ReadByte();
Send_ACK();
CRC_Byte[1]=IIC_ReadByte();
Send_ACK();
Byte[4]=IIC_ReadByte();
Send_ACK();
Byte[5]=IIC_ReadByte();
Send_ACK();
CRC_Byte[2]=IIC_ReadByte();
Send_NOT_ACK();
IIC_Stop();
if((Calc_CRC8(Byte,2)!=CRC_Byte[0])||(Calc_CRC8(Byte+2,2)!=CRC_Byte[1])||(Calc_CRC8(Byte+4,2)!=CRC_Byte[2]))
return 2;//CRC校验出错
CO2Data = 0;//这里要清0,官网给出的程序未清0,(由于CO2Data是全局变量),导致CO2浓度值非常高
CO2Data=(CO2Data|Byte[0])<<8;
CO2Data=(CO2Data|Byte[1])<<8;
CO2Data=(CO2Data|Byte[2])<<8;
CO2Data=(CO2Data|Byte[3]);
return 0;
}
3、逻辑分析仪数据
IIC发出写指令
需要注意一下:程序写的是地址是0X54,但上图片的Address Write:2A ,不要被这个给迷惑(本人从这里就被迷惑了一小会,脑子短路了),其实是这样的,程序中的0X54包含了IIC 的最低位的写指令,而逻辑分析仪把这个最低位分析为Wr,其它7位为地址,所以出现2A。
IIC读---CO2模块返回的数据
IIC时钟
这个二氧化碳传感器的IIC时钟最大为100Khz,太大读取数据有错误,所以贴个图片,提醒自己不要忽略。
相关资料下载如下: