STM32使用I2C和PWM捕获读取MLX90615温度值
一、MLX90615使用说明
MLX90615是一款红外温度传感器,默认使用SMBus模式,如果需要使用PWM模式则需要修改EEPROM地址中Config Register中的值才能将其配置为PWM模式。笔者因为老师给的电路板使用的模式为PWM,因此需要配置EEPROM寄存器的值,将其配置为PWM模式进行温度的读取。找了很多相关的资料,但是基本上没有使用PWM捕获获取温度的资料。笔者在使用I2C写入数据修改的EEPROM寄存器值配置工作模式时遇到了很多的问题,花了一天多的时间才得以解决。因此发一贴来分享遇见的这些问题。EEPROM Config Register的地址为0X02,每位具体代表的值如下图所示:
MLX90615内部含有两块内存一个是EEPRM一个是RAM。
按上图所示0x1?选择的是EEPROM,0x2?选中的RAM,0x27是RAM中温度存放的地址,0x12是EEPROM Config Register的地址,芯片的器件地址为0x00(或者是0x5B)。具体的IIC通信过程如下图所示:
知晓了上诉基本原理之后就需要编程实现上诉功能,来获取传感器采集到的温度。值得注意的是,MLX90615的IIC通信都要需要进行校验,即最后的PEC,采用的ocr-8校验,如果校验不通过则代表写入或者读取的数据有问题。
二、STM32与MLX90615之间的IIC通信
本文采用的MCU为STM32F103VET6,采用模拟IIC的方式进行MCU和温度传感器MLX90615之间通信。按照上述所示的IIC通信过程编写响应程序,具体编程如下图所示:
2.1 用到的引脚相关宏定义,便于主函数的编写
#ifndef __MLX90615_H__
#define __MLX90615_H__#include "stm32f10x.h"
#include "bsp_SysTick.h"#define u8 uint8_t
#define u16 uint16_t
#define u32 uint32_t#define ACK 0
#define NACK 1//MLX90615 constants
#define SA 0x00 // Slave address
#define DEFAULT_SA 0x5B // Default Slave address
#define RAM_Access 0x20 // RAM access command
#define EEPROM_Access 0x10 // EEPROM access command#define mlx_I2C_PORT GPIOB //使用到的CPIO口
#define mlx_SCL_PIN GPIO_Pin_10
#define mlx_SDA_PIN GPIO_Pin_11#define mlx_SCL_LOW() mlx_I2C_PORT->BRR = mlx_SCL_PIN // define SCL
#define mlx_SCL_HIGH() mlx_I2C_PORT->BSRR = mlx_SCL_PIN // define SCL#define mlx_SDA_LOW() mlx_I2C_PORT->BRR = mlx_SDA_PIN // define SDA
#define mlx_SDA_HIGH() mlx_I2C_PORT->BSRR = mlx_SDA_PIN // define SDA#define mlx_SCL_State() ((mlx_I2C_PORT->IDR & mlx_SCL_PIN) != 0) //获取SCL的值
#define mlx_SDA_State() ((mlx_I2C_PORT->IDR & mlx_SDA_PIN) != 0) //获取SDA的值
2.2 GPIO的初始化
// 函数名称: mlx_gpio_init()
//
// 函数功能: 初始化IO口
//
// 入口参数: 时间
//
// 返回参数: 无
//
// 说明: 配置CPIO位低速推挽输出模式
//==========================================================
void mlx_gpio_init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB时钟GPIO_InitStructure.GPIO_Pin = mlx_SCL_PIN | mlx_SDA_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_Init(mlx_I2C_PORT, &GPIO_InitStructure);mlx_SCL_HIGH();mlx_SDA_HIGH();
}
//==========================================================
// 函数名称: mlx_SDA_OUT()
//
// 函数功能: IIC数据线输出模式
//
// 入口参数: 时间
//
// 返回参数: 无
//
// 说明: 最开始的GPIO初始化已经写过了但是检测应答信号的时候需要修改位浮空输入
//因此在后面的使用中需要SDA引脚再次初始化位输出模式 因此单独写一个输出配置函数
//==========================================================
void mlx_SDA_OUT(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB时钟GPIO_InitStructure.GPIO_Pin = mlx_SDA_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; //低速GPIO_Init(mlx_I2C_PORT, &GPIO_InitStructure);
}//==========================================================
// 函数名称: mlx_SDA_IN()
//
// 函数功能: IIC数据线输入模式
//
// 入口参数: 时间
//
// 返回参数: 无
//
// 说明: 配置为输入检测应答信号
//==========================================================
void mlx_SDA_IN(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB时钟GPIO_InitStructure.GPIO_Pin = mlx_SDA_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //输入模式GPIO_Init(mlx_I2C_PORT, &GPIO_InitStructure);
}
分别是SCL和SDA引脚进行初始化操作,后面两个初始化时因为SDA引脚需要检测应答信号,因此需要改变GPIO的工作模式,所以单独写了输入模式和输出模式的初始化程序。
2.3 开始位和停止位
//==========================================================
// 函数名称: start_bit()
//
// 函数功能: IIC 开始时序
//
// 入口参数: 时间
//
// 返回参数: 无
//
// 说明:
//==========================================================
void START_bit(void)
{ mlx_SDA_OUT();mlx_SDA_HIGH();Delay_us(5);mlx_SCL_HIGH();Delay_us(5);mlx_SDA_LOW();Delay_us(4);mlx_SCL_LOW();Delay_us(5);
}//==========================================================
// 函数名称: stop_bit()
//
// 函数功能: IIC 停止时序
//
// 入口参数: 时间
//
// 返回参数: 无
//
// 说明:
//==========================================================
void STOP_bit(void)
{mlx_SDA_OUT();mlx_SCL_LOW();Delay_us(5);mlx_SDA_LOW();Delay_us(5);mlx_SCL_HIGH();Delay_us(5);mlx_SDA_HIGH();
}
2.4 接收和发送函数
//==========================================================
// 函数名称: send_bit()
//
// 函数功能: IIC 写入数据时序
//
// 入口参数: 时间
//
// 返回参数: 无
//
// 说明:
//==========================================================
void send_bit(unsigned char bit_out)
{ mlx_SDA_OUT();if(bit_out) mlx_SDA_HIGH(); else mlx_SDA_LOW();Delay_us(1);mlx_SCL_HIGH();Delay_us(5);mlx_SCL_LOW();Delay_us(5);return;
}//End of send_bit()//==========================================================
// 函数名称: Receive_bit()
//
// 函数功能: IIC 读取数据时序
//
// 入口参数: 时间
//
// 返回参数: 无
//
// 说明:
//==========================================================
unsigned char Receive_bit(void)
{unsigned char Ack_bit;mlx_SDA_IN(); __NOP();__NOP();__NOP();Delay_us(3);mlx_SCL_HIGH();Delay_us(1);if(mlx_SDA_State())Ack_bit=1;elseAck_bit=0;mlx_SCL_LOW(); Delay_us(1); return Ack_bit;
}//End of Receive_bit
//==========================================================
// 函数名称: TX_byte()
//
// 函数功能: IIC发送数据
//
// 入口参数: Tx_buffer:数据
//
// 返回参数: 无
//
// 说明:
//==========================================================
unsigned char TX_byte(unsigned char Tx_buffer)
{unsigned char Bit_counter;unsigned char Ack_bit;unsigned char 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_outelse bit_out=0; // else clear bit_outsend_bit(bit_out); // Send the current bit on SDATx_buffer<<=1; // Get next bit for checking}Ack_bit=Receive_bit();// Get acknowledgment bitreturn Ack_bit;
}// End of TX_bite()//==========================================================
// 函数名称: RX_byte()
//
// 函数功能: IIC 读取数据
//
// 入口参数: ack_nack: unsigned char ack_nack (acknowledgment bit)
// 0 - Master device sends ACK
// 1 - Master device sends NACK
//
// 返回参数: 无
//
// 说明:
//==========================================================
unsigned char RX_byte(unsigned char ack_nack)
{unsigned char RX_buffer=0;unsigned char Bit_Counter;for(Bit_Counter=8; Bit_Counter; Bit_Counter--){if(Receive_bit()) // Get a bit from the SDA line{RX_buffer <<= 1; // If the bit is HIGH save 1 in RX_bufferRX_buffer |=0x01;}else{RX_buffer <<= 1; // If the bit is LOW save 0 in RX_buffer RX_buffer &=0xfe; }}send_bit(ack_nack); // Sends acknowledgment bitreturn RX_buffer;
}
2.5 读取函数和发送函数
//==========================================================
// 函数名称: MemRead()
//
// 函数功能: 从框架/EEPROM读取数据
//
// 入口参数: SlaveAddress:读取地址
// command:命令
//
// 返回参数: 温度值
//
// 说明:
//==========================================================
unsigned int MemRead(unsigned char SlaveAddress,unsigned char command)
{unsigned int data; // Data storage (DataH:DataL)unsigned char Pec; // PEC byte storageunsigned char DataL; // Low data byte storageunsigned char DataH; // High data byte storageunsigned char arr[6]; // Buffer for the sent bytesunsigned char PecReg; // Calculated PEC byte storageunsigned char ErrorCounter; // Defines the number of the attempts for communication with MLX90614ErrorCounter=0x00; // Initialising of ErrorCounterdo{repeat:STOP_bit(); //If slave send NACK stop comunication --ErrorCounter; //Pre-decrement ErrorCounterif(!ErrorCounter){ //ErrorCounter=0?printf("break 1\r\n");break; //Yes,go out from do-while{}}START_bit(); //Start conditionif(TX_byte(SlaveAddress)){ //Send SlaveAddressprintf("repeat 1\r\n");goto repeat; //Repeat comunication again}if(TX_byte(command)){ //Send command printf("repeat 2\r\n");goto repeat; //Repeat comunication again}START_bit(); //Repeated Start conditionif(TX_byte(SlaveAddress+1)){ //Send SlaveAddress-------------------???printf("repeat 3\r\n");goto repeat; //Repeat comunication again}DataL=RX_byte(ACK); //Read low data,master must send ACKDataH=RX_byte(ACK); //Read high data,master must send ACKPec=RX_byte(NACK); //Read PEC byte, master must send NACKSTOP_bit(); //Stop conditionarr[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 CRCprintf("PecReg:%d\n", PecReg);printf("Pec:%d\n", Pec);printf("DataL:%d\tDataH:%d\r\n",DataL,DataH);}while(PecReg != Pec); //If received and calculated CRC are equal go out from do-while{}*((unsigned char *)(&data))=DataL; // *((unsigned char *)(&data)+1)=DataH ; //data=DataH:DataLreturn data;
}
void MemWrite(unsigned char SlaveAddress,unsigned char command, uint16_t data)
{//uint8_t Pec; // PEC byte storageuint8_t i;uint8_t DataL; // Low data byte storageuint8_t DataH; // High data byte storageuint8_t arr[6]; // Buffer for the sent bytesuint8_t PecReg; // Calculated PEC byte storage//uint8_t ask_status;/*擦除地址中的数据仅限于EEPROM*/SendRequest(); //复位DataL = (data & 0x00ff); //要写入数据的低8位DataH = (data>>8); //要写入数据的高8位printf("datal:%d dataH:%d \n", DataL, DataH);//计算擦除值的PECarr[5]=0;arr[4]=SlaveAddress; //arr[3]=command; //arr[2]=0x00; //Load array arr arr[1]=0x00; //arr[0]=0; // //PecReg=PEC_calculation(arr);//Calculate CRCSTOP_bit(); Delay_ms(5);START_bit(); //Start conditionTX_byte(SlaveAddress); //Send SlaveAddress//Delay_ms(1);TX_byte(command); //Send command 0012//Delay_ms(1);//擦除扇区for(i=0; i <2 ;i++){if (TX_byte(0x00) == 1){printf("应答失败\n");}//Delay_ms(1);}if (TX_byte(PecReg) == 1){printf("清除扇区检验失败\n");}STOP_bit(); /*写入需要的数据仅限于EEPROM*/SendRequest();//复位//计算输入值的PECarr[5]=0; arr[4]=SlaveAddress; //arr[3]=command; //arr[2]=DataL; //Load array arr arr[1]=DataH; //arr[0]=0; // //PecReg=PEC_calculation(arr);//Calculate CRC//printf("打印的PEC值:%d\n",PecReg);//TX_byte(PecReg);STOP_bit(); //Stop conditionDelay_ms(5);START_bit(); //Start conditionTX_byte(SlaveAddress); //Send SlaveAddress//Delay_ms(1);TX_byte(command); //Send command //Delay_ms(1);TX_byte(DataL); //Read low data,master must send ACK//ask_status = read_ack();//printf("askstatus的值为%d \n", ask_status);//Delay_ms(1);TX_byte(DataH); //Read high data,master must send ACK//ask_status = read_ack();//printf("askstatus的值为%d \n", ask_status);//Delay_ms(1);if (TX_byte(PecReg) == 1){printf("输入数据检验失败\n");}//TX_byte(Pec); //Read PEC byte, master must send NACK//ask_status = read_ack();//printf("askstatus的值为%d \n", ask_status);//Delay_ms(1);STOP_bit(); //Stop condition
}
上述为使用IIC读取和写入数据的代码。值得注意的是,这个传感器读取和写入数据的时候必须进Packet Error Code校验。校验要是不通过代表写入或者读取数据失败。具体的代码后面会上传。
三、如何使用PWM捕获或者是SMBUS读取温度数据
unsigned char SlaveAddress; //Contains device address
unsigned char command; //Contains the access command
unsigned int data; //Contains data value
//float temp;
uint16_t send_data = 5328; //pwm工作模式 输出1kz的pwm send_data = 5329; smbus模式
SlaveAddress=SA; //Set device address
command=0x12; //eeprom config command=0x27 读取温度数据;if (Key_Scan(KEY1_GPIO_PORT, KEY1_GPIO_PIN) == KEY_ON)
{MemWrite(SlaveAddress,command,send_data);//data=MemRead(0x00,command); //Read memory//temp=CalcTemp(data);//sprintf((char *)buf," tmp:%0.2f ",temp);//printf("data:%d\r\n",data);Delay_ms(1000);printf("写入成功%d\n", send_data);
}
if(Key_Scan(KEY2_GPIO_PORT, KEY2_GPIO_PIN) == KEY_ON)
{data=MemRead(SlaveAddress,command); //Read memorytemp=CalcTemp(data);printf("data:%d\r\n",data);Delay_ms(1000);
}
float CalcTemp(unsigned int value)
{float temp;temp=(value*0.02)-273.15;// _NOP();Delay_us(1);return temp;
}
如上述代码所示,按下按键1就能修改传感器的工作模式,如果是在SMBUS工作模式下按下按键2则可以读取温度。如果是在PWM工作模式下,需要修改对应的电路图,具体电路如下图所示:
如果使用PWM捕获需要使用STM32的高级定时器功能来实现PWM捕获,具体代码可以自行百度或者参考野火STM32教程,直接拷贝对应模块的代码就能进行使用,根据自身的需求修改对面的源码。
四、结语
第一次在CSDN发帖子,不知道该怎么写,感觉写的很差,其中有错误的地方欢迎大家指出。
上述的两张图片分别为直接测量的室温,和手指直接放在传感器上测出来的温度,因为没有温度计,感觉上来说温度还是挺正确的。
参考的帖子:https://blog.csdn.net/baoke485800/article/details/51320740
链接:https://pan.baidu.com/s/1vbqCcuCYBJ8EqlU8_1vYkQ
提取码:c7cf
复制这段内容后打开百度网盘手机App,操作更方便哦
STM32使用I2C和PWM捕获读取MLX90615温度值相关推荐
- 基于FPGA的IIC读取LM74A温度值
基于FPGA的IIC读取LM74A温度值 IIC总线概述 采用串行总线技术可以使系统的硬件设计大大简化.系统的体积减小.可靠性提高.同时,系统的更改和扩充极为容易.常用的串行扩展总线有: I2C (I ...
- STM32通用定时器输出PWM控制舵机 —— 重装载值、比较值、当前值
参考:stm32 定时器输出PWM原理及工作原理+控制舵机 作者:点灯小哥 发布时间: 2021-03-09 23:17:52 网址:https://blog.csdn.net/weixin_4601 ...
- nrf52832通过i2c官方库nrf_drv_twi读取tmp117温度
twi调试过程如下: 1 代码实现:分别实现对nrf_drv_twi_init,nrf_drv_twi_rx, nrf_drv_twi_tx相关官方库的调用 2 修改工程配置文件sdk_config. ...
- 32读取ltc的温度值_Arduino基础入门篇29—模拟温度传感器LM35
温度传感器就是利用物质随温度变化特性的规律,把温度转换成可输出信号的传感器,是普遍应用的传感器之一.本篇介绍模拟温度传感器-LM35. 1. LM35介绍 LM35是很常用的温度传感器元件,电路连接非 ...
- STC15F2K60S2读取DS18B20温度串口显示
为方便大家调试,特附该程序的项目下载地址 STC15F2K60S2读取DS18B20温度实例下载地址 //************************** //程序说明:stc15f2k60s2采 ...
- STM32模拟I2C协议获取MLX90615红外温度传感器测温数据(Open Drain管脚配置)
STM32模拟I2C协议获取MLX90615红外温度传感器测温数据(Open Drain管脚配置) STM32的GPIO管脚可以配置为Open Drain输出模式,并且有两个功能: 可以设置内部上拉, ...
- arduino i2c 如何写16位寄存器_基于STM32使用I2C读取传感器数据
撑腰会儿:I2C通信协议介绍zhuanlan.zhihu.com 上文介绍了I2C协议的基本结构,今天,使用STM32和LM75A温度传感器来实现I2C读取信息. 首先,为了使用I2C读取传感器测量 ...
- STM32学习记录:输入捕获应用
目录 前言 一.输入捕获的应用 1.1.测量脉宽或者频率 1.2.测量频率的步骤方法 1.3.测量脉宽的步骤方法 二. 输入捕获工作过程 2.1.CH1为例,输入捕获工作过程 2.2.输入通道 2.3 ...
- STM32F1读取MLX90615非接触式红外温度传感器
MLX90615 简介 MLX90615是一种红外温度计,用于非接触式温度测量.红外敏感热电堆探测器芯片和信号调节芯片集成在同一个TO-46 CAN封装中.由于采用了低噪声放大器.16位模数转换器和强 ...
最新文章
- python中tk窗口刷新_80 行 Python 代码写个图形计算器
- eclipse中查看java源代码设置方法
- 第十六届智能车竞赛总决赛线上比赛赛道设计
- 从零开始一个http服务器(五)-模拟cgi
- 驰骋工作流引擎设计系列05 启动流程设计
- Python安装Whl文件
- Spring 核心容器类BeanFactory
- Flink解析kafka canal未压平数据为message报错
- 【必懂C++】第一个程序当然是HelloWorld呀 01
- 你应该知道的 CSS 基础知识
- 关于对象流两端的数据不一致的问题:
- 【Gym-100085 K】Kingdom Roadmap【树上构造题】
- JBoss中间件漏洞总结
- Php把ts转为mp4,ts格式转换mp4 - 狸窝
- 打卡day01 python基础—常用数据类型
- 电脑关机后电源灯还亮
- Win10 电脑屏幕亮度随背景颜色变化而变化
- 【PID优化】基于matlab粒子群算法优化BP神经网络PID控制【含Matlab源码 2022期】
- Xcode 发布测试包TestFlight
- MySQL 修改报错 You can't specify target table 'tb_trade' for update in FROM clause
热门文章
- 现货黄金3月1日行情分析:关注通胀博弈关键点 金市高位震荡
- Open Cluster Management 部署应用实践
- 时间控件的添加,My97DatePicker时间控件的下载
- 注意力评分函数(掩蔽softmax操作,加性注意力,缩放点积注意力)
- 北京ios培训-如何选择好的iOS开发培训机构
- 优达twitter 清理_Udacity优达学城数据分析视频
- matlab for判断语句,matlab使用笔记(一)——matlab语言中if、for语句与C语言中的差别...
- 8255a初始化c语言程序,8255A的c语言程序.doc
- 解剖95后—洞悉未来十年消费红利.pdf
- 从理论到实践落地「微服务