引脚介绍
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;
}
标签:SCL,ACD10,引脚,void,STM32,SDA,IIC,GPIO
From: https://blog.csdn.net/w1094598477/article/details/136630085