了解更多开源请访问:开源基础软件社区https://ost.51cto.com前言最近我的一个项目需要用到红外温度传感器,所以就想能不能在Hi3861上开发这个外设。经过一段时间的摸索,最终还是简单的开启了红外温度传感器,后面会补充传感器的使用。本次使用的开发板:HiSpark_WiFi_IoT。红外线温度传感器介绍红外线温度传感器应用广泛。可用于疫情期间体温测量,可用于汽车空调控制和防雾应用,可用于家庭家电温度控制等。MLX90614是一款红外非接触式温度计(以下简称gy906)。红外感应热电堆探测器芯片和信号处理专用集成芯片集成在TO-39金属封装中。用于阻挡可见光和近红外辐射(传输长波长)的滤光片集成在封装内,以提供对环境和阳光的免疫力。需要注意的是,封装内部的温差会影响温度计测量的准确性,需要尽可能将传感器与环境隔离。协议查阅文档,发现红外温度传感器采用SMBus通信协议或PWM(默认SMBus输出格式)。SMBus协议要求IO口设置为开漏输出,Hi3861的IO口模式选择没有发现开漏。输出选项,暂时不要选择SMBus协议。摸索了半天,才知道SMbus规范是从I2C简化过来的。两条信号线是SMBCLK和SMBDATA。这与I2C上的时钟(SCL)和数据(SDA)相同。SMBus的读数据格式与I2C协议几乎相同,区别仅在于电平的确定。虽然两个协议的级别确定不同,但也有一些重叠。I2C协议中有两个级别的标识:相对标识和绝对标识。相对标识是根据Vdd的电压来确定的。高电平为0.7Vdd,低电平低于0.3Vdd。再看一下红外温度传感器上的SMBus协议(如下图),高电平需要高于Vdd-0.1,与I2C协议一致。低电平最大只能是0.6V,这里只能希望Hi3861的I2C能把低电平拉到0.6V以下。不过巧合的是,验证过Hi3861是可以用的!这次要用到的MLX90614BCC版本,这个型号的电源是3V的,注意不要插到5V的电源上。!接线:VIN->3V3,GND->GND,SLK->SLK,SDA->SDA。既然已经使用了I2C,那么就要知道设备的地址了。找了半天,发现这个设置的默认地址是0X00或者0XB4,其中0x00在接单个I2C设备时默认是可以访问的。并且修改EEPROM可以修改I2C地址。如果不小心修改了地址忘记了地址,可以单独插上sensor读取0X0E的值得到设备的地址。传感器将温度数据存放在RAM中的Tojb1中,Tobj1在ram中的地址为0x07,则读取温度的命令为0x07,向设备发送0x07,即可读取温度数据。代码写IO口初始化老步骤,第一步是初始化IO口。流程:GPIO口初始化(GPIO口在开发板背面标注:13,14)。IO口复用成I2C。初始化I2C端口(I2C端口可以从hi_io.h中的GPIO端口引脚函数列表中得知)。#defineGPIO_SDA13#defineGPIO_SCL14#defineGY906_I2C0voidgy906_init(void){IoTGpioInit(GPIO_SDA);IoTGpioInit(GPIO_SCL);hi_io_set_func(GPIO_SDA,HI_IO_FUNC_GPIO_13_I2C0_SDA);hi_io_set_func(GPIO_SCL,HI_IO_FUNC_GPIO_14_I2C0_SCL);hi_i2c_init(GY906_I2C,400000);}主函数和线程查询相关文档,gy906反馈信息有三个,第一个是低位数据,第二个是高位数据,第三个是校验位。将高位数据和低位数据拼接在一起,然后通过公式计算得到温度数据。流程:初始化I2c传输数据。接收传感器反馈的数据。判断数据的正确性。通过数据拼接计算得到温度数据。#defineGY906_I2C0#defineGY906_addr0x00//0x00or0xB4//获取温度值voidgy906_get(void){hi_i2c_datagy_data={0};//I2C数据结构uint8_trecv_data[3]={0};//接收数据缓存uint8_tsend_data[1]={0x07};//读取温度的指令//初始化gy_datagy_data.send_buf=send_data;gy_data.send_len=1;gy_data.receive_buf=recv_data;gy_data.receive_len=3;//I2C读写操作hi_i2c_writeread(GY906_I2C,(GY906_addr<<1)|0x01,&gy_data);//进行奇偶判断uint8_taddr[6]={0,0,0,0x01,0x07,0x00};地址[1]=recv_data[1];//高位addr[2]=recv_data[0];//低位uint8_tPY_CRC1=PEC_Calculation(addr);//如果校验位正确if(PY_CRC1==recv_data[2]){printf("温度正确!\n");}//如果校验位错误,返回所有值else{printf("temperaturefalse!\n");printf("recv_data:low:%xhigh:%xCRC:%x\n",recv_data[0],recv_data[1],recv_data[2]);printf("CRC1:%x\n",PY_CRC1);}//打印温度T=(DataH:DataL)*0.02-273.15floattemperature_f=(((float)((recv_data[1]<<8)|recv_data[0]))*2-27315)/100;printf("temperature:%.2f\n",temperature_f);}//主函数voidgy906_demo(void){//IO口初始化gy906_init();while(1){gy906_get();睡觉(1);}}//线程创建voidgy_demo(void){osThreadAttr_tattr;attr.name="gy_demo";属性.attr_bits=0U;属性.cb_mem=NULL;属性.cb_size=0U;属性.stack_mem=NULL;attr.stack_size=10240;属性优先级=25;if(osThreadNew((osThreadFunc_t)gy906_demo,NULL,&attr)==NULL){printf("[gy_demo]创建gy_demo失败!\n");}}SYS_RUN(gy_demo);验证算法algorithm代码如下(部分介绍标注在注释中:uint8_tPEC_Calculation(uint8_tpec[]){uint8_tcrc[6];//storepolynomialuint8_tBitPosition=47;//storethehighest所有数据的位,6*8=48最高位为47位uint8_tshift;uint8_ti;uint8_tj;uint8_ttemp;do{/*Initialize0x000000000107*/crc[5]=0;crc[4]=0;crc[3]=0;crc[2]=0;crc[1]=0x01;crc[0]=0x07;//设置最大位位为47,记录位位BitPosition=47;/*设置移位位置为0*/shift=0;/*从pec[5]开始寻找传输报文中的第一个“1”*/i=5;j=0;//0x80->10000000,逐位找到第一个“1”while((pec[i]&(0x80>>j))==0&&i>0){//位位置-1BitPosition--;如果(j<7){j++;}否则{j=0x00;我-;}}/*while结束*//*记录位位置*/shift=BitPosition-8;/*校验操作*///循环次数为:shiftwhile(shift){for(i=5;i<0xFF;i--)//i<0xff表示i>0,遍历crc数组{//以下操作是将一个八位数据整体左移,将最高位移到最低位,例:10011000->00110001if((crc[i-1]&0x80)&&(i>0)){项目p=1;}否则{温度=0;}crc[i]<<=1;//向左移动一位crc[i]+=temp;}/*for结束*/shift--;}/*Endofwhile*///设置已经操作的位置为0for(i=0;i<=5;i++){pec[i]^=crc[i];}/*for结束*/}while(BitPosition>8);/*循环操作*/returnpec[0];}编译脚本BUILD.gnstatic_library("my_gy906_demo"){sources=["gy906.c",]include_dirs=["//utils/native/lite/include","//kernel/liteos_m/components/cmsis/2.0","//base/iot_hardware/peripheral/interfaces/kits","//device/soc/hisilicon/hi3861v100/sdk_liteos/include",]}可以点击链接下面下载效果文章相关附件:https://ost.51cto.com/resource/2302了解更多开源内容请访问:开源基础软件社区https://ost.51cto.com.
