首页资源分类IC设计及制造 > MLX90614 驱动

MLX90614 驱动

已有 460559个资源

下载专区


TI最新应用解决方案

工业电子 汽车电子 个人消费电子

上传者其他资源

文档信息举报收藏

标    签: MLX90614

分    享:

文档简介

MLX90614 驱动

文档预览

$MLX90614.C /** ****************************************************************************** * * 基于STM32F103的MLX90614红外温度传感器驱动程序 * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "stdlib.h" #include "stm32f10x.h" //=============================================================================== //#include "MLX90614.H" //-- IO Operate -- #define SetBit_SDA GPIO_SetBits(GPIOB,GPIO_Pin_10) #define ClrBit_SDA GPIO_ResetBits(GPIOB,GPIO_Pin_10) #define SetBit_SCK GPIO_SetBits(GPIOB,GPIO_Pin_11) #define ClrBit_SCK GPIO_ResetBits(GPIOB,GPIO_Pin_11) #define STA_SDA GPIOB->IDR & GPIO_Pin_10 #define STA_SCL GPIOB->IDR & GPIO_Pin_11 //-- MLX90614 Command Mode -- #define RAM #define EEPROM #define MODE #define EXITMODE #define READFLAG #define SLEEP #define RD #define WR 0x00 0x20 0x60 0x61 0xf0 0xff 0x01 0x00 //对RAM进行操作 //对EEPROM进行操作 //进入命令模式 //退出命令模式 //读标志 //进入睡眠模式 //读操作 //写操作 //-- MLX90614 RAM Address -- #define AMBITEMPADDR #define IR1ADDR #define IR2ADDR #define ENVITEMPADDR #define OBJ1TEMPADDR -70.01 ~ 382.19 度 #define OBJ2TEMPADDR -70.01 ~ 382.19 度 0x03 0x04 0x05 0x06 0x07 0x08 //周围温度 // // //环境温度 -40 ~ 125 度 //目标1温度,检测到的红外温度 //目标2温度,检测到的红外温度 //-- MLX90614 EEPROM Address -- #define TOBJMAXADDR 0x00 #define TOBJMINADDR 0x01 #define PWMCTRLADDR 0x02 #define TARANGEADDR 0x03 #define KEADDR 0x04 #define CONFIGADDR 0x05 #define SMBUSADDR 0x0e #define RES1ADDR 0x0f #define RES2ADDR 0x19 #define ID1ADDR 0x1c #define ID2ADDR 0x1d #define ID3ADDR 0x1e //测量温度上限设定 //测量温度下限设定 //PWM设定 //环境温度设定 //频率修正系数 //配置寄存器 //器件地址设定 //保留 //保留 //ID地址1 //ID地址2 //ID地址3 $MLX90614.C #define ID4ADDR //-- Special Define -- #define ACK_SUCCESS #define ACK_FAIL 0x1f 0x01 0x00 //ID地址4 //成功接收到应答信号 //没有收到应答信号 #define N 5 //以上宏定义可以放在头文件里面 //============================================================================ /** * @功能 I2C通信状态改变后的延时 * @说明 无 * @参数 无 * @返回值 无 */ void I2C_Delay(void) { Delay_us(2); } /** * @功能 产生通讯开始信号 * @说明 MLX90614在SCK=1时,检测到SDA由1到0表示通信开始 * @参数 无 * @返回值 无 */ void I2C_Start(void) { SetBit_SDA; SetBit_SCK; I2C_Delay(); ClrBit_SDA; I2C_Delay(); ClrBit_SCK; I2C_Delay(); } /** * @功能 产生通讯停止信号 * @说明 MLX90614在SCK=1时,检测到SDA由0到1表示通信结束 * @参数 无 * @返回值 无 */ void I2C_Stop(void) { ClrBit_SDA; ClrBit_SCK; I2C_Delay(); SetBit_SCK; I2C_Delay(); SetBit_SDA; I2C_Delay(); } $MLX90614.C /** * @功能 将MLX90614的工作模式从PWM模式切换到SMBus模式 * @说明 从PWM模式切换到SMBus的方法是将SCL保持至少1.44ms以上的低电平 * 如果PWM没有使能就不需要发送请求命令 * @参数 无 * @返回值 无 */ void PwmToSMBus(void) { ClrBit_SCK; Delay_us(1500); //大于1.44ms SetBit_SCK; } /** * @功能 退出睡眠模式 * @说明 保持SCK高电平后,SDA持续至少33ms低电平, * 在退出睡眠模式后需要间隔250ms(典型值)才输出数据。 * @参数 无 * @返回值 无 */ void Eixt_Sleep(void) { SetBit_SCK; SetBit_SDA; I2C_Delay(); ClrBit_SDA; Delay_ms(35); //大于33ms退出睡眠模式 SetBit_SDA; Delay_ms(260); //大于250ms开始输出数据 } /** * @功能 从RAM/EEPROM中读取一个字节数据 * @说明 从MLX90614中的指定地址读取一个字节数据,高位在前,低位在后 * @参数 ack_nack:主机应答信号 * @返回值 dat: 读取的数据 */ uint8_t I2C_ReadByte(uint8_t ack_nack) { uint8_t i=0; uint8_t dat=0; ClrBit_SCK; Delay_us(5); for(i=0;i<8;i++) { dat = dat<<1; ClrBit_SCK; Delay_us(5*N); SetBit_SCK; Delay_us(5*N); if(STA_SDA) { dat = dat | 0x01; $MLX90614.C } } ClrBit_SCK; Delay_us(3*N); if(!ack_nack) ClrBit_SDA; else SetBit_SDA; Delay_us(3*N); SetBit_SCK; Delay_us(4*N); ClrBit_SCK; Delay_us(4*N); //第8个时钟下降沿 //在第9个时钟上升沿,主机发送应答信号 //在第9个时钟上升沿,主机发送应答信号 return dat; } /** * @功能 向EEPROM写一个字节数据 * @说明 在写完一个字节后检测MLX6014是否发送了应答信号 * @参数 dat:需要发送的字节 * @返回值 s_ack:应答信号状态 */ uint8_t I2C_WriteByte(uint8_t dat) { uint8_t i=0; uint8_t s_ack=0; ClrBit_SCK; ClrBit_SDA; I2C_Delay(); for(i=0;i<8;i++) { ClrBit_SCK; Delay_us(3*N); if(dat&0x80) { SetBit_SDA; } else { ClrBit_SDA; } dat = dat<<1; Delay_us(4*N); SetBit_SCK; Delay_us(4*N); } //改变SDA状态 //SCK上升沿写入数据 ClrBit_SCK; //第8个下降沿开始,MLX90614将SDA置为低电平供主机检测是否正确接收 SetBit_SDA; Delay_us(2*N); SetBit_SCK; //第9个上升沿后,主机检测SDA状态 if(STA_SDA) //高电平表示正确接收数据 $MLX90614.C { s_ack = ACK_FAIL; } else { s_ack = ACK_SUCCESS; } Delay_us(2*N); ClrBit_SCK; Delay_us(4*N); return s_ack; } /** * @功能 读MLX90614的RAM中内容 * @说明 主要读取三个,环境温度,物体温度1,物体温度2 * 器件从地址可以通过向EEPROM的SMBus地址0x0E中写入来进行设定。 * @参数 saddr:从机地址,7位地址,任何MLX90614都会对0x00地址作出反应 * cmd:存放温度的寄存器地址 * @返回值 Data:读取出来的数值 */ uint16_t I2C_ReadRAM(uint8_t saddr,uint8_t cmd) { uint16_t uint8_t uint8_t Data; DataL; DataH; //接收数据低字节 //接收数据高字节 uint8_t uint8_t PEC; retry = 10; //失败重复次数 uint8_t uint8_t uint8_t s_ack = 0; Pecreg; buf[6]; //计算的PEC值 //存储已接收数据的缓存 ClrBit_SCK; 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); // $MLX90614.C // // 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); if(Pecreg == PEC) { break; } } else goto stop_rr; } else goto stop_rr; } else goto stop_rr; //调用计算 PEC 的函数 //退出循环 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; ClrBit_SCK; 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); 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; //发送低字节 //发送高字节 //发送PEC字节 //发送停止位 //退出循环 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 uint8_t uint8_t uint8_t uint8_t uint8_t Data; DataL; DataH; PEC; Pecreg; buf[6]; //接收数据低字节 //接收数据高字节 //接收的PEC值 //计算的PEC值 //存储已接收数据的缓存 while(retry--) { $MLX90614.C I2C_Start(); s_ack = I2C_WriteByte((saddr<<1)|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); if(s_ack == ACK_SUCCESS) { s_ack = 0; DataL = I2C_ReadByte(1); DataH = I2C_ReadByte(1); PEC = I2C_ReadByte(1); I2C_Stop(); //发送起始位 //发送从机地址和Wr位 //发送命令 //重新发送起始位 //发送从机地址和Rd位 //读数据低字节 //读数据高字节 //读数据PEC字节 //发送停止位 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); if(Pecreg == PEC) { break; } } else goto stop_re; } else goto stop_re; } else goto stop_re; //调用计算 PEC 的函数 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 uint8_t s_ack = 0; 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); ClrBit_SCK; while(retry--) { I2C_Start(); s_ack = I2C_WriteByte((saddr<<1)|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); 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; //发送起始位 //发送从机地址和Wr位 //发送命令 //发送低字节 //发送高字节 //发送PEC码 //发送停止位 //退出循环 stop_we: I2C_Stop(); } Delay_ms(5); } //写入之后等待5ms /** * @功能 * @说明 计算PEC包裹校验码,根据接收的字节计算PEC码 计算传入数据的PEC码 $MLX90614.C * @参数 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[4]=0; crc[3]=0; crc[2]=0; crc[1]=0x01; crc[0]=0x07; Bitposition=47; shift=0; //在传送的字节中找出第一个“1” //载入 CRC数值 0x000000000107 //设置Bitposition的最大值为47 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; } $MLX90614.C 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); }

Top_arrow
回到顶部
EEWORLD下载中心所有资源均来自网友分享,如有侵权,请发送举报邮件到客服邮箱bbs_service@eeworld.com.cn 或通过站内短信息或QQ:273568022联系管理员 高进,我们会尽快处理。