我上个贴子发布了如何利用USB进行串口通信,
【树莓派Pico测评】- USB CDC串口通信(BSP编译,非MicroPython)
这次发布一个I2C的例子,刚好我手头上有MLX90614,市场上的手持红外测温的清一色的都是用的它
这个芯片我买了大概5-6年了,一直吃灰,刚好最近玩PICO时又从宝箱里翻出了它,刚好在这个疫情后时代用得上
程序基于我上次的程序进行修改,这里我只发出主程序
#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[3];
int r = 0;
//先写站号及命令码 nostop=false 写入后不发送i2c停止指令
//PICO_ERROR_TIMEOUT
r = i2c_write_timeout_us(I2C_PORT, MLX90614_ADDR, ®_addr, 1, true, 2000); //超时2ms
if (r < 1) {
return -1;
}
//再读数据 lsb,msb,pec
r = i2c_read_timeout_us(I2C_PORT, MLX90614_ADDR, &bf[0], 3, false, 2000);
if (r < 1) {
return -1;
}
MLX90614_value = bf[0] + (bf[1] << 8);
return r;
}
以主是主程序,程序比较简单,输出当前温度及芯片本体温度,参数及地址参照MLX90614手册进行就好了
编译主程序,并且复制程序
硬件链接图:
运行效果展示
从上图中可以看出,室温/芯片温度约16度左右,基本正常,手摸一下温度会慢慢升高
目标物体温度,无物体时约15.61度,差不多室温,手腕放主去,2秒后升到33度左右,
和公司的每天早上量体温的机器基本一致,至于为什么不是36,37度我也不知道,应该是出厂就校准过的啊,不应该差这么多吧?可能是一些参数还需要配置,比如测量温度上下限等,有空了再试试。
等节后了加工一个PCB,再找个漂亮的盒子,再搞个小屏,这样就是一个成品模块了。
这芯片买的时候180,现在估计卖300也能卖出去,哈,增值啊。
不该2019年底的时候把 MLX90640,如果这个没卖玩起来更爽。32*24像素的红外相机啊!
再列个网址 https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__i2c.html
这个网址是关于I2C的SDK API说明,当然其它API这里也有看到介绍
https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware.html