利用STM32制作红外测温仪之软件设计(MLX90614)
生活随笔
收集整理的這篇文章主要介紹了
利用STM32制作红外测温仪之软件设计(MLX90614)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
目錄
- (一)工程目錄如圖:
- (二)main函數實現:
- (三)MLX90614測溫代碼實現
前面介紹了使用 STM32制作紅外測溫儀硬件設計,今天來說一下軟件的實現,具體的程序,完整的keil代碼我已經打包放在了這里 MLX90614紅外測溫儀軟件設計.rar
由于程序流程比較清晰,這里我就不把程序流程圖貼出來了,直接上代碼。
(一)工程目錄如圖:
(二)main函數實現:
/******************************************************* *文件名: main.c *作 者: 水枂:https://me.csdn.net/download/weixin_43839785 *生成日期: 2019/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.44ms MLX_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.C 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(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.C uint8_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數值 0x000000000107 crc[4]=0; crc[3]=0; crc[2]=0; crc[1]=0x01; crc[0]=0x07; Bitposition=47; //設置Bitposition的最大值為47 shift=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" { //是 - 當前字節 + 1 temp=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為要轉換的數據 *修改時間 : 2019/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青年
簡書:水枂
總結
以上是生活随笔為你收集整理的利用STM32制作红外测温仪之软件设计(MLX90614)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基金收益多少可以止盈
- 下一篇: dc/ep是什么意思