【树莓派Pico测评】-制作红外体温计( I2C接口测试+MLX90614)
<div class='showpostmsg'> 本帖最后由 fxyc87 于 2021-2-7 16:46 编辑<p>我上个贴子发布了如何利用USB进行串口通信,</p>
<p><a href="https://bbs.eeworld.com.cn/thread-1156658-1-1.html" target="_blank" title="【树莓派Pico测评】- USB CDC串口通信(BSP编译,非MicroPython)">【树莓派Pico测评】- USB CDC串口通信(BSP编译,非MicroPython)</a></p>
<p>这次发布一个I2C的例子,刚好我手头上有MLX90614,市场上的手持红外测温的清一色的都是用的它</p>
<p>这个芯片我买了大概5-6年了,一直吃灰,刚好最近玩PICO时又从宝箱里翻出了它,刚好在这个疫情后时代用得上</p>
<p>程序基于我上次的程序进行修改,这里我只发出主程序</p>
<pre>
<code class="language-cpp">#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/stdio_usb.h"
#include "hardware/i2c.h"
// I2C 声明
#define I2C_PORT i2c0
#define I2C_SDA 0
#define I2C_SCL 1
//MLX90614 声明
#define MLX90614_ADDR 0x5a //地址
#define CMD_RAM(n)(0|n)
#define CMD_EEPROM(n) (32|n) //001x xxxx* EEPROM Access
#define CMD_FLAG(n) (0xf0) //1111_0000** Read Flags
#define CMD_SLEEP(n) (0xff) //1111_1111 Enter SLEEP mode
//led 声明
#define LED 25
//usb 声明
//函数申明
int ReadData(uint8_t reg_addr); //
//变量申明
uint16_t MLX90614_value; //读取的16位原始结果
int main()
{
//USB初始化
stdio_usb_init();
//LED初始化
gpio_init(LED);
gpio_set_dir(LED,GPIO_OUT);
gpio_put(LED,1);
//LED闪烁提示
sleep_ms(5000);
for(int i=0;i<10;i++){
sleep_ms(100);
gpio_put(LED,0);
sleep_ms(100);
gpio_put(LED,1);
}
//MLX90614切换到I2C模式,SCL至少低电平 1.44ms
gpio_set_function(I2C_SCL, GPIO_FUNC_SIO);
gpio_set_dir(I2C_SCL, GPIO_OUT);
gpio_put(I2C_SCL, 0);
sleep_ms(5);
gpio_put(I2C_SCL, 1);
sleep_ms(30);
// I2C 50Khz.
i2c_init(I2C_PORT, 50*1000);
gpio_set_function(I2C_SDA, GPIO_FUNC_I2C);
gpio_set_function(I2C_SCL, GPIO_FUNC_I2C);
gpio_pull_up(I2C_SDA);
gpio_pull_up(I2C_SCL);
/*MLX90614 RAM地址
ta本体温度, 6
温度1 7
温度2 8
*/
/*MLX90614 EEPROM地址
Tomax 0x00 Yes
Tomin 0x01 Yes
PWMCTRL 0x02 Yes
Ta range 0x03 Yes
Emissivity 0x04 Yes
Config Register1 0x05 Yes
SMBus address (LSByte only) 0x0E Yes
*/
//读取EEPROM配置数据
float max, min;
int r= ReadData(CMD_EEPROM(0));
if (r < 3) {
printf("读取配置失败\n");
while (1);
}
printf("dat:%d\n", MLX90614_value);
max = MLX90614_value / 100.0f - 273.15f;
printf("Tomax:%f\n", max);
r = ReadData(CMD_EEPROM(1));
if (r < 3) {
printf("读取RAM失败\n");
while (1);
}
printf("dat:%d\n", MLX90614_value);
min = MLX90614_value / 100.0f - 273.15f;
printf("Tomax:%f\n", min);
while(1){
//本体温度
float temp1,temp2;
int r;
r = ReadData(CMD_RAM(6));
if (r < 3) {
printf("读取温度6失败\n");
while (1);
}
temp1 = MLX90614_value * 0.02f-273.15;
r = ReadData(CMD_RAM(7));
if (r < 3) {
printf("读取温度7失败\n");
while (1);
}
temp2 = MLX90614_value * 0.02f - 273.15;
printf("temp:%3.2f,%3.2f\t@eeworld.fxyc87\n", temp1,temp2);
//打印出读的数据
gpio_put(LED, 1);
sleep_ms(500);
gpio_put(LED, 0);
sleep_ms(500);
}
return 0;
}
/*
读取MLX90614寄存器数据
reg_addr 地址有 CMD_RAM(a),CMD_EEPROM(a),CMD_FLAG(a),CMD_SLEEP(a)
读取成功,返回数据长度
失败:-1
*/
int ReadData(uint8_t reg_addr) { //
uint8_t bf;
int r = 0;
//先写站号及命令码 nostop=false 写入后不发送i2c停止指令
//PICO_ERROR_TIMEOUT
r = i2c_write_timeout_us(I2C_PORT, MLX90614_ADDR, &reg_addr, 1, true, 2000); //超时2ms
if (r < 1) {
return -1;
}
//再读数据 lsb,msb,pec
r = i2c_read_timeout_us(I2C_PORT, MLX90614_ADDR, &bf, 3, false, 2000);
if (r < 1) {
return -1;
}
MLX90614_value = bf + (bf << 8);
return r;
}</code></pre>
<p>以主是主程序,程序比较简单,输出当前温度及芯片本体温度,参数及地址参照MLX90614手册进行就好了</p>
<p></p>
<p> </p>
<p>编译主程序,并且复制程序</p>
<p></p>
<p>硬件链接图:</p>
<p></p>
<p>运行效果展示</p>
<p></p>
<p>从上图中可以看出,室温/芯片温度约16度左右,基本正常,手摸一下温度会慢慢升高</p>
<p>目标物体温度,无物体时约15.61度,差不多室温,手腕放主去,2秒后升到33度左右,</p>
<p>和公司的每天早上量体温的机器基本一致,至于为什么不是36,37度我也不知道,应该是出厂就校准过的啊,不应该差这么多吧?可能是一些参数还需要配置,比如测量温度上下限等,有空了再试试。</p>
<p>等节后了加工一个PCB,再找个漂亮的盒子,再搞个小屏,这样就是一个成品模块了。</p>
<p>这芯片买的时候180,现在估计卖300也能卖出去,哈,增值啊。</p>
<p>不该2019年底的时候把 MLX90640,如果这个没卖玩起来更爽。32*24像素的红外相机啊!</p>
<p> </p>
<p>再列个网址 https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__i2c.html</p>
<p>这个网址是关于I2C的SDK API说明,当然其它API这里也有看到介绍</p>
<p>https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware.html</p>
<p> </p>
<p>**** Hidden Message *****</p>
</div><script> var loginstr = '<div class="locked">查看精华帖全部内容,请<a href="javascript:;" style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
if(parseInt(discuz_uid)==0){
(function($){
var postHeight = getTextHeight(400);
$(".showpostmsg").html($(".showpostmsg").html());
$(".showpostmsg").after(loginstr);
$(".showpostmsg").css({height:postHeight,overflow:"hidden"});
})(jQuery);
}
</script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script> <p></p>
<p>硬件链接</p>
<p>SDA接P00,</p>
<p>SCL接P01</p>
赞赞赞赞,期待成品。这个灵敏度怎么样 annysky2012 发表于 2021-2-8 09:30
赞赞赞赞,期待成品。这个灵敏度怎么样
<p>MLX90614有好几个子系列,</p>
<p>5V的,3V的,还有角度</p>
<p>有90度视野的,有30度,有10度的,</p>
<p>还有温度有+-1度,+-0.5度的,+-0.1度的,好几个级别呢,</p>
<p>我这个是最普通的,</p>
<p>国产的测温计很多卖20块钱,不知道用的 那个测温芯片,速度快,但是不准</p>
<p>1.用614测温应该使用医疗级别的型号,而不是工业级别的型号</p>
<p>2.测体表温度与实际值偏差大,是因为你缺少一个值换算的经验公式~</p>
joeymm 发表于 2021-2-9 10:57
1.用614测温应该使用医疗级别的型号,而不是工业级别的型号
2.测体表温度与实际值偏差大,是因为你缺少 ...
<p>对,实际上就是校准</p>
<p>不用转换模块,直接串口UART通讯的数字红外温度传感器,硬件上还与MLX90614 pin to pin</p>
<p> </p>
页:
[1]