由于2020年疫情的影响,一堆制造商突然出现在中国。
硬件平台:nRF52832 JHM3000
JHM3000是单线通信体温传感器芯片,线性好,校准后精度可达0.1度。
主要问题是通信是单一的IO输出,芯片上电后,IO脉冲信号将不断输出,需要MCU计算脉宽来解码数据。
每个采样周期为:2.8ms间隔 6ms数据传输
相邻两个高脉宽之比决定数据类型,START=3:3,BIT0=5:1,BIT1=1:5 数据样本:91、3、3、1、6、1、5、1、5、1、5、1、5、1、5、6、1、1、5、5、2、1、5、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、5、1、5、5、1、5、5、1、5、5、1、5、5、1、5、5、5、1、5、5、1、5、5、1、5、5、1、5、5、5、5、1、5、5、5、1、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、1、5、1、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、... 每次采样一次START 14个BIT数据:S BBBBBBBBBBBBB
解码数据时,需要先找到START然后开始分析采样数据。
以下是主源代码:
/* * JHM3000 体温传感器驱动程序 * 每次采样2.8ms 数据传输6ms * 单线IO输出,相邻两个高脉宽比决定数据,START=3:3, BIT0=5:1, BIT1=1:5 * 数据样本:61、4、3、1、5、1、6、1、6、1、5、1、5、1、5、1、5、6、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、5、1、5、1、5、1、5、1、5、1、5、1、1、1、1、1、1、1、1、1、1、1、1、1、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、1、5、5、1、5、5、1、5、5、1、5、1、5、5、1、5、5、5、5、1、1、5、5、5、5、1、1、1、5、1、5、5、1、5、5、5、5、1、1、1、5、1、5、5、1、5、5、5、5、1、5、5、5、5、1、1、5、1、1、1、1、1、1、5、1、1、1、1、1、1、1、1、5、5、5、1、1、1、1、1、1、1、1、1、1、5、1、1、1、1、1、1、1、5、5、5、5、5、1、1、1、1、1、1、1、5、5、5、5、1、1、1、1、1、1、1、1、1、1、5、1、1、1、1、5、5、5、5、5、5、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、5、5、5、1、1、1、1、1、1、1、1、5、5、5、6、1、5、1、6、1、1、1、5、1、1、1、5、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、5、5、5、5、5、5、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、5、1、1、5、5、5、5、5、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、5、5、5、1、1、1、1、5、5、1、5、5、5、5、5、5、1、5、5、5、1、5、1、5、5、5、5、5、5、1、1、1、1、1、1、1、1、1、1、1、1、1、1、5、1、5、1、5、5、5、5、5、5、5、5、5、5、1、1、1、1、5、5、5、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、1、5、5、5、5、5、5、5、1、1、5、5、1、1、1、1、1、1、1、5、 * 91、3、1、6、1、5、1、5、1、5、1、5、1、5、1、6、1、5、1、5、5、5、1、5、5、5、1、5、5、1、5、5、1、5、5、1、5、1、5、1、5、1、5、1、5、1、5、5、5、1、5、5、5、5、5、1、5、5、5、1、5、5、1、5、5、1、5、5、1、5、5、1、5、1、5、1、5、1、5、1、5、5、1、5、5、1、5、1、5、1、5、1、5、5、1、5、5、1、5、1、5、1、5、5、5、5、5、5、5、5、5、1、5、5、1、5、5、1、5、5、1、5、5、1、5、5、1、5、5、1、5、1、5、1、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5、5 * 91,3,4,... * 每次采样一次START 14个BIT数据:S BBBBBBBBBBBBB * 蒋晓岗<kerndev@foxmail.com> * 2020.03.06 */ #include <stdint.h> #include <stdbool.h> #include "log.h" #include "bsp.h" #include "sdk.h" ///判断数据类型,错误返回0, 成功返回1,S位bit=-1,BIT10,BIT1返回1 static int decode_one_bit(uint32_t t1, uint32_t t2, int *bit) { uint32_t diff; if((t1 t2) > 10) { LOG("t1=%d, t2=%d\r\n", t1, t2); return 0; } if(t1 > t2) { diff = t1 - t2; if(diff > t2) { *bit = 0; return 1; } } if(t2 > t1) { diff = t2 - t1; if(diff > t1) { *bit = 1; return 1; } } *bit = -1; return 1; } //等待管脚电平跳变 static int wait_pin_state(int state, uint32_t timeout) { uint32_t diff; uint32_t tick; diff = 0; tick = app_timer_cnt_get(); timeout = timeout << 5; /1毫秒等于32小时 while(diff < timeout) { if(nrf_gpio_pin_read(HM3000_PIN_DATA) == state) { return 1; } else { app_timer_cnt_diff_compute(app_timer_cnt_get(), tick, &diff); } } return 0; } //计算高电平时长 static int calc_pulse_width(uint32_t *pw) { int ret; uint32_t diff; uint32_t tick; ret = wait_pin_state(1, 5); if(!ret) { return 0; } tick = app_timer_cnt_get(); ret = wait_pin_state(0, 5); if(!ret) { return 0; } app_timer_cnt_diff_compute(app_timer_cnt_get(), tick, &diff); *pw = diff; return 1; } //等待高电平结束 static int wait_for_idle(void) { return wait_pin_state(0, 5); } //等待ADC采样开始 //ADC采样有2.5ms高电平 static int wait_for_adc(void) { int i; int ret; uint32_t pw; for(i=0; i<32; i ) { ret = calc_pulse_width(&pw); if(!ret) { return 0; } if(pw > 30) { return 1; } } return 0; } //接收一个数据 static int recv_one_bit(int *bit) { int ret; uint32_t t1; uint32_t t2; ret = calc_pulse_width(&t1); if(!ret) { return 0; } ret = calc_pulse_width(&t2); if(!ret) { return 0; } return decode_one_bit(t1, t2, bit); } /// static int recv_start_bit(void) { int ret; int bit; ret = recv_one_bit(&bit); if(!ret) { return 0; } return bit == -1; } //接收采样数据 //数据=1位符号 13位数据 static int recv_adc_data(int *data) { int i; int bit; int ret; int16_t tmp; tmp = 0; for(i=0; i<14; i ) { ret = recv_one_bit(&bit); if(!ret) { LOG("drv_hm3000: recv bit%d failed!ret) { LOG("drv_hm3000: recv bit%d failed!\r\n", i); return 0; } if(bit < 0) { LOG("drv_hm3000: recv bit%d invalid!\r\n", i); return 0; } if(bit) { tmp |= 1 << (15 - i); } } //LOG("drv_hm3000: raw=%d\r\n", tmp); *data = tmp >> 2; return 1; } //采样数据 static int sample_data(int *data) { int ret; ret = wait_for_idle(); if(!ret) { LOG("drv_hm3000: wait idle timeout!ret) { LOG("drv_hm3000: wait idle timeout!\r\n"); return 0; } ret = wait_for_adc(); if(!ret) { LOG("drv_hm3000: wait adc timeout!\r\n"); return 0; } ret = recv_start_bit(); if(!ret) { LOG("drv_hm3000: recv start failed!\r\n"); return 0; } ret = recv_adc_data(data); if(!ret) { LOG("drv_hm3000: recv data failed!\r\n"); return 0; } return ret; } #if 0 //调试数据 static void dump_data(void) { int i; static uint32_t time[100]; for(i=0; i<64; i ) { calc_pulse_width(&time[i]); } for(i=0; i<64; i ) { LOG("%d,", time[i]); } LOG("\r\n"); } #endif //读取采样数据 int drv_hm3000_read(int *data) { //dump_data(); //return 0; int ret; //uint8_t sr; //sd_nvic_critical_region_enter(&sr); ret = sample_data(data); //sd_nvic_critical_region_exit(sr); return ret; } ///打开芯片电源 void drv_hm3000_enable(void) { nrf_gpio_pin_write(HM3000_PIN_PWR, 1); } //关闭芯片电源 void drv_hm3000_disable(void) { nrf_gpio_pin_write(HM3000_PIN_PWR, 0); } ///初始化驱动 void drv_hm3000_init(void) { nrf_gpio_cfg_output(HM3000_PIN_PWR); nrf_gpio_cfg_input(HM3000_PIN_DATA, NRF_GPIO_PIN_NOPULL); nrf_gpio_pin_write(HM3000_PIN_PWR, 0); }