600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > 利用STM32制作红外测温仪之软件设计(MLX90614)

利用STM32制作红外测温仪之软件设计(MLX90614)

时间:2019-10-04 02:13:33

相关推荐

利用STM32制作红外测温仪之软件设计(MLX90614)

目录

(一)工程目录如图:(二)main函数实现:(三)MLX90614测温代码实现

前面介绍了使用STM32制作红外测温仪硬件设计,今天来说一下软件的实现,具体的程序,完整的keil代码我已经打包放在了这里MLX90614红外测温仪软件设计.rar

由于程序流程比较清晰,这里我就不把程序流程图贴出来了,直接上代码。

(一)工程目录如图:

(二)main函数实现:

/********************************************************文件名: main.c*作 者: 水枂:/download/weixin_43839785*生成日期: /1/2*最后修改:*功能描述: 红外温度测量********************************************************/#include "varytypes.h"extern unsigned char image[];extern char envirTemp[][32];extern char objectTemp[][32];extern char historyTemp_max[][32];extern char historyTemp_min[][32];extern unsigned char flag;u16 volatile arr[2]={0,100};int main(void){delay_init();//延时函数初始化NVIC_Configuration();//设置NVIC中断分组0~4共5组 :2位抢占优先级,2位响应优先级 BlueTooth_Init();//蓝牙初始化USART2_Init();//串口蓝牙初始化LED_Init();//初始化LED端口PC13KEY_Init();//初始化按键端口PA0OLED_Init();//初始化oledOLED_Clear();//清屏RTCInit();//RTC时钟初始化AT24CXX_Init();//AT24C04存储初始化MLX_I2C_Init();//Mlx90614读取初始化/*****************************************温度记录值读取******************************************///arr[0]=AT24CXX_ReadOneByte(0);//max//arr[1]=AT24CXX_ReadOneByte(1);//min/*****************************************开机界面显示******************************************/OLED_ShowString(3,1,"welcome");OLED_DrawBMP(77, 1,128, 6,image);OLED_ShowString(3,4,"waiting.");delay_s(1);OLED_ShowString(3,4,"waiting..");delay_s(1);OLED_ShowString(3,4,"waiting...");delay_s(1);OLED_Clear();while(1){KEY_Scan();if(flag==0){OLED_ShowCHinese_Mul(3,1,5,objectTemp);display_temp(75,1,OBJ1TEMPADDR);OLED_ShowCHinese_Mul(3,5,5,envirTemp);display_temp(75,5,ENVITEMPADDR);}else if(flag==1){OLED_ShowCHinese_Mul(1,1,7,historyTemp_max);OLED_ShowNum(105,1,AT24CXX_ReadOneByte(0),3,16);OLED_ShowCHinese_Mul(1,5,7,historyTemp_min);OLED_ShowNum(105,5,AT24CXX_ReadOneByte(1),3,16);}}}/*****************************************************函数名 :display_temp*功 能 :显示采集回来转换后的温度*参 数 : @ x,y :起点坐标 // @object: 是环境温度还是物体温度ENVITEMPADDR、OBJ1TEMPADDR、OBJ2TEMPADDR*说 明 :Temperature data is T=(Data)*0.02-273.15运用了这个的转换公式计算温度*****************************************************/void display_temp(u8 x,u8 y,u8 object){u16 temp,T;u8 point_before,point_after;u8 point_after_one ,point_after_two;temp=I2C_ReadRAM(0x00,object);//0x00是器件的地址,由于只有一个用了0x00T=temp*2;if(T>=27315) //温度:零上{T=T-27315;point_before=T/100;point_after=T-point_before*100;point_after_one=point_after/10;//为了小数点后显示正常point_after_two=point_after%10;OLED_ShowNum(x,y,point_before,3,16);OLED_ShowString(x+24,y,".");OLED_ShowNum(x+32,y,point_after_one,1,16);OLED_ShowNum(x+40,y,point_after_two,1,16);if(object==OBJ1TEMPADDR){if(point_before>arr[0]){arr[0]=point_before;}//arr[0]存放温度最高值if(point_before<arr[1]){arr[1]=point_before;}//arr[1]存放温度最低值}}else//温度:零下{T=27315-T;point_before=T/100;point_after=T-point_before*100;OLED_ShowString(x,y,"-");OLED_ShowNum(x+8,y,point_before,3,16);OLED_ShowString(x+32,y,".");OLED_ShowNum(x+40,y,point_after,2,16);} }

(三)MLX90614测温代码实现

关于MLX90614的文档,可以直接百度,或者去淘宝卖家那要一份,MLX90614测温代码实现:

/********************************************************************************** 基于STM32F103的MLX90614红外温度传感器驱动程序********************************************************************************/#include "mlx90614.h"/*** @功能 I2C通信状态改变后的延时* @说明 无* @参数 无* @返回值 无*/void I2C_Delay(void){delay_us(5);}/*****************************************************************初始化MLX_IIC用的端口****************************************************************/void MLX_I2C_Init(void){GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);;//使能 GPIOB 时钟//GPIOB6,B7初始化设置GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽模式GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHzGPIO_Init(GPIOB, &GPIO_InitStructure);//初始化MLX_IIC_SCL=1;MLX_IIC_SDA=1;}/******************************************************************************** 函 数 名 : SDA_OUT* 函数功能 : SDA输出配置 * 输 入 : 无* 输 出 : 无*******************************************************************************/void MLX_SDA_OUT(void){GPIO_InitTypeDef GPIO_InitStructure;//GPIOB9初始化设置GPIO_InitStructure.GPIO_Pin =GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽模式GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHzGPIO_SetBits(GPIOB,GPIO_Pin_7);//上拉GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化}/******************************************************************************** 函 数 名 : SDA_IN* 函数功能 : SDA输入配置 * 输 入 : 无* 输 出 : 无*******************************************************************************/void MLX_SDA_IN(void){GPIO_InitTypeDef GPIO_InitStructure;//GPIOB9初始化设置GPIO_InitStructure.GPIO_Pin =GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//输入模式GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化}/*** @功能 产生通讯开始信号* @说明 MLX90614在SCK=1时,检测到SDA由1到0表示通信开始* @参数 无* @返回值 无*/void I2C_Start(void){MLX_SDA_OUT();MLX_IIC_SDA=1;MLX_IIC_SCL=1;I2C_Delay();MLX_IIC_SDA=0;I2C_Delay();MLX_IIC_SCL=0;I2C_Delay();}/*** @功能 产生通讯停止信号* @说明 MLX90614在SCK=1时,检测到SDA由0到1表示通信结束* @参数 无* @返回值 无*/void I2C_Stop(void){MLX_SDA_OUT();MLX_IIC_SDA=0;MLX_IIC_SCL=0;I2C_Delay();MLX_IIC_SCL=1;I2C_Delay();MLX_IIC_SDA=1;I2C_Delay();}/******************************************************************************** 函 数 名 : IIC_Ack* 函数功能 : 产生ACK应答 * 输 入 : 无* 输 出 : 无*******************************************************************************/void I2C_Ack(void){MLX_IIC_SCL=0;MLX_SDA_OUT();MLX_IIC_SDA=0;delay_us(2);MLX_IIC_SCL=1;delay_us(5);MLX_IIC_SCL=0;}/******************************************************************************** 函 数 名 : IIC_NAck* 函数功能 : 产生NACK非应答 * 输 入 : 无* 输 出 : 无*******************************************************************************/ void I2C_NAck(void){MLX_IIC_SCL=0;MLX_SDA_OUT();MLX_IIC_SDA=1;delay_us(2);MLX_IIC_SCL=1;delay_us(5);MLX_IIC_SCL=0;}/******************************************************************************** 函 数 名 : IIC_Wait_Ack* 函数功能 : 等待应答信号到来 * 输 入 : 无* 输 出 : 1,接收应答失败0,接收应答成功*******************************************************************************/u8 I2C_Wait_Ack(void){u8 tempTime=0;MLX_SDA_IN();//SDA设置为输入 MLX_IIC_SDA=1;delay_us(1); MLX_IIC_SCL=1;delay_us(1); while(MLX_READ_SDA){tempTime++;if(tempTime>250){I2C_Stop();return 1;}}MLX_IIC_SCL=0;//时钟输出0 return 0; } /*** @功能 将MLX90614的工作模式从PWM模式切换到SMBus模式* @说明 从PWM模式切换到SMBus的方法是将SCL保持至少1.44ms以上的低电平* 如果PWM没有使能就不需要发送请求命令* @参数 无* @返回值 无*/void PwmToSMBus(void){MLX_IIC_SCL=0;delay_us(1500); //大于1.44msMLX_IIC_SCL=1;}/*** @功能 退出睡眠模式* @说明 保持SCK高电平后,SDA持续至少33ms低电平,* 在退出睡眠模式后需要间隔250ms(典型值)才输出数据。* @参数 无* @返回值 无*/void Eixt_Sleep(void){MLX_IIC_SCL=1;MLX_IIC_SDA=1;I2C_Delay();MLX_IIC_SDA=0;delay_ms(35); //大于33ms退出睡眠模式MLX_IIC_SDA=1;delay_ms(260); //大于250ms开始输出数据}/*** @功能 从RAM/EEPROM中读取一个字节数据* @说明 从MLX90614中的指定地址读取一个字节数据,高位在前,低位在后* @参数 ack_nack:主机应答信号* @返回值 dat: 读取的数据*/uint8_t I2C_ReadByte(uint8_t ack){u8 i,receive=0;MLX_SDA_IN();//SDA设置为输入for(i=0;i<8;i++ ){MLX_IIC_SCL=0; delay_us(2);MLX_IIC_SCL=1;receive<<=1;if(MLX_READ_SDA)receive++; delay_us(1); } if (!ack)I2C_NAck();//发送nACKelseI2C_Ack(); //发送ACK return receive;}/*** @功能 向EEPROM写一个字节数据* @说明 在写完一个字节后检测MLX6014是否发送了应答信号* @参数 dat:需要发送的字节* @返回值 s_ack:应答信号状态*/uint8_t I2C_WriteByte(uint8_t dat){u8 t; uint8_t s_ack=0;MLX_SDA_OUT();MLX_IIC_SCL=0;//拉低时钟开始数据传输for(t=0;t<8;t++){ if((dat&0x80)>0) //0x80 1000 0000MLX_IIC_SDA=1;elseMLX_IIC_SDA=0;dat<<=1; delay_us(2); //对TEA5767这三个延时都是必须的MLX_IIC_SCL=1;delay_us(2); MLX_IIC_SCL=0;delay_us(2);} if(I2C_Wait_Ack()) //高电平表示正确接收数据 (高?低??这个应该是低电平){s_ack = ACK_FAIL;}else{s_ack = ACK_SUCCESS;}//delay_us(2*N);//修改的//MLX_IIC_SCL=0;//delay_us(4*N);return s_ack;}/*** @功能 读MLX90614的RAM中内容* @说明 主要读取三个,环境温度,物体温度1,物体温度2* 器件从地址可以通过向EEPROM的SMBus地址0x0E中写入来进行设定。* @参数 saddr:从机地址,7位地址,任何MLX90614都会对0x00地址作出反应* cmd:存放温度的寄存器地址* @返回值 Data:读取出来的数值*using Read Word: SA(write) - Command - SA(read) - LSByte - MSByte - PEC*/uint16_t I2C_ReadRAM(uint8_t saddr,uint8_t cmd){uint16_t Data;uint8_t DataL; //接收数据低字节uint8_t DataH; //接收数据高字节uint8_t PEC;uint8_t retry = 10; //失败重复次数uint8_t s_ack = 0;uint8_t Pecreg; //计算的PEC值uint8_t buf[6]; //存储已接收数据的缓存MLX_IIC_SCL=0;while(retry--){I2C_Start(); //发送起始位s_ack = I2C_WriteByte((saddr<<1)|WR); //发送从机地址和Wr位if(s_ack == ACK_SUCCESS){s_ack = 0;s_ack = I2C_WriteByte(RAM|cmd);//发送命令,8位,RAM表示对RAM操作,cmd表示操作RAM的地址if(s_ack == ACK_SUCCESS){s_ack = 0;I2C_Start(); //重新发送起始位s_ack = I2C_WriteByte((saddr<<1)+1); //发送从机地址和Rd位if(s_ack == ACK_SUCCESS){s_ack = 0;DataL = I2C_ReadByte(1); //读数据低字节DataH = I2C_ReadByte(1); //读数据高字节PEC = I2C_ReadByte(1); //读数据PEC字节// DataL=RX_byte(0); //// DataH=RX_byte(0); //// PEC=RX_byte(1);I2C_Stop(); //发送停止位buf[5]=(saddr<<1);buf[4]=EEPROM|cmd;buf[3]=(saddr<<1)|RD;buf[2]=DataL;buf[1]=DataH;buf[0]=0;Pecreg=PEC_Cal(buf,6); //调用计算 PEC 的函数if(Pecreg == PEC){break; //退出循环}}else goto stop_rr;}else goto stop_rr;}else goto stop_rr;stop_rr:I2C_Stop(); //发送停止位,芯片接收失败}PEC = PEC+1;Data = (DataH<<8) + DataL;return Data;}/*** @功能 清除EEPROM指定单元的数据* @说明 在向EEPROM中写入数据之前必须先清除内存单元中的数据,也就是全部写入0* @参数 saddr:从机地址cmd:发送命令* @返回值 无*/void I2C_ClearEEPROM(uint8_t saddr,uint8_t cmd){uint8_t retry = 10; //失败重复次数uint8_t s_ack = 0;MLX_IIC_SCL=0;while(retry--){I2C_Start(); //发送起始位s_ack = I2C_WriteByte((saddr<<1)|WR); //发送从机地址和Wr位if(s_ack == ACK_SUCCESS){s_ack = 0;s_ack = I2C_WriteByte(EEPROM|cmd);//发送命令,8位 EPROM表示对RAM操作,cmd表示操作EEPROM的地址$MLX90614.Cif(s_ack == ACK_SUCCESS){s_ack = 0;s_ack = I2C_WriteByte(0x00); //发送低字节if(s_ack == ACK_SUCCESS){s_ack = 0;s_ack = I2C_WriteByte(0x00); //发送高字节if(s_ack == ACK_SUCCESS){s_ack = 0;s_ack = I2C_WriteByte(0x6f); //发送PEC字节if(s_ack == ACK_SUCCESS){I2C_Stop(); //发送停止位break; //退出循环}else goto stop_ce;}else goto stop_ce;}else goto stop_ce;}else goto stop_ce;}else goto stop_ce;stop_ce:I2C_Stop(); //发送停止位,芯片接收失败}delay_ms(5); //擦除完成至少等待5ms}/*** @功能 读EEPROM指定单元的数据* @说明 从指定从机读取指定EEPROM地址的数据* @参数 saddr:从机地址cmd:读取EEPROM地址* @返回值 Data:读取数据*/uint16_t I2C_ReadEEPROM(uint8_t saddr,uint8_t cmd){uint8_t retry = 10;uint8_t s_ack;uint16_t Data;uint8_t DataL; //接收数据低字节uint8_t DataH; //接收数据高字节uint8_t PEC; //接收的PEC值uint8_t Pecreg; //计算的PEC值uint8_t buf[6]; //存储已接收数据的缓存while(retry--){I2C_Start(); //发送起始位s_ack = I2C_WriteByte((saddr<<1)|WR); //发送从机地址和Wr位if(s_ack == ACK_SUCCESS){s_ack = 0;s_ack = I2C_WriteByte(EEPROM|cmd); //发送命令if(s_ack == ACK_SUCCESS){s_ack = 0;I2C_Start(); //重新发送起始位s_ack = I2C_WriteByte((saddr<<1)|RD); //发送从机地址和Rd位if(s_ack == ACK_SUCCESS){s_ack = 0;DataL = I2C_ReadByte(1); //读数据低字节DataH = I2C_ReadByte(1); //读数据高字节PEC = I2C_ReadByte(1); //读数据PEC字节I2C_Stop(); //发送停止位buf[5]=(saddr<<1);buf[4]=EEPROM|cmd;buf[3]=(saddr<<1)|RD;buf[2]=DataL;buf[1]=DataH;buf[0]=0;Pecreg=PEC_Cal(buf,6); //调用计算 PEC 的函数if(Pecreg == PEC){break;}}else goto stop_re;}else goto stop_re;}else goto stop_re;stop_re:I2C_Stop();}Data = (DataH<<8) + DataL;return Data;}/*** @功能 写EEPROM指定单元的数据* @说明 在向EEPROM中写入数据之前必须先清除内存单元中的数据,也就是全部写入0* @参数 saddr:要清除数据的内存单元* @返回值 无*/void I2C_WriteEEPROM(uint8_t saddr,uint8_t cmd,uint8_t DataL,uint8_t DataH){uint8_t retry = 10; //失败重复次数uint8_t s_ack = 0;uint8_t Pecreg; //存储计算所得PEC结果$MLX90614.Cuint8_t buf[6]; //存储将要发送字节的缓冲器buf[5]=0;buf[4]=saddr<<1;buf[3]=cmd;buf[2]=DataL;buf[1]=DataH;buf[0]=0;Pecreg=PEC_Cal(buf,6);MLX_IIC_SCL=0;while(retry--){I2C_Start(); //发送起始位s_ack = I2C_WriteByte((saddr<<1)|WR); //发送从机地址和Wr位if(s_ack == ACK_SUCCESS){s_ack = 0;s_ack = I2C_WriteByte(EEPROM|cmd); //发送命令if(s_ack == ACK_SUCCESS){s_ack = 0;s_ack = I2C_WriteByte(DataL); //发送低字节if(s_ack == ACK_SUCCESS){s_ack = 0;s_ack = I2C_WriteByte(DataH); //发送高字节if(s_ack == ACK_SUCCESS){s_ack = 0;s_ack = I2C_WriteByte(Pecreg); //发送PEC码if(s_ack == ACK_SUCCESS){I2C_Stop(); //发送停止位break; //退出循环}else goto stop_we;}else goto stop_we;}else goto stop_we;}else goto stop_we;}else goto stop_we;stop_we:I2C_Stop();}delay_ms(5); //写入之后等待5ms}/*** @功能 计算PEC包裹校验码,根据接收的字节计算PEC码* @说明 计算传入数据的PEC码* @参数 pec[]:传入的数据n:传入数据个数* @返回值 pec[0]:计算得到的PEC值*/uint8_t PEC_Cal(uint8_t pec[],uint16_t n){unsigned char crc[6];unsigned char Bitposition=47;unsigned char shift;unsigned char i;unsigned char j;unsigned char temp;do{crc[5]=0; //载入 CRC数值 0x000000000107crc[4]=0;crc[3]=0;crc[2]=0;crc[1]=0x01;crc[0]=0x07;Bitposition=47; //设置Bitposition的最大值为47shift=0;//在传送的字节中找出第一个“1”i=5; //设置最高标志位 (包裹字节标志)j=0; //字节位标志,从最低位开始while((pec[i]&(0x80>>j))==0 && (i>0)){Bitposition--;if(j<7){j++;}else{j=0x00;i--;}}//while语句结束,并找出Bitposition中为“1”的最高位位置shift=Bitposition-8;//得到CRC数值将要左移/右移的数值“shift”//对CRC数据左移“shift”位while(shift){for(i=5;i<0xFF;i--){if((crc[i-1]&0x80) && (i>0))//核对字节的最高位的下一位是否为"1"{ //是 - 当前字节 + 1temp=1; //否 - 当前字节 + 0} //实现字节之间移动“1”else{temp=0;}crc[i]<<=1;crc[i]+=temp;}shift--;}//pec和crc之间进行异或计算for(i=0;i<=5;i++){pec[i]^=crc[i];}}while(Bitposition>8);return pec[0]; //返回计算所得的crc数值}/*** @功能 设定MLX90614器件地址* @说明 器件从地址可以通过向EEPROM的SMBus地址0x0E中写入来进行设定。为了给从器件设定地址,必须先以0x00+Wr当作从地址开始,当主机发送此命令,MLX90614总是会反馈并忽略掉内部芯片编码信息。向EEPROM写入数据前需要清除原来的数据,就是向修改单元写入0x0000擦除之后需要等待5ms才可以重新写入数据修改地址时写入的地址高字节MLX90614会忽略修改之后需要重新将MLX90614的电源断开重启。* @参数 soaddr:从机旧地址snaddr:从机新地址* @返回值 无*/void I2C_SetSlaveAddr(uint8_t soaddr,uint8_t snaddr){// uint8_t cmd = EEPROM|SMBUSADDR;// uint8_t DataL = snaddr;// uint8_t DataH = 0x00;// EEPROM_WRITE(snaddr,cmd,0x00,0x00);// EEPROM_WRITE(snaddr,cmd,DataL,DataH);}/**************************************************函数名 : CALTEMP()*功 能 : 把读回来的数据转换为摄氏度*说 明 : 从RAM里面读出来的是一个比较大的数(可以用显示屏打印出来看看)需要使用下面的公式把温度转换出来://Temperature data is T=(Data)*0.02-273.15*参 数 : TEMP为要转换的数据 *修改时间 : /3/15***************************************************/void CALTEMP(unsigned long int TEMP){unsigned long int T;unsigned int A, B;//unsigned int tempb;T=TEMP*2;if(T>=27315) //温度:零上{T=T-27315;A=T/100;B=T-A*100;}else//温度:零下{T=27315-T;A=T/100;B=T-A*100;} }

程序这一部分不做过多的讲解,关于测温的功能都是按照官方提供的文档进行编写的,需要自己好好参悟,最后说一下,这个MLX90614测温很容易受外界环境的干扰,需要自己写算法,在硬件上进行改进才能得到更高的准确度。

本文章仅供学习交流用禁止用作商业用途,文中所有内容均为原创未经授权

微信公众号:zhjj0729

微博:文艺to青年

简书:水枂

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。