STM32 F103C8T6学习笔记17:类IIC通信—MLX90614红外非接触温度计

news2024/11/17 9:37:04

今日学习配置MLX90614红外非接触温度计 与 STM32 F103C8T6 单片机的通信

文章提供测试代码讲解、完整工程下载、测试效果图

本文需要用到的大概基础知识:1.3寸OLED配置通信显示、IIC通信、 定时器配置使用

这里就只贴出我的  OLED驱动方面的网址链接了:

其余的在我STM32 F103C8T6专栏里找吧.......

 STM32 F103C8T6学习笔记16:1.3寸OLED的驱动显示日历-CSDN博客

目录

MLX90614相关基础概念:

红外测温优势:

 MLX90614介绍:

MLX90614 存储器:

MLX90614 的 SMBus 协议:

起始信号与停止信号:

宏定义:

发送读取与PEC:

传感器与单片机引脚接线:

MLX90614配置应用设计函数:

类IIC引脚初始化:

定时器实时刷新OLED打印数据与BMP图像的标志:

数据读取与打印处理:

测试效果图与视频:

测试工程下载:


MLX90614相关基础概念:

红外测温优势:

一般来说,测温方式可分为接触式和非接触式

接触式测温只能测量被测物体与测温传 感器达到热平衡后的温度,所以响应时间长,且极易受环境温度的影响;

而红外测温是根据 被测物体的红外辐射能量来确定物体的温度,不与被测物体接触,具有影响动被测物体温度 分布场,温度分辨率高、响应速度快、测温范围广、不受测温上限的限制、稳定性好等特点, 近年来在家庭自动化、汽车电子、航空和军事上得到越来越广泛的应用。

 MLX90614介绍:

MLX90614系列模块是一组通用的红外测温模块。

在出厂前该模块已进行校验及线 性化,具有非接触、体积小、精度高,成本低等优点。被测目标温度和环境温度能通过单通 道输出,并有两种输出接口,适合于汽车空调、室内暖气、家用电器、手持设备以及医疗设 备应用等。

MLX90614 是一款红外非接触温度计。TO-39 金属封装里同 时集成了红外感应热电堆探测器芯片和信号处理专用集成芯 片。 由于集成了低噪声放大器、17位模数转换器和强大的数字信 号处理单元,使得高精度和高分辨度的温度计得以实现。 温度计具备出厂校准化,有数字PWM和SMBus(系统管理 总线)输出模式。

作为标准,配置为 10 位的 PWM 输出格式用于连续传送温 度范围为-20…120 ˚C 的物体温度,其分辨率为 0.14 ˚C。 POR 默认模式是SMBus 输出格式

MLX90614 存储器:

EEPROM 只有某些存储单元用户能够写入,但是可以读出全部存储单元。

MLX90614 的 EEPROM 有32 个16 位存储单元,

其中存储单元

Tomax,Tomin,Ta 分别是 用户物体温度上下限和环境温度范围,

PWMCTRL是PWM配置寄存器。

RAM   用户不能向RAM写入数据,但是可以读一些存储单元。

MLX90614 的RAM有 32 个17位存储单元,

其中TA,TOBJ1是环境温度和物体温度

在SMBus方式下,可以从这几个存储单元读出环境和被测物体的温度。

MLX90614 的 SMBus 协议:

单片机与MLX90614红外测温模块之间通信的方式是  “类IIC” 通信

意思就是通信方式跟IIC通信方式很像但又不是IIC,它有另外一个名字叫做SMBus。

SMBus (System Management Bus)是1995年由 intel公司提出的一种高效同步串行总线,SMBus只有两根信号线:双向数据线和时钟信号线,容许CPU与各种外围接口器件以串行方式进行通信、交换信息,既可以提高传输速度也可以减小器件的资源占用,另外即使在没有SMBus 接口的单片机上也可利用软件进行模拟。。MLX90614 SMBus时钟的最大频率为100KHz,最小为 10KHz。

起始信号与停止信号:

宏定义:

这里直接贴出所有需要的宏定义供查阅了:

#define ACK         0
#define NACK          1
#define SA     	             0x00 //Slave address ??MLX90614????0x00,????????0x5a
#define RAM_ACCESS    	     0x00 //RAM access command
#define EEPROM_ACCESS   	   0x20 //EEPROM access command
#define RAM_TA               0x06 //环境
#define RAM_TOBJ1    	       0x07 //To1 address in the eeprom 物体
#define RAM_TOBJ2            0x08 //

#define SMBUS_PORT               GPIOB
#define SMBUS_SCK                GPIO_Pin_10
#define SMBUS_SDA                GPIO_Pin_11

#define RCC_APB2Periph_SMBUS_PORT                RCC_APB2Periph_GPIOB

#define SMBUS_SCK_H()            SMBUS_PORT->BSRR = SMBUS_SCK
#define SMBUS_SCK_L()            SMBUS_PORT->BRR  = SMBUS_SCK
#define SMBUS_SDA_H()            SMBUS_PORT->BSRR = SMBUS_SDA
#define SMBUS_SDA_L()            SMBUS_PORT->BRR  = SMBUS_SDA

#define SMBUS_SDA_PIN()          SMBUS_PORT->IDR & SMBUS_SDA 

//在SMBus上生成启动条件
void SMBus_StartBit(void)
{
    SMBUS_SDA_H();                // Set SDA line
    SMBus_Delay(1);               // Wait a few microseconds
    SMBUS_SCK_H();                // Set SCL line
    SMBus_Delay(5);               // Generate bus free time between Stop
    SMBUS_SDA_L();                // Clear SDA line
    SMBus_Delay(10);              // Hold time after (Repeated) Start
    // Condition. After this period, the first clock is generated.
    //(Thd:sta=4.0us min)
    SMBUS_SCK_L();            // Clear SCL line
    SMBus_Delay(2);            // Wait a few microseconds
}

//在SMBus上生成停止条件
void SMBus_StopBit(void)
{
    SMBUS_SCK_L();                // Clear SCL line
    SMBus_Delay(5);               // Wait a few microseconds
    SMBUS_SDA_L();                // Clear SDA line
    SMBus_Delay(5);               // Wait a few microseconds
    SMBUS_SCK_H();                // Set SCL line
    SMBus_Delay(10);              // Stop condition setup time(Tsu:sto=4.0us min)
    SMBUS_SDA_H();                // Set SDA line
}

发送读取与PEC:

//延时
void SMBus_Delay(u16 time)
{
    u16 i, j;
    for (i=0; i<4; i++)
    {
        for (j=0; j<time; j++);
    }
}

//从 RAM/EEPROM 读取数据
u16 SMBus_ReadMemory(u8 slaveAddress, u8 command)
{
    u16 data;                        // Data storage (DataH:DataL)
    u8 Pec;                                // PEC byte storage
    u8 DataL=0;                        // Low data byte storage
    u8 DataH=0;                        // High data byte storage
    u8 arr[6];                        // Buffer for the sent bytes
    u8 PecReg;                        // Calculated PEC byte storage
    u8 ErrorCounter;        // Defines the number of the attempts for communication with MLX90614

    ErrorCounter=0x00;                                // Initialising of ErrorCounter
        slaveAddress <<= 1;        //2-7???????
        
    do
    {
repeat:
        SMBus_StopBit();                            //If slave send NACK stop comunication
        --ErrorCounter;                                    //Pre-decrement ErrorCounter
        if(!ErrorCounter)                             //ErrorCounter=0?
        {
            break;                                            //Yes,go out from do-while{}
        }

        SMBus_StartBit();                                //Start condition
        if(SMBus_SendByte(slaveAddress))//Send SlaveAddress ???Wr=0????????
        {
            goto        repeat;                            //Repeat comunication again
        }
        if(SMBus_SendByte(command))            //Send command
        {
            goto        repeat;                            //Repeat comunication again
        }

        SMBus_StartBit();                                        //Repeated Start condition
        if(SMBus_SendByte(slaveAddress+1))        //Send SlaveAddress ???Rd=1????????
        {
            goto        repeat;                     //Repeat comunication again
        }

        DataL = SMBus_ReceiveByte(ACK);        //Read low data,master must send ACK
        DataH = SMBus_ReceiveByte(ACK); //Read high data,master must send ACK
        Pec = SMBus_ReceiveByte(NACK);        //Read PEC byte, master must send NACK
        SMBus_StopBit();                                //Stop condition

        arr[5] = slaveAddress;                //
        arr[4] = command;                        //
        arr[3] = slaveAddress+1;        //Load array arr
        arr[2] = DataL;                                //
        arr[1] = DataH;                                //
        arr[0] = 0;                                        //
        PecReg=PEC_Calculation(arr);//Calculate CRC
    }
    while(PecReg != Pec);                //If received and calculated CRC are equal go out from do-while{}

        data = (DataH<<8) | DataL;        //data=DataH:DataL
    return data;
}

u8 SMBus_SendByte(u8 Tx_buffer)
{
    u8        Bit_counter;
    u8        Ack_bit;
    u8        bit_out;

    for(Bit_counter=8; Bit_counter; Bit_counter--)
    {
        if (Tx_buffer&0x80)
        {
            bit_out=1;   // If the current bit of Tx_buffer is 1 set bit_out
        }
        else
        {
            bit_out=0;  // else clear bit_out
        }
        SMBus_SendBit(bit_out);                // Send the current bit on SDA
        Tx_buffer<<=1;                                // Get next bit for checking
    }

    Ack_bit=SMBus_ReceiveBit();                // Get acknowledgment bit
    return        Ack_bit;
}

void SMBus_SendBit(u8 bit_out)
{
    if(bit_out==0)
    {
        SMBUS_SDA_L();
    }
    else
    {
        SMBUS_SDA_H();
    }
    SMBus_Delay(2);                                        // Tsu:dat = 250ns minimum
    SMBUS_SCK_H();                                        // Set SCL line
    SMBus_Delay(10);                            // High Level of Clock Pulse
    SMBUS_SCK_L();                                        // Clear SCL line
    SMBus_Delay(10);                            // Low Level of Clock Pulse
//        SMBUS_SDA_H();                                    // Master release SDA line ,
    return;
}

u8 SMBus_ReceiveBit(void)
{
    u8 Ack_bit;

    SMBUS_SDA_H();          //?????????,????
    SMBUS_SCK_H();                        // Set SCL line
    SMBus_Delay(2);                        // High Level of Clock Pulse
    if (SMBUS_SDA_PIN())
    {
        Ack_bit=1;
    }
    else
    {
        Ack_bit=0;
    }
    SMBUS_SCK_L();                        // Clear SCL line
    SMBus_Delay(4);                        // Low Level of Clock Pulse

    return        Ack_bit;
}

u8 SMBus_ReceiveByte(u8 ack_nack)
{
    u8         RX_buffer;
    u8        Bit_Counter;

    for(Bit_Counter=8; Bit_Counter; Bit_Counter--)
    {
        if(SMBus_ReceiveBit())                        // Get a bit from the SDA line
        {
            RX_buffer <<= 1;                        // If the bit is HIGH save 1  in RX_buffer
            RX_buffer |=0x01;
        }
        else
        {
            RX_buffer <<= 1;                        // If the bit is LOW save 0 in RX_buffer
            RX_buffer &=0xfe;
        }
    }
    SMBus_SendBit(ack_nack);                        // Sends acknowledgment bit
    return RX_buffer;
}


//计算接收字节的PEC
u8 PEC_Calculation(u8 pec[])
{
    u8         crc[6];
    u8        BitPosition=47;
    u8        shift;
    u8        i;
    u8        j;
    u8        temp;

    do
    {
        /*Load pattern value 0x000000000107*/
        crc[5]=0;
        crc[4]=0;
        crc[3]=0;
        crc[2]=0;
        crc[1]=0x01;
        crc[0]=0x07;

        /*Set maximum bit position at 47 ( six bytes byte5...byte0,MSbit=47)*/
        BitPosition=47;

        /*Set shift position at 0*/
        shift=0;

        /*Find first "1" in the transmited message beginning from the MSByte byte5*/
        i=5;
        j=0;
        while((pec[i]&(0x80>>j))==0 && i>0)
        {
            BitPosition--;
            if(j<7)
            {
                j++;
            }
            else
            {
                j=0x00;
                i--;
            }
        }/*End of while */

        /*Get shift value for pattern value*/
        shift=BitPosition-8;

        /*Shift pattern value */
        while(shift)
        {
            for(i=5; i<0xFF; i--)
            {
                if((crc[i-1]&0x80) && (i>0))
                {
                    temp=1;
                }
                else
                {
                    temp=0;
                }
                crc[i]<<=1;
                crc[i]+=temp;
            }/*End of for*/
            shift--;
        }/*End of while*/

        /*Exclusive OR between pec and crc*/
        for(i=0; i<=5; i++)
        {
            pec[i] ^=crc[i];
        }/*End of for*/
    }
    while(BitPosition>8); /*End of do-while*/

    return pec[0];
}

传感器与单片机引脚接线:

MLX90614配置应用设计函数:

类IIC引脚初始化:

//MLX90614 SMBus通信 初始化
void SMBus_Init(void)
{
    GPIO_InitTypeDef    GPIO_InitStructure;

        /* Enable SMBUS_PORT clocks */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SMBUS_PORT, ENABLE);

    /*??SMBUS_SCK?SMBUS_SDA????????*/
    GPIO_InitStructure.GPIO_Pin = SMBUS_SCK | SMBUS_SDA;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(SMBUS_PORT, &GPIO_InitStructure);

    SMBUS_SCK_H();
    SMBUS_SDA_H();
}

定时器实时刷新OLED打印数据与BMP图像的标志:


//刷新时间标志
 uint16_t TDisplay_cnt,TDisplay;
//刷新BMP图像
uint16_t BMP_cnt,BMP_FLAG,BMPDisplay;	
//定时器2中断服务函数
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{		
		if(++TDisplay_cnt==15)  //定时器刷新温度
		{
			TDisplay_cnt=0;
			TDisplay=1;
			
		}
		
		if(++BMP_cnt==9)		        //定时器   刷新太空人图片
		{
			BMP_cnt=0;BMP_FLAG++;BMPDisplay=1;
			if(BMP_FLAG==29){BMP_FLAG=1;}
		}
		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清出中断寄存器标志位,用于退出中断
	}
}

数据读取与打印处理:

//OLED打印读取到的温度值
void Print_temperature(void)
{
	if(TDisplay==1)
	{
	  char  buf[20];                //用于暂存oled数据
		float temp;                   //读取温度
		
//		huanjing=temp*100;             //浮点数扩大100倍存入整数,方便显示
//		wuti=temp*100;                 //浮点数扩大100倍存入整数,方便显示	
		
		temp=SMBus_ReadTemp(RAM_TA);    //读取环境温度
		OLED_ShowCHinese(65+16*0,0,2);  //打印中文“环”
		OLED_ShowCHinese(65+16*1,0,3);  //打印中文“境”
		OLED_ShowCHinese(65+16*2,0,0);  //打印中文“温”
		OLED_ShowCHinese(65+16*3,0,1);  //打印中文“度”		
		//打印环境温度的值
		sprintf(buf,"%.2f C",temp);
 		OLED_ShowString(70,2,(u8 *)buf,16);
		
		temp=SMBus_ReadTemp(RAM_TOBJ1);//读取物体温度
		OLED_ShowCHinese(65+16*0,4,4);  //打印中文“物”
		OLED_ShowCHinese(65+16*1,4,5);  //打印中文“体”
		OLED_ShowCHinese(65+16*2,4,0);  //打印中文“温”
		OLED_ShowCHinese(65+16*3,4,1);  //打印中文“度”			
		//打印物体温度的值
		sprintf(buf,"%.2f C",temp);
 		OLED_ShowString(70,6,(u8 *)buf,16);		
		
		
		TDisplay=0;
	}
}

测试效果图与视频:

测试效果还行,能明显区分不同温度的物体:

类IIC通信—MLX90614红外非接触温度计

测试工程下载:

https://download.csdn.net/download/qq_64257614/89250067

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1637647.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

线上线下收银一体化,新零售POS系统引领连锁门店数字化转型-亿发

在市场竞争日益激烈的背景下&#xff0c;没有哪个商家能够永远屹立不倒。随着互联网技术的快速发展&#xff0c;传统的线下门店面临着来自电商和新零售的新型挑战。实体零售和传统电商都需要进行变革&#xff0c;都需要实现线上线下的融合。 传统零售在客户消费之后就与商家失…

群晖Docker部署Java jar包

安装群晖Docker组件Container Manager 打开组件,找到注册表搜索java,安装java映像 安装完成后会在映像目录里展示出来,点击运行 常规设置按需配置即可 这里要设置一个文件夹目录给这个容器来使用 一般来说给个/root来用就够了 设置完成后可以在容器目录里看到容器已经运行起来了…

判断循环链表以及其环入口

文章目录 题目题目链接题目要求 解题思路方法一&#xff1a;哈希表方法二&#xff1a;双指针 进阶思考快指针一次走三步 进阶问题&#xff08;入口点&#xff09;题目链接题目要求问题思路 总结 题目 题目链接 环形链表 题目要求 解题思路 显而易见的是&#xff0c;单纯的遍…

可靠的Mac照片恢复解决方案

当您在搜索引擎搜索中输入“Mac照片恢复”时&#xff0c;您将获得数以万计的结果。有很多Mac照片恢复解决方案声称他们可以在Mac OS下恢复丢失的照片。但是&#xff0c;并非互联网上的所有Mac照片恢复解决方案都可以解决您的照片丢失问题。而且您不应该花太多时间寻找可靠的Mac…

uniapp 对接 Apple 登录

由于苹果要求App使用第三方登录必须要求接入Apple登录 不然审核不过 所以&#xff1a; 一、勾选苹果登录 二、 设置AppId Sign In Apple 设置完成重新生成描述文件 &#xff01;&#xff01;&#xff01;&#xff01;证书没关系 示例代码&#xff1a; async appleLogin…

2024年最新省市县三级行政区划数据(审图号:GS(2024)0650号)

2024年省、市、县三级行政区划数据由国家基础地理信息中心发布&#xff0c;通过《2024版国家地理信息公共服务平台&#xff08;天地图&#xff09;》正式对外提供。这份数据涵盖了最新的省市县三级行政区划信息&#xff0c;更新于2024年1月&#xff0c;提供了详细的矢量数据下载…

食谱管理和餐饮计划应用Mealie

放假除了休闲娱乐&#xff0c;也不能忘了美食 什么是 Mealie &#xff1f; Mealie 是一个自托管的食谱管理和餐饮计划应用&#xff0c;具有 RestAPI 后端和基于 Vue 构建的响应式前端应用&#xff0c;为整个家庭提供愉快的用户体验。通过提供 URL&#xff0c;您可以轻松将食谱…

知识产权 | 守护科技创新之光,共筑知识产权长城

2024年4月26日&#xff0c;迎来了一年一度的世界知识产权日&#xff0c;今年的主题是&#xff1a;“立足创新创造&#xff0c;构建共同未来。” 易我科技是一家专注于数据安全产品研发、生产、销售、服务一体化的高新技术软件企业。易我科技自成立以来&#xff0c;始终秉持尊重…

贝叶斯回归

1. 贝叶斯推断的定义 简单来说&#xff0c;贝叶斯推断 (Bayesian inference) 就是结合“经验 (先验)”和“实践 (样本)”&#xff0c;得出“结论 (后 验)”。 2. 什么是先验&#xff1f; 贝叶斯推断把模型参数看作随机变量。在得到样本之前&#xff0c;根据主观经验和既有知…

微视网媒:引领新媒体时代的视觉先锋

在信息爆炸的时代&#xff0c;内容消费的方式日新月异&#xff0c;而“微视网媒”正是这场媒体变革中的佼佼者。凭借其独特的视角、精湛的制作和广泛的传播渠道&#xff0c;微视网媒不仅改变了人们获取信息的方式&#xff0c;更在不断地塑造着未来的媒体生态。 一、创新内容&am…

STM32中断之TIM定时器详解

系列文章目录 STM32单片机系列专栏 C语言术语和结构总结专栏 文章目录 1. TIM简述 2. 定时器类型 2.1 基本定时器 2.2 通用定时器 2.3 高级定时器 3. 定时中断 4. 代码示例1 5. 代码示例2 1. TIM简述 定时器的基本功能&#xff1a;定时器可以在预定的时间间隔内产生周…

LeetCode 198—— 打家劫舍

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 此题使用动态规划求解&#xff0c;假设 d p [ i ] [ 0 ] dp[i][0] dp[i][0] 代表不偷窃第 i i i 个房屋可以获得的最高金额&#xff0c;而 d p [ i ] [ 1 ] dp[i][1] dp[i][1] 代表偷窃第 i i i 个房屋可以获…

2024年谷歌Google广告开户是什么政策?

2024年谷歌Google广告依然是众多企业拓展市场、提升品牌影响力的重要渠道&#xff0c;随着谷歌政策的不断更新与优化&#xff0c;以及对第三方cookie逐步禁用的决定&#xff0c;如何高效地在这一平台上开展广告活动&#xff0c;成为每一家企业必须面对的战略挑战。云衔科技作为…

【平台开发】MTK6833 实现lk下CQE接口移植 - cmdq irq

1.cmdq_irq 检测中断bit 2.目前遇到问题 任务执行后&#xff0c;没有触发对应中断&#xff0c;伴有错误发生&#xff0c;但任务完成标志位能检测到 寄存器CQIS,CQDQS等均为0&#xff0c;CQTCN为任务完成寄存器看到置1&#xff0c;CQTERRI检测到8000错误 错误详情如下&#xf…

基于SpringBoot+Vue外卖系统设计和实现(源码+LW+部署讲解)

&#x1f339;作者简介&#xff1a;✌全网粉丝10W&#xff0c;csdn特邀作者、博客专家、Java领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战&#xff0c;高校老师/讲师/同行前辈交流✌ &#x1f339; 主要…

day7 c++

整理代码 1、unique_ptr 指针 #include <iostream> #include <memory> using namespace std; class Demo {public:Demo(){cout<<"无参构造"<<endl;}~Demo(){cout<<"Demo的析构函数"<<endl;} };int main() {//unique…

(1)探索 SpringAI - 基本概述

人工智能简介 A system is ability to correctly interpret external data, to learn from such data, and to use those learnings to achieve specific goals and tasks through flexible adaptation. 翻译&#xff1a;系统正确解释外部数据的能力&#xff0c;从这些数据中学…

【C语言/数据结构】经典链表OJ习题~第二期——链中寻环

&#x1f388;&#x1f388;&#x1f388;欢迎采访小残风的博客主页&#xff1a;残风也想永存-CSDN博客&#x1f388;&#x1f388;&#x1f388; &#x1f388;&#x1f388;&#x1f388;本人码云 链接&#xff1a;残风也想永存 (FSRMWK) - Gitee.com&#x1f388;&#x1f…

AI家居设备的未来:智能家庭的下一个大步

&#x1f512;目录 ☂️智能家居设备的发展和AI技术的作用 ❤️AI技术实现智能家居设备的自动化控制和智能化交互的依赖 AI家居设备的未来应用场景 &#x1f4a3;智能家庭在未来的发展和应用前景 &#x1f4a5;智能家居设备的发展和AI技术的作用 智能家居设备的发展和AI技术的…

Tokitsukaze and Average of Substring

原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 前缀和。 开一个int类型的前缀和数组pre[30][N]&#xff08;pre[i][j]表示某字符转成的数字 i 在一段区间的前缀个数。因为字母表有‘a’~z…