那么在这里我就来写一写关于mlx90614红外测温的驱动代码和来说一说他的事理。紧张是利用STM32F103C8T6单片机和mlx90614模块将丈量的温度显示到0.96寸oled上面,如果你没有oled的话也可以用串口调试助手把温度信息打印出来。
一、所需材料
STM32F103C8T6最小系统板+mlx90614红外测温模块+0.96寸oled+一个jlink下载器。

带红外测温枪方案的开拓板-OWL Micro F1 快速购买

二、mlx90614传感器先容
MLX90614 系列模块是一组通用的红外测温模块。在出厂前该模块已进行校验及线性化,具有非打仗、体积小、精度高,本钱低等优点。被测目标温度和环境温度能通过单通道输出,并有两种输出接口,适宜于汽车空调、室内暖气、家用电器、手持设备以及医疗设备运用等。测温办法可分为打仗式和非打仗式,打仗式测温只能丈量被测物体与测温传感器达到热平衡后的温度,以是相应韶光长,且极易受环境温度的影响;而红外测温是根据被测物体的红外辐射能量来确定物体的温度,不与被测物体打仗,具有影响动被测物体温度分布场,温度分辨率高、相应速率快、测温范围广、不受测温上限的限定、稳定性好等特点,以是我们选择mlx90614来作为红外测温模块。 单片机与mlx90614红外测温模块之间通信的办法是“类IIC”通信,意思便是通信办法跟IIC通信办法很像但又不是IIC,它有其余一个名字叫做SMBus。SMBus (System Management Bus)是 1995 年由 intel 公司提出的一种高效同步串行总线,SMBus 只有两根旗子暗记线:双向数据线和时钟旗子暗记线,容许 CPU 与各种外围接口器件以串行办法进行通信、交流信息,即可以提高传输速率也可以减鄙吝件的资源占用,其余纵然在没有SMBus 接口的单片机上也可利用软件进行仿照。
三、MLX90614事情事理MLX90614由MLX81101红外热电堆传感器和包括含有稳压电路、低噪声放大器、A/D转换器、DSP单元、脉宽调制电路及逻辑掌握电路的MLX90302旗子暗记处理芯片构成。 其事情事理为:红外热电堆传感器输出的温度旗子暗记经由内部低噪声、低失落调的运算放大器(OPA)放大后经由A/D转换器(ADC)转换为17位数字旗子暗记通过可编程FIR及IIR低通数字滤波器(即DSP)处理后输出,输出结果存储在其内部RAM存储单元中。
MLX90614中有两个存储器,分别为EEPROM和RAM。MLX90614共有32个字长为16位的EEPROM存储单元,其地址为000H—01FH。EEPROM中所有的寄存器都是可以通过SMBus进行读取,但只有部分寄存器是可以进行改写的(地址为0x00, 0x01, 0x02, 0x03, 0x04, 0x05,0x0E, 0x0F, 0x09)。可改写部分如左表所示。
Tomax和Tomin是设定的丈量物体温度上、下限,Ta范围即环境温度范围。其丈量温度上限打算方法为:Tomax=100×(To MAX+273.15),通过打算将结果写入000H;温度下限打算方法与上限打算方法一样,将打算结果写入001H。MLX90614中统共有32个17位的RAM存储单元,用户不能通过RAM来写入数据,只能读取RAM中的部分存储单元读取16位存储数据。其采集的环境温度数据保存在地址006H存储单元中,采集的被测物体温度数据存储在007H存储单元中。因此利用存储在RAM地址中的数据,通过公式的打算,可以得到环境温度Ta及被测物体温度数据To。
Ta和To既可通过SMBus读取RAM单元(分辨率0.02°C ,固定例模)输出,也可通过PWM数字模式输出(10位分辨率,范围可配置)。由于变电所测温温度范围与MLX90614出厂时校准的温度范围符合,因此可直接采取SMBus办法进行温度数据Ta和To的读取输出。
Ta=RAM(006H)x0.02-273.15
To=RAM(007H)x0.02-273.15
四、IIC协议事理IIC主从机之间通讯步骤如下:
1.主机发送一个起始旗子暗记关照各从机就位;
2.主机发送从机地址和读写标志位(写标志位为0,读标志位为1)从机地址和读写标志位一共占用8位,地址占用高7位,读写标志位占用最低位;
3从机给主机回答相应(ACK);
4.如果是写模式,主机发送一字节数据等待从机相应,主机收到相应之后如果还有数据要发就连续发送第二段数据等待相应……直到发送完成;如果是读模式,此时主机STM32读取从机发来的数据,并给从机相应,如果从机还有数据要发送(接着申报请示第二段),主机接着读取然后发送相应给从机…
5.主机给从机一个停滞旗子暗记。
1.写时序首先主机发送一个起始位,然后在发送从机的地址0x00和写标志位0,一共是8位。发送这8位之后,主机等待从机的相应,如果从机发送的是应答旗子暗记,主机就连续向从机发送一个字节的数据,同理再一次等待从机的相应,主机收到相应之后如果还有数据要发就连续发送第二段数据等待相应…直到发送完成;
写所用到的函数有:
1.void SMBus_StartBit(void);—主机发送一个起始位
2.u8 SMBus_ SendByte (u8 ack_nack);—主机发送从机的地址和写标志位
3.SMBus_ReceiveBit(ack_nack);—从机发送的是应答旗子暗记
4.u8 SMBus_SendByte(u8 ack_nack);—主机发送从机的一个字节的数据
5.void SMBus_StopBit(void);—主机发送一个停滞位
2.读时序首先主机发送一个起始位,然后在发送从机的地址0x00和读标志位1,一共是8位。发送这8位之后,主机等待从机的相应,如果从机发送的是应答旗子暗记,从机就向主机发送一个字节的数据。读时序便是主机从从机读数据,反过来便是从机向主机发送数据,同理,从机在发送完一个字节的数据之后也要向主机讯问是否连续发送,如果主机让连续发送也便是发送了应答旗子暗记,那么从机就连续发送数据,每次发送完之后都要讯问是否要连续发送,直到主机发送了非应答旗子暗记,从机才停滞发送数据,末了主机再发送一个停滞旗子暗记即可。
读所用到的函数有:
1.void SMBus_StartBit(void);—主机发送一个起始位
2.u8 SMBus_ SendByte (u8 ack_nack);—主机发送从机的地址和写标志位
3.SMBus_ReceiveBit(ack_nack);—从机发送的是应答旗子暗记
4.u8 SMBus_ReceiveByte (u8 ack_nack);—从机向主机发送的一个字节的数据
5.void SMBus_StopBit(void);—主机发送一个停滞位
3.通信过程1.起始旗子暗记—在时钟线SCL高电日常平凡代数据线SDA发生低落沿跳变产生起始旗子暗记2.应答旗子暗记—在时钟线SCL为高电日常平凡代数据线SDA保持低电平为应答旗子暗记3.非应答旗子暗记—在时钟线SCL为高电日常平凡代数据线SDA保持高电平为非应答旗子暗记4.结束旗子暗记—在时钟线SCL高电日常平凡代数据线SDA发生上升沿跳变产生停滞旗子暗记5.数据旗子暗记—在数据传输期间,时钟线 SCL 为高电日常平凡代,如果数据线 SDA 为高电平则代表二进制1,同理,时钟线 SCL 为高电日常平凡代,如果数据线 SDA 为低电平则代表二进制 0。6.上面1号框是SDA 数据有效期,2号框是数据改变期。五、程序编写1.起始旗子暗记与停滞旗子暗记voidSMBus_StartBit(void){SMBUS_SDA_H();//首先拉高数据线SMBus_Delay(5);//延时几奇妙SMBUS_SCK_H();//拉高时钟线SMBus_Delay(5);//延时几奇妙SMBUS_SDA_L();//拉低数据线SMBus_Delay(5);//延时几奇妙//在SCK=1时,检测到SDA由1到0表示通信开始(低落沿)SMBUS_SCK_L();//拉低时钟线SMBus_Delay(5);//延时几奇妙}voidSMBus_StopBit(void){SMBUS_SCK_L();//拉低时钟线SMBus_Delay(5);//延时几奇妙SMBUS_SDA_L();//拉低数据线SMBus_Delay(5);//延时几奇妙SMBUS_SCK_H();//拉高时钟线SMBus_Delay(5);//延时几奇妙SMBUS_SDA_H();//拉高数据线}2.发送一个字节
u8SMBus_SendByte(u8Tx_buffer){u8Bit_counter;u8Ack_bit;u8bit_out;for(Bit_counter=8;Bit_counter;Bit_counter--){if(Tx_buffer&0x80)//如果最高位为1{bit_out=1;//把最高位置1}else//如果最高位为0{bit_out=0;//把最高位置0}SMBus_SendBit(bit_out);//把最高位发送出去Tx_buffer<<=1;//左移一位把最高位移出去等待下一个最高位,循环8次,每次都发最高位,就可把一个字节发出去了}Ack_bit=SMBus_ReceiveBit();//GetacknowledgmentbitreturnAck_bit;}
发送一个字节也便是8个bit位,我们的做法便是循环8次,每次将最高位发送出去。如果最高位为1,我们将这一个字节Tx_buffer和0x80(10000000)进行"与运算",把最高位置为1。如果最高位为0,就把最高位置为0,再通过 SMBus_SendBit(bit_out); 把最高位发送出去,之后再通过Tx_buffer<<=1;左移一位把最高位移出去等待下一个最高位,循环8次,每次都发最高位,就可把一个字节发出去了。这里是SMBus发送一个字节,我们知道在从机发送完一个字节之后,主机要返回一个应答旗子暗记见告从机是否连续发送下一个字节,以是这里我们 利用Ack_bit=SMBus_ReceiveBit();这条语句来见告从机是否还要连续发送下一个字节,如果返回的是0就连续发送,如果返回的是1就停滞发送。
3.吸收一个字节u8SMBus_ReceiveByte(u8ack_nack){u8RX_buffer;u8Bit_Counter;for(Bit_Counter=8;Bit_Counter;Bit_Counter--){if(SMBus_ReceiveBit())//GetabitfromtheSDAline{RX_buffer<<=1;//IfthebitisHIGHsave1inRX_bufferRX_buffer|=0x01;//如果Ack_bit=1,把收到应答旗子暗记1与00000001进行或运算,确保为1}else{RX_buffer<<=1;//IfthebitisLOWsave0inRX_bufferRX_buffer&=0xfe;//如果Ack_bit=1,把收到应答旗子暗记0与11111110进行与运算,确保为0}}SMBus_SendBit(ack_nack);//把应答旗子暗记发出去,如果0,就进行下一次通信,如果为1,就拜拜了。returnRX_buffer;}
从SMBus上吸收一个字节也便是8位,我们也是用一个for循环将8位依次接管过来。首先问我们通过if函数来判断SMBus_ReceiveBit()是否是收到了应答旗子暗记,如果收到了的应答旗子暗记也便是1,我们就将收到的数据左移1位RX_buffer <<= 1;如果左移一位之后空出的那一位数据位1然后就与0x01也便是0000 0001 进行"或运算",确保为1。如果左移一位之后空出的那一位数据位0然后就与0xfe也便是1111 1110 进行"或运算",确保为0。末了SMBus把应答旗子暗记发出去,如果0,就进行下一次通信,如果为1,就拜拜了,就不接管数据了。
4.数据校验u8PEC_Calculation(u8pec[]){u8crc[6];//存放多项式u8BitPosition=47;//存放所有数据最高位,68=48最高位便是47位u8shift;u8i;u8j;u8temp;do{crc[5]=0;crc[4]=0;crc[3]=0;crc[2]=0;crc[1]=0x01;crc[0]=0x07;BitPosition=47;shift=0;i=5;j=0;while((pec[i]&(0x80>>j))==0&&i>0){BitPosition--;if(j<7){j++;}else{j=0x00;i--;}}shift=BitPosition-8;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;}shift--;}for(i=0;i<=5;i++){pec[i]^=crc[i];}}while(BitPosition>8);returnpec[0];}
这个数据校验是很主要的,目的便是来判断检测你采集的数据是否是是精确的。
也便是我们程序会把PEC的数据通过SA_W、Command、SA_R把LSByte、MSByte读出来。然后我们自己再写一个校验的函数来判断读到的PEC数据是否精确,如果精确了才能进行下一步的判断,如果禁绝确的话就连续读,直到精确为止。如何才能知道自己读到的数据是否精确呢?
这就须要自己单独建立一个C工程,把这个函数u8 PEC_Calculation(u8 pec[])放到里面运行一遍,看看自己输入的数据时候跟自己要得到数据数据是否一样就可以了。也便是把0x00、0x3a、0xd2、0xb5、0x07、0xb4放到这个函数运行,终极返回出来的数据是否是0x30就可以了,如果是就解释数据校验精确,如果不是就须要该函数,至于为啥返回的是0x30请看上面的时序表。
5.读取温度函数u16SMBus_ReadMemory(u8slaveAddress,u8command){u16data;u8Pec;u8DataL=0;u8DataH=0;u8arr[6];u8PecReg;u8ErrorCounter;ErrorCounter=0x00;//InitialisingofErrorCounterslaveAddress<<=1;//2-7位表示从机地址从机地址左移一位,把读写位空出来do{repeat:SMBus_StopBit();--ErrorCounter;if(!ErrorCounter)//ErrorCounter=0?{break;//如果为0就跳出do-while{}循环}SMBus_StartBit();if(SMBus_SendByte(slaveAddress))//发送从机地址最低位Wr=0表示接下来写命令{gotorepeat;}if(SMBus_SendByte(command))//发送命令{gotorepeat;}SMBus_StartBit();if(SMBus_SendByte(slaveAddress+1))//发送从机地址+1最低位Rd=1表示接下来读数据{gotorepeat;}DataL=SMBus_ReceiveByte(ACK);//读低位数据保存到DataLDataH=SMBus_ReceiveByte(ACK);//读高位数据保存到DataHPec=SMBus_ReceiveByte(NACK);//读校验数据保存到PecSMBus_StopBit();arr[5]=slaveAddress;arr[4]=command;arr[3]=slaveAddress+1;arr[2]=DataL;arr[1]=DataH;arr[0]=0;PecReg=PEC_Calculation(arr);//CalculateCRC数据校验}while(PecReg!=Pec);data=(DataH<<8)|DataL;returndata;}
这个函数的输入参数就IIC设备的从机地址和command寄存器地址。首先从机地址左移一位,把读写位空出来,由于不知道最开始是啥状态,我们就须要发送一个停滞旗子暗记,由于ErrorCounter=0x00;那么进行"--"操作之后就不即是0,就进行下面的操作。接下来就发送起始旗子暗记,发送从机设备地址,如果发送的从机地址精确,就接着发送操作从机地址的command这个地址,由于这里保存着温度数据。然后重新发起一个起始旗子暗记,开始读数据,把温度数据的低位DataL高位DataH 和PEC数据读出来,再进行PEC数据校验,判断读到的PEC数据和校验得到的PEC数据是否相等,相等的话就跳出循环,通过将高位数据左移8位再与低8位进行按位或就得到了终极的数据data。
6.得到终极温度值floatSMBus_ReadTemp(void){floattemp;temp=SMBus_ReadMemory(0x00,0x07)0.02-273.15;returntemp;}
通过数据手册我们知道将终极读取的数据0.02-273.15就会得到终极的温度实际值,通过串口打印或者oled显示就可以得到传感器读取的温度了。
六、CRC8校验事理1.模2除法模2除法与算术除法类似,但每一位除的结果不影响其它位,即不向上一位借位,以是实际上便是异或。在循环冗余校验码(CRC)的打算中有运用到模2除法。CRC校验中有两个关键点,一是预先确定一个发送端和吸收端都用来作为除数的二进制比特串(或多项式),可以随机选择,也可以利用国际标准,但是最高位和最低位必须为1;二是把原始帧与上面打算出的除数进行模2除法运算,打算出CRC码。
2.详细步骤1.选择得当的多项式,确定除数。
2.看选定多项式的二进制位数,然后将要发送的数据上面加上这个位数1位的0,然后用得到的数据以模2除法的办法除上面确定的除数,得到的余数便是该数的CRC校验码。把稳,余数的位数一定只比除数位数少一位,也便是CRC校验码位数比除数位数少一位,如果前面位是0也不能省略。
3.实例1现假设我们利用的多项式为:G(X) =X^ 8 + X^ 2+X^ 1+1,哀求出0x1A的CRC8校验码。下面是详细的打算过程:1.将多项式转化为二进制序列,由G(X) = X^ 8 + X^ 2+X^ 1+1可知二进制一种有9位,第8位、第2位、第1位和第0位分别为1,则序列为100000111。2.原来要打算的数据为1 1010,多项式的最高次为8,则在数据的后面加上8位0,数据变为110100000 0000,然后利用模2除法除以除数100000111,终极得到的除不尽的余数,变为我们哀求的CRC8结果。
3.末了除不尽的余数为0x46,以是0x1A按多项式G(X) = X8+X2+X+1打算得到的CRC8码为0x46。
4.示例2也便是求0xb4 0x07 0xb5 0xd2 0x3a 的CRC8校验码是否是0x30
1.将多项式转化为二进制序列,由G(X) = X^8+X^2+X^1+1可知二进制一种有9位,第8位、第2位、第1位和第0位分别为1,则序列为100000111。
2.原来要打算的数据为b4 07 b5 d2 3a转换为2进制便是
1011010000000111101101011101001000111010多项式的最高次为8,则在数据的后面加上8位0,数据变为101101000000011110110101110100100011101000000000
然后利用模2除法除以除数100000111,终极得到的除不尽的余数,变为我们哀求的CRC8结果。
5.读取温度函数
u16SMBus_ReadMemory(u8slaveAddress,u8command){u16data;u8Pec;u8DataL=0;u8DataH=0;u8arr[6];u8PecReg;u8ErrorCounter;ErrorCounter=0x00;//InitialisingofErrorCounterslaveAddress<<=1;//2-7位表示从机地址从机地址左移一位,把读写位空出来do{repeat:SMBus_StopBit();--ErrorCounter;if(!ErrorCounter)//ErrorCounter=0?{break;//如果为0就跳出do-while{}循环}SMBus_StartBit();if(SMBus_SendByte(slaveAddress))//发送从机地址最低位Wr=0表示接下来写命令{gotorepeat;}if(SMBus_SendByte(command))//发送命令{gotorepeat;}SMBus_StartBit();if(SMBus_SendByte(slaveAddress+1))//发送从机地址+1最低位Rd=1表示接下来读数据{gotorepeat;}DataL=SMBus_ReceiveByte(ACK);//读低位数据保存到DataLDataH=SMBus_ReceiveByte(ACK);//读高位数据保存到DataHPec=SMBus_ReceiveByte(NACK);//读校验数据保存到PecSMBus_StopBit();arr[5]=slaveAddress;arr[4]=command;arr[3]=slaveAddress+1;arr[2]=DataL;arr[1]=DataH;arr[0]=0;PecReg=PEC_Calculation(arr);//CalculateCRC数据校验}while(PecReg!=Pec);data=(DataH<<8)|DataL;returndata;}
这个函数的输入参数就IIC设备的从机地址和command寄存器地址。首先从机地址左移一位,把读写位空出来,由于不知道最开始是啥状态,我们就须要发送一个停滞旗子暗记,由于ErrorCounter=0x00;那么进行"--"操作之后就不即是0,就进行下面的操作。接下来就发送起始旗子暗记,发送从机设备地址,如果发送的从机地址精确,就接着发送操作从机地址的command这个地址,由于这里保存着温度数据。然后重新发起一个起始旗子暗记,开始读数据,把温度数据的低位DataL高位DataH 和PEC数据读出来,再进行PEC数据校验,判断读到的PEC数据和校验得到的PEC数据是否相等,相等的话就跳出循环,通过将高位数据左移8位再与低8位进行按位或就得到了终极的数据data。
6.得到终极温度值floatSMBus_ReadTemp(void){floattemp;temp=SMBus_ReadMemory(0x00,0x07)0.02-273.15;returntemp;}
通过数据手册我们知道将【终极读取的数据0.02-273.15】就会得到终极的温度实际值,通过串口打印或者oled显示就可以得到传感器读取的温度了。
更多干货内容只须要你关注电子芯吧客微信"大众年夜众号
声明:本文系网络转载,版权归原作者所有。










