文章目录
- [一、AIT1001 简介](#一、AIT1001 简介)
- 二、引脚功能
- 三、时序与寄存器数据说明
- 四、程序
- 五、驱动测试现象
摘要: 本文详细介绍 AIT1001 红外热测温模块的 STM32 驱动开发全过程。AIT1001 是一款数字信号与 PWM 模拟信号双输出型的红外热电堆模块,内置 MEMS 热电堆芯片、NTC 热敏电阻及信号处理电路,支持 I2C 通信并带 CRC 校验。文章从模块简介、引脚功能、时序与寄存器说明入手,逐步讲解 CRC 校验算法,并给出完整的 STM32 工程代码(含 USART1 串口打印与 I2C1 通信),最后展示实际接线与串口输出现象,帮助读者快速上手非接触式测温应用。
一、AIT1001 简介
AIT1001 是一款数字信号与PWM模拟信号双输出型的红外热电堆模块,包含MEMS热电堆芯片、NTC热敏电阻以及信号处理电路。产品具有体积小、精度高、质优价廉等优点,适用于需要非接触方式进行测温的场景,如冰箱、吸油烟机和空调等家用电器、汽车空调、室内暖气、手持设备以及医疗设备应用等。


二、引脚功能
| 引脚 | 功能 |
|---|---|
| 1-GND | 电源负 |
| 2-SCL | 时钟线 (需外接 4.7K 上拉电阻) |
| 3-SDA | 数据线 (需外接 4.7K 上拉电阻) |
| 4-VCC | 电源正 |
| 5-PWM | PWM输出 |

三、时序与寄存器数据说明
1.时序说明
传感器读取流程 :
在一个I2C完整的Start-Stop读取模块数据通信中,每个寄存器数据后跟随一个对该寄存器数据的CRC校验字节,其CRC校验码字节的计算是对该寄存器数据字节进行CRC计算所得
注:每个寄存器数据后跟随一个对该寄存器数据的CRC校验字节。数据字节高位在前,低位在后

2.通用寄存器

3.读写寄存器数据说明
读取取产品编码和软件版本号寄存器数据举例:

写入模块数据举例:
连续写入模块数据举例:将Coef=100、uValAdj=-10写入

CRC校验
测量读取到的数据,CRC计算代码如下:
c
unsigned char calc_crc(unsigned char *pdat, unsigned char len)
{
unsigned char bits,byte,crc=0xFF;
for(byte=0; byte<len; byte++)
{
crc^=(*pdat);
for(bits=0;bits<8;bits++)
{
if(crc&0x80) crc=(crc<<1)^0x31;
else crc=(crc<<1);
}
pdat++;
}
return crc;
}
四、程序
STM32
main.C
c
#include "stm32f10x.h"
#include <stdio.h>
#include <Delay.h>
#define AIT1001_ADDR 0x0A //I2C 7位地址 0x0A
/*=========================================================
* USART1
* PA9 -> TX
* PA10 -> RX
*=========================================================*/
void USART1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_USART1,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
/*=========================================================
* printf重定向
*=========================================================*/
int fputc(int ch, FILE *f)
{
USART_SendData(USART1,(uint8_t)ch);
while (USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
return ch;
}
/*=========================================================
* I2C1初始化
* PB6 -> SCL
* PB7 -> SDA
* I2C通信时钟 25kHz
*=========================================================*/
void I2C1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
/*AIT1001要求 <50kHz 则使用25kHz*/
I2C_InitStructure.I2C_ClockSpeed = 25000;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C1,&I2C_InitStructure);
I2C_Cmd(I2C1,ENABLE);
}
/*=========================================================
* AIT1001 CRC8
* 初始值:0xFF
* 多项式:0x31
*=========================================================*/
uint8_t AIT1001_CRC8(uint8_t *data,uint8_t len)
{
uint8_t i;
uint8_t j;
uint8_t crc = 0xFF;
for (i = 0; i < len; i++)
{
crc ^= data[i];
for (j = 0; j < 8; j++)
{
if (crc & 0x80)
{
crc = (crc << 1) ^ 0x31;
}
else
{
crc <<= 1;
}
}
}
return crc;
}
/*=========================================================
* AIT1001 写入寄存器地址
*=========================================================*/
uint8_t AIT1001_WriteRegAddr(uint8_t reg)
{
uint32_t timeout;
timeout = 100000;
while (I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY))
{
if (--timeout == 0)
return 0;
}
I2C_GenerateSTART(I2C1,ENABLE);
timeout = 100000;
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT))
{
if (--timeout == 0)
return 0;
}
I2C_Send7bitAddress(I2C1,AIT1001_ADDR << 1,I2C_Direction_Transmitter);
timeout = 100000;
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if (I2C_GetFlagStatus(I2C1,I2C_FLAG_AF))
{
I2C_ClearFlag(I2C1,I2C_FLAG_AF);
I2C_GenerateSTOP(I2C1,ENABLE);
return 0;
}
if (--timeout == 0)
{
I2C_GenerateSTOP(I2C1,ENABLE);
return 0;
}
}
I2C_SendData(I2C1,reg);
timeout = 100000;
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if (--timeout == 0)
{
I2C_GenerateSTOP(I2C1,ENABLE);
return 0;
}
}
I2C_GenerateSTOP(I2C1,ENABLE);
return 1;
}
/*=========================================================
* AIT1001读取数据
* data[0] = Tntc 高字节
* data[1] = Tntc 低字节
* data[2] = Tntc CRC
* data[3] = Tobj 高字节
* data[4] = Tobj 低字节
* data[5] = Tobj CRC
*=========================================================*/
uint8_t AIT1001_ReadData(uint8_t *data)
{
uint32_t timeout;
uint8_t i;
if (!AIT1001_WriteRegAddr(0x00))
{
return 0;
}
I2C_AcknowledgeConfig(I2C1,ENABLE);
timeout = 100000;
while (I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY))
{
if (--timeout == 0)
return 0;
}
I2C_GenerateSTART(I2C1,ENABLE);
timeout = 100000;
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT))
{
if (--timeout == 0)
return 0;
}
I2C_Send7bitAddress(I2C1,AIT1001_ADDR << 1,I2C_Direction_Receiver);
timeout = 100000;
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
{
if (--timeout == 0)
{
I2C_GenerateSTOP(I2C1,ENABLE);
return 0;
}
}
for (i = 0;i < 5;i++)
{
timeout = 100000;
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED))
{
if (--timeout == 0)
{
I2C_AcknowledgeConfig(I2C1,ENABLE);
I2C_GenerateSTOP(I2C1,ENABLE);
return 0;
}
}
data[i] = I2C_ReceiveData(I2C1);
}
I2C_AcknowledgeConfig(I2C1,DISABLE);
timeout = 100000;
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED))
{
if (--timeout == 0)
{
I2C_AcknowledgeConfig(I2C1,ENABLE);
I2C_GenerateSTOP(I2C1,ENABLE);
return 0;
}
}
I2C_GenerateSTOP(I2C1,ENABLE);
data[5] = I2C_ReceiveData(I2C1);
I2C_AcknowledgeConfig(I2C1,ENABLE);
return 1;
}
uint8_t AIT1001_ReadTemperature
(
float *Tntc,
float *Tobj
)
{
uint8_t data[6];
uint8_t crc_ntc;
uint8_t crc_obj;
uint16_t raw_ntc;
uint16_t raw_obj;
if (!AIT1001_ReadData(data))
{
return 0;
}
crc_ntc = AIT1001_CRC8(&data[0],2);
if (crc_ntc != data[2]) {return 0;}
crc_obj = AIT1001_CRC8(&data[3],2);
if (crc_obj != data[5]) {return 0;}
raw_ntc = ((uint16_t)data[0] << 8) | data[1];
raw_obj = ((uint16_t)data[3] << 8) | data[4];
*Tntc = (float)raw_ntc / 10.0f;
*Tobj = (float)raw_obj / 10.0f;
return 1;
}
int main(void)
{
float Tntc;
float Tobj;
USART1_Init();
I2C1_Init();
Delay_ms(100);
while (1)
{
if (AIT1001_ReadTemperature(&Tntc,&Tobj))
{
printf("Tntc=%.1f C, Tobj=%.1f C\r\n",Tntc,Tobj);
}
else
{
printf("AIT1001 Read Error\r\n");
}
Delay_ms(1000);
}
}
五、驱动测试现象
---------------------------------------------------接线--------------------------------------------------
PA9 ->TX
PA10->RX
PB6 ->SCL
PB7 ->SDA
注:( SCL、SDA 需接 4.7K 的上拉电阻)
开发板串口输出如下:
Tntc:模块内部 NTC 温度
Tobj:红外被测物体温度

以上内容个人理解,如有不正欢迎指正,需要资料及工程可留言邮箱