1、 C 语言代码MLX90614 和单片机 STC12C5604AD 的 SMBus, PWM 通信 1 / 381 目的该文档的主要目的是描述怎样实现单片机和红外温度计 MLX90614 的 SMBus 通信,并简略介绍利用单片机对 MLX90614 的 PWM 输出脉冲进行测量并计算相关温度。代码是基于 STC12C5604AD 单片机的。实例给出了由 C 语言实现 MLX90614 读取物体温度,写入数据到 MLX90614、以及对 PWM 脉冲的测量和计算等功能。 2 C 代码2.1 由 MLX90614 读取温度部分实例给出了应用 C 语言来实现从 MLX90614 中读取物体温度的程
2、序。为了使程序操作和运行简单起见,整个项目被分为几个子项目。在该文档中整个 C 程序分为主文件 SMBus.c (用来实现对物体温度的读取、改变 SMBus 地址、改变发射率、以及改变 PWMCTRL 配置参数功能);子文件 SMBus_CM.c(具体描述SMBus 通信的起始状态,终止状态,发送和接受数据); 子文件 SMBus_OP.c(包含了利用 SMBus 通信由MLX90614 读取数据,对 MLX90614 写入数据和 PEC 校验码计算的程序);子文件 Delay.c(调用延迟函数);子文件 dec2hex.c(将十进制转换为十六进制);子文件 CalTem.c(根据十六进制数值
3、计算温度读数);子文件 digitalLED.c(在数字 LEDs 上显示温度读数)。在主文件的头文件中引用相应的子文件.h 文件,以将所有功能综合、链接起来。/-/-/主文件 SMBus.c/-/-/红外温度计MLX90614 中读取物体温度描述:该文件是基于单片机 STC12C5604AD 编写的 C 语言程序,可通过 SMBus 实现对 MLX90614 温度数据的读取,对 MLX90614 写入数据的功能。实例给出了读取物体温度的程序,以及可根据十六进制数值计算温度数值并在数字 LEDs 上显示温度的程序,但是此为可选项,用户可根据自己的应用另行选择其他方式。/-/头文件C 语言代码M
4、LX90614 和单片机 STC12C5604AD 的 SMBus, PWM 通信 2 / 38/-/#include #include “stdio.h“ #include “intrins.h“ #include “string.h“#include “SMBus_CM.h“ /引用 SMBus_CM.h 文件(包含起始状态,终止状态,发送,接收字节等)#include “SMBus_OP.h“ /引用 SMBus_OP.h 文件(包含由 MLX90614 中读取数据和写入数据)#include “digitalLED.h“ /引用 digitalLED.h 文件以在数字 LEDs 上显示
5、温度读数 #include “CalTem.h“ /引用 CalTem.h 文件来根据十六进制数值计算温度#include “dec2hex.h“ /引用 dec2hex.h 文件将十进制转换为十六进制 #include “Delay.h“ /引用 Delay.h 文件/-/宏定义 I/O 端口和 SMBus 信号输入输出方向/-/#define _SDA_OUTPUT P1M0=0x10; P1M1=0x10; /设置 SDA 为开漏输出#define _SDA_INPUT P1M0=0x10; P1M1=0x00; /设置 SDA 为高阻输入#define _SCL_IO P1M0=0x0
6、8; P1M1=0x08; /设置 SCL 为开漏输出的 I/O 端口 sbit SDA = P14; /指定 SDA 线给 P14sbit SCL = P13; /指定 SCL 线给 P13/-/主函数功能作用:读取物体温度/-/void main()unsigned char slaveaddress; unsigned long int DATA;unsigned int *mahm;_SCL_IO; /引用宏定义- 设置 SCL 为开漏式 I/O 口_SDA_OUTPUT; /引用宏定义-设置 SDA 为开漏式输出C 语言代码MLX90614 和单片机 STC12C5604AD 的 S
7、MBus, PWM 通信 3 / 38SCL=0; /Delay(1200); /SMBus 请求时间,将 PWM 模式转换为 SMBus 模式(至少为 2ms)SCL=1; /while(1)slaveaddress=MEM_READ(0x00,0x2E); /读取存于 MLX90614 EEPROM “0Eh“地址中的 SMBus 地址DATA=MEM_READ(slaveaddress,0x07); /基于上述地址由 MLX90614 的内存 07h 中读取物体温度mahm=CALTEMP(DATA); /基于所得的十六进制温度格式计算实际温度show(mahm,5); /在数字 LED
8、s 上显示计算所得温度/-/-/子文件 SMBus_CM.c/-/-/该文档包含了 SMBus 通信的起始状态,终止状态,发送和接受字节等/-/头文件/-/#include #include “SMBus_CM.h“ /头文件中引用本身#include “intrins.h“#include “Delay.h“ C 语言代码MLX90614 和单片机 STC12C5604AD 的 SMBus, PWM 通信 4 / 38/-/宏定义 I/O 端口和 SMBus 信号的方向/-/#define _SDA_OUTPUT P1M0=0x10; P1M1=0x10; /设置 SDA 为开漏输出#def
9、ine _SDA_INPUT P1M0=0x10; P1M1=0x00; /设置 SDA 为高阻输入#define _SCL_IO P1M0=0x08; P1M1=0x08; /设置 SCL 为开漏式 I/O 端口sbit SDA = P14; /指定 SDA 线给 P14sbit SCL = P13; /指定 SCL 线给 P13/-/函数名: start_bit功能: 在 SMBus 总线上产生起始状态注解: 参考 “系统管理总线说明书-版本 2.0”/-/void start_bit()_SDA_OUTPUT; /设置 SDA 为输出SDA=1; /设置 SDA 线为高电平_nop_()
10、;_nop_(); SCL=1; /设置 SCL 线为高电平Delay(5); /在终止和起始状态之间产生总线空闲时间(Tbuf=4.7us 最小值)SDA=0; /设置 SDA 线为低电平Delay(5); /(重复)开始状态后的保持时间,在该时间后,产生第一个时钟信号/Thd:sta=4us 最小值SCL=0; /设置 SCL 线为低电平_nop_();_nop_();/-/函数名: stop_bit功能: 在 SMBus 总线上产生终止状态注解: 参考 “系统管理总线说明书-版本 2.0”C 语言代码MLX90614 和单片机 STC12C5604AD 的 SMBus, PWM 通信 5
11、 / 38/-/void stop_bit()_SDA_OUTPUT; /设置 SDA 为输出SCL=0; /设置 SCL 线为低电平Delay(5);SDA=0; /设置 SDA 线为低电平Delay(5);SCL=1; /设置 SCL 线为高电平Delay(5); /终止状态建立时间(Tsu:sto=4.0us 最小值)SDA=1; /设置 SDA 线为高电平 /-/函数名: send_bit功能:在 SMBus 总线上发送一位数据/-/void send_bit(unsigned char bit_out)_SDA_OUTPUT; /设置 SDA 为开漏输出以在总线上传送数据if(bit
12、_out=0) /核对字节的位/如果 bit_out=1,设置 SDA 线为高电平SDA=0;else SDA=1; /如果 bit_out=0,设置 SDA 线为低电平_nop_(); /_nop_(); /Tsu:dat=250ns 最小值_nop_(); /SCL=1; /设置 SCL 线为高电平Delay(4); /时钟脉冲高电平脉宽(10.6us)SCL=0; /设置 SCL 线为低电平Delay(4); /时钟脉冲低电平脉宽 C 语言代码MLX90614 和单片机 STC12C5604AD 的 SMBus, PWM 通信 6 / 38/-/函数名: receive_bit功能:在
13、SMBus 总线上接收一位数据/-/unsigned char receive_bit()unsigned char bit_in;_SDA_INPUT; /设置 SDA 为高阻输入SCL=1; /设置 SCL 线为高电平Delay(2);if(SDA=1) /从总线上读取一位,赋给 bit_inbit_in=1;elsebit_in=0;Delay(2);SCL=0; /设置 SCL 线为低电平Delay(4);return bit_in; /返回 bit_in 值/-/函数名: slave_ack功能: 由受控器件 MLX90614 中读取确认位返回值: unsigned char ack
14、1 - ACK0 - NACK/-/unsigned char slave_ack()unsigned char ack;ack=0;_SDA_INPUT; /设置 SDA 为高阻输入SCL=1; /设置 SCL 线为高电平Delay(2); if(SDA=1) /从总线上读取一位,赋给 ackC 语言代码MLX90614 和单片机 STC12C5604AD 的 SMBus, PWM 通信 7 / 38ack=0;elseack=1; Delay(2); SCL=0; /设置 SCL 线为低电平Delay(4); return ack;/-/发送一个字节函数名: TX_byte功能: 在 SM
15、Bus 总线上发送一个字节参数: unsigned char TX_buffer (将要在总线上发送的字节)注解: 先发送字节的高位/-/void TX_byte(unsigned char TX_buffer)unsigned char Bit_counter;unsigned char bit_out;for(Bit_counter=8;Bit_counter;Bit_counter-)if(TX_buffer /如果 TX_buffer 的当前位是 1,设置 bit_out 为 1elsebit_out=0; /否则,设置 bit_out 为 0send_bit(bit_out); /发
16、送 SMBus 总线上的当前位 TX_buffer#include “SMBus_CM.h“ /引用 SMBus_CM.h 文件 #include “intrins.h“#include “SMBus_OP.h“ /头文件中引用本身#include “Delay.h“/-/sbit SDA = P14; /指定 MLX90614 的 SDA 线给单片机 P14 引脚sbit SCL = P13; /指定 MLX90614 的 SCL 线给单片机 P13 引脚/-/计算 PEC 包裹校验码函数名: PEC_cal功能: 根据接收的字节计算 PEC 码参数: unsigned char pec,
17、int n返回值: pec0 - 该字节包含计算所得 crc 数值注解: 参考“系统管理总线说明书-版本 2.0”和应用指南“MCU 和 MLX90614 的 SMBus 通信“/-/unsigned char PEC_cal(unsigned char pec,int n)unsigned char crc6;unsigned char Bitposition=47;unsigned char shift;unsigned char i;unsigned char j;unsigned char temp;docrc5=0; /载入 CRC 数值 0x000000000107crc4=0;c
18、rc3=0;C 语言代码MLX90614 和单片机 STC12C5604AD 的 SMBus, PWM 通信 10 / 38crc2=0;crc1=0x01;crc0=0x07;Bitposition=47; /设置 Bitposition 的最大值为 47shift=0;/在传送的字节中找出第一个“1”i=5; /设置最高标志位 (包裹字节标志)j=0; /字节位标志,从最低位开始while(peciif(j0) /核对字节的最高位的下一位是否为“1“ /是 - 当前字节 + 1temp=1; /否 - 当前字节 + 0 /实现字节之间移动“1”elsetemp=0;crci8); retu
19、rn pec0; /返回计算所得的 crc 数值 /-/由 MLX90614 RAM/EEPROM 读取的数据函数名: MEM_READ功能: 给定受控地址和命令时由 MLX90614 读取数据参数: unsigned char slave_addR (受控地址)unsigned char cmdR (命令)返回值: unsigned long int Data/-/unsigned long int MEM_READ(unsigned char slave_addR, unsigned char cmdR)unsigned char DataL; /unsigned char DataH;
20、/由 MLX90614 读取的数据包unsigned char PEC; /unsigned long int Data; /由 MLX90614 返回的寄存器数值unsigned char Pecreg; /存储计算所得 PEC 字节unsigned char arr6; /存储已发送字节的缓冲器unsigned char ack_nack;unsigned char SLA;SLA=(slave_addR#include “intrins.h“#include “Delay.h“/-/ 函数名: Delay功能: 延迟一定的时间参数: N 表示延迟时间为 MCU 机器周期的 N 倍注解:
21、机器周期是时钟周期(1/Fosc)的 12 倍,对于 STC12C5604AD, Fosc=11.0592MHz/-/void Delay(unsigned int N) unsigned int i;for(i=0;i=27315)T=T-27315;a=T/100;b=T-a*100;if(a=100)A4=a/100;a=a%100;A5=a/10;a=a%10;A6=a;else if(a=10)A4=0;A5=a/10;a=a%10;A6=a;else A4=0;A5=0;A6=a;if(b=10)A7=b/10;b=b%10;A8=b;C 语言代码MLX90614 和单片机 STC
22、12C5604AD 的 SMBus, PWM 通信 19 / 38elseA7=0;A8=b;elseT=27315-T;a=T/100;b=T-a*100;A4=9;if(a=10)A5=a/10;a=a%10;A6=a;else A5=0;A6=a;if(b=10)A7=b/10;b=b%10;A8=b;elseA7=0;A8=b;mah4=A4;C 语言代码MLX90614 和单片机 STC12C5604AD 的 SMBus, PWM 通信 20 / 38mah3=A5;mah2=A6;mah1=A7;mah0=A8;return mah;/-/-/子文件 digitalLED.c/-/
23、-/根据计算所得数据在数字式 LEDs 上显示/-/#include #include “digitalLED.h“ /头文件引用自身/-/定义 I/O 端口去控制数字式 LEDs/-/sbit a0 = P17; /指定 a0 线给 P17sbit a1 = P15; /指定 a1 线给 P15sbit a2 = P16; /指定 a2 线给 P16/-/函数名: show功能: 在数字式 LEDs 上显示温度读数参数: unsigned int mahh,int number注解: 显示存储在数组 mahh5的数据/-/C 语言代码MLX90614 和单片机 STC12C5604AD 的
24、SMBus, PWM 通信 21 / 38void show(unsigned int mahh,int number)unsigned char yanshicon; unsigned char weicon;unsigned char code LED_tab10= 0xFC, /00x60, /10xDA, /20xF2, /30x66, /40xB6, /50xBE, /60xE0, /70xFE, /80xF6, /9;P2=0; /关显示a0=1;a1=1;a2=1;/a2,a1,a0 控制显示位置,可由 0-7 之间变化/控制显示位置,当其值为 0-7 时,对应数码管位 1-8
25、位while(1) if(+yanshicon200) /每 200 个扫描周期执行一次yanshicon=0;if(+weicon7) weicon=0; /显示位置轮流,需要严格限制范围为 0-7 P2=0; /关显示switch(weicon)case 0: /第 1 位显示内容P2=0; /关显示a0=0;a1=0;a2=0;break;C 语言代码MLX90614 和单片机 STC12C5604AD 的 SMBus, PWM 通信 22 / 38case 1: /第 2 位显示内容P2=0; /关显示a0=1;a1=0;a2=0;break;case 2: /第 3 位显示内容P2=0;