STM32模拟IIC读取ACD10红外二氧化碳数据

本文介绍了如何使用ACD10模块通过IIC通信,包括配置引脚、模拟IIC通信方法,以及读取CO2浓度的命令和CRC校验函数的使用。
摘要由CSDN通过智能技术生成
引脚介绍
ACD10通过IIC来通信我们使用下图右边四个引脚就可以了,系统默认模式为IIC通信方式,他也支持USART串口通信不过需要配置pin5引脚(低电平)。

模拟IIC通信配置比较简单,在单片机上面随便找两个引脚就可以。用来配置SDA数据与SCL时钟引脚。

读取数据命令

官方给我们命令行列表也有很多,我们要读取数据使用第一个功能读取CO2的浓度就可以了

iic.c iic.h

下面为模拟IIC的代码已经宏定义

#ifndef __IIC_H
#define	__IIC_H
需要使用到的宏定义

#define ACD10_GPIO GPIOA
#define SDA_PIN GPIO_Pin_4   //这里定义的引脚以及 相关代码中所使用的都是这两个
#define SCL_PIN GPIO_Pin_5    //直接配置成自己选中的引脚即可使用  

#define I2C1_OwnAddress 0x54  //数据手册的地址码
#define SDA_High 	GPIO_SetBits(ACD10_GPIO,SDA_PIN) //拉高数据线
#define SDA_Low 	GPIO_ResetBits(ACD10_GPIO,SDA_PIN) 
#define SCL_High 	GPIO_SetBits(ACD10_GPIO,SCL_PIN) //拉高时钟线
#define SCL_Low 	GPIO_ResetBits(ACD10_GPIO,SCL_PIN) 

void IIC_Start(void);
void IIC_Stop(void);
void IIC_SendACK(int ack);
int IIC_RecvACK(void);
void IIC_SendByte(u8 dat);
u8 IIC_DataByte(void);


//初始化引脚  以及更改切换模式
void SDA_Gpio_init(int flag);
void Acd10_Config(void);

#endif

IIC.c代码 

#include "iic.h"

//起始信号
void IIC_Start(void)
{
	SDA_Gpio_init(1);//更改写模式
	SDA_High;
	SCL_High;
	Delay_us(4);
	SDA_Low;
	Delay_us(4);
	SCL_Low;
	
}

//停止信号
void IIC_Stop(void)
{
	SDA_Gpio_init(1);//更改写模式
	SDA_Low;
	SCL_High;
	Delay_us(4);
	SDA_High;
	Delay_us(4);
}

//发送应答信号 入口参数:ack(0:ACK   1:NAK)
void IIC_SendACK(int ack)
{
	SDA_Gpio_init(1);//更改写模式
	SCL_Low;
	if(ack == 1)   //写应答信号
		SDA_High;
	else if(ack == 0)
		SDA_Low; 
	else
		return;	
	
	SCL_High;
	Delay_us(4);
	SCL_Low;
	Delay_us(4);

}

//接收应答信号
int IIC_RecvACK(void)
{
	uint16_t mcy = 0;
	
	SDA_Gpio_init(0);
	
	SCL_High;
	Delay_us(4);
	if(GPIO_ReadInputDataBit(ACD10_GPIO,SDA_PIN)==1)//读应答信号
		mcy = 1 ;  
  else
    mcy = 0 ;
	SCL_Low;                    //拉低时钟线
  Delay_us(4);                 //延时
	SDA_Gpio_init(1);
  return mcy;
}

//向IIC总线发送一个直接数据
void IIC_SendByte(u8 dat)
{
	SDA_Gpio_init(1);
	for(u8 i=0;i<8;i++)
	{
		if(0x80 & dat)
			SDA_High;
		else
			SDA_Low;
		dat<<=1;
		
		SCL_High;
		Delay_us(4);
		SCL_Low;
		Delay_us(4);	
	}
}

//在IIC总线接收一个字节数据
u8 IIC_DataByte(void)
{
  u8 i;
  u8 dat = 0;  //dat是存放接收到的一个字节的数据


	SDA_High;//使能内部上拉,准备读取数据,
	Delay_us(2);
  for (i=0; i<8; i++)         //8位计数器
  {
    dat <<= 1;       //循环8次,每次接收一个位,8次之后完成一个字节数据的接收
    SCL_High;               //拉高时钟线
    Delay_us(4);             //延时
		dat	|= GPIO_ReadInputDataBit(ACD10_GPIO,SDA_PIN);//读取SDA引脚的电平,如果是高电平,就是传输“1” 
		
		SCL_Low;                //拉低时钟线
    Delay_us(4);          //延时
  }		
  SDA_High;
  return dat;
}

void Acd10_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStruct.GPIO_Pin  = SDA_PIN | SCL_PIN;
	GPIO_InitStruct.GPIO_Speed= GPIO_Speed_50MHz;
	GPIO_Init(ACD10_GPIO, &GPIO_InitStruct);
	
}

//读写模式的更改
void SDA_Gpio_init(int flag)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStruct.GPIO_Pin = SDA_PIN;
	if(flag == 1)
	{//开漏输出
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;//开漏
	}
	else if(flag == 0)
	{//上拉输入
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;//上拉
	}
	GPIO_Init(ACD10_GPIO,&GPIO_InitStruct);
}

 以上为iic的配置

下面是封装一个获取数据的函数


u8 buf[6] = {0} , CRC_buf[3]; u16 CO2 , TEM;
//读取指令
uint8_t Acd10_Read(void)
{
		//向从设备发送
	IIC_Start();
	IIC_SendByte(I2C1_OwnAddress);		//发送设备地址

	if(IIC_RecvACK()==1)
		return 1;
	IIC_SendByte(0x03);								//发送高字节
	if(IIC_RecvACK()==1)
		return 1;
	IIC_SendByte(0x00);								//发送低字节
	if(IIC_RecvACK()==1)
		return 1;
	IIC_Stop();
	
    //这里的延时极为重要,需要给一定的时间在进行发送起始信号,不然会接收不到从机的应答
    Delay_ms(10);
	//接收信息
	//发送起始信号与地址
	IIC_Start();
	IIC_SendByte(I2C1_OwnAddress+1); //读取地址为0x55 在发送的地址加1就可以了
	//判断是否应答
	if(IIC_RecvACK()==1)
		return 1;
	
/*因为要接收9次数据所以直接使用了for 省的我们来回发送应答信号了,每接收两个字节数据我们就需要接收一个CRC,所有上面定义了两个数组 一个用来接收我们co2和tem数据 一个用来接收crc校验。
*/
	for(u8 i=0;i<6;i++)
	{
		buf[i] = IIC_DataByte(); 
		IIC_SendACK(0);       //接收一次需要发送一个应答信号
		Delay_us(2);
		if((i+1)%2 == 0)
		{
			CRC_buf[(i+1)/2-1] = IIC_DataByte(); 
			if(i==5)
				IIC_SendACK(1);//判断是否为最后一次接收,如果是发送接收完毕的应答信号
			else
				IIC_SendACK(0);
		}
	}
	IIC_Stop();
//判断CRC 我们获取到的数据是否正确
	if((Calc_CRC8(buf,2)!=CRC_buf[0])||(Calc_CRC8(buf+2,2)!=CRC_buf[1])||(Calc_CRC8(buf+4,2)!=CRC_buf[2]))
		return 2;//CRC校验出错
	CO2 = (u16)((((u16)buf[0])<<24) | (((u16)buf[1])<<16) |
	(((u16)buf[2])<<8) | ((u16)buf[3]));
	TEM = buf[4] * 256 + buf[5];
	return 0;

}


//CRC校验函数,这个在官方例程中给到了,直接拿来用
u8 Calc_CRC8(unsigned char *data, unsigned char Num)
{
	unsigned char bit, byte, crc=0xFF;
	for(byte=0; byte<Num; byte++)
	{
		crc^=(data[byte]);
		for(bit=8;bit>0;--bit)
		{
			if(crc&0x80) crc=(crc<<1)^0x31;
			else crc=(crc<<1);
		}
	}
	return crc;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值