AIT1001 非接触式红外测温模块 STM32 驱动开发实战:从引脚到代码全解析

文章目录

摘要: 本文详细介绍 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:红外被测物体温度

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

相关推荐
深圳老胡4 小时前
STM32F407 控制 L6470 步进电机驱动 —— 控制过程简介
笔记·stm32·单片机·嵌入式硬件·代码规范
wuyk5554 小时前
《WiFi 嵌入式物联网开发全套实战》| 第 16 章 ESP32 AP+STA 双模共存原理与工程坑点
网络·stm32·物联网
Brilliantwxx8 小时前
【STM32】 SPI Flash 驱动开发实战:阻塞模式驱动 W25Q64(含工程代码)
开发语言·stm32·单片机·嵌入式硬件
youcans_9 小时前
【嵌入式软件AI编程】16. Claude Code 与 VS Code 的协同开发
stm32·mcu·嵌入式·ai编程·claude code
Zw-awa10 小时前
按键接到 STM32 后:GPIO 输入到底读到了什么
stm32
阿钱真强道10 小时前
06 嵌入式操作系统 | vim 与软件管理:apt / 源码编译
ubuntu·vim·嵌入式·apt·源码编译
MarkZhou62410 小时前
智能蒸烤双核通信架构拆解:从冗余耦合到分层解耦
stm32·单片机·嵌入式硬件·架构·安卓·安全架构
G.E.M.小白10 小时前
【IMX6ULL ARM内核启动与时钟系统超详解】PLL/PFD/分频/根时钟配置
嵌入式·arm·时钟·imx6ull
嵌入式阿蔡10 小时前
嵌入式DevOps 2026:AI驱动工具链与CI/CD闭环
嵌入式