一、背景
有幸参加rt-thread的活动,体验rt-thread studio 和瑞萨 cpk-ra2l1评估板。本篇结合前面的文章,暂时制作一个空气质量监测系统,主要使用:dht11、pms1003, oled模块, 后续继续扩展甲醛,co2, iaq模块
二、模块信息
三、新建工程
这里使用的模块,我们需要提前分配好引脚:uart0 采集pms1003, dht11 使用p0208 引脚, oled i2c1通信 使用p0205 p0206,
配置rt-thread settings ,添加u8g2 库,配置i2c,具体信息如下图
在 ra smart configurator 种添加uart0,配置好引脚和波特率
在 ra smart configurator 种添加i2c1
四、编写代码
hal_entery.c
/*
copyright (c) 2006-2021, rt-thread development teamspdx-license-identifier: apache-2.0change logs:date author notes2021-10-10 sherman first version
/
#include
#include hal_data.h
#include
#include dht11.h
#include
#include pms1003.h
#include
#include
#include
//#define dbg_enable
//#define dbg_section_name pms_series
//#define dbg_level dbg_log
//#define dbg_color
//#define dbg_enable
#define led1_pin p502 / onboard led pins /
#define user_input p004
/ ******* dht11 /
#define data_pin 0x0208 //p208 dht11
#define thread_priority 5
#define thread_stack_size 1024
#define thread_timeslice 10
static rt_thread_t tid_dht11 = rt_null;
/ pms1003 /
//tx p101 rx p100
#define pms_series_uart uart0
#ifdef pms_series_sample_using_dma
struct rt_messagequeue pms_mq;
#else
struct rt_semaphore pms_sem;
#endif
pms_device_t pms1003;
struct rx_msg
{
rt_device_t dev;
rt_size_t size;
};
/ oled /
static rt_thread_t tid_oled = rt_null;
int temp = 0;
int humi = 0;
int pm2_5 = 0;
int pm10 = 0;
static void dht11threadentry(void *parameter)
{
dht_device_t sensor = dht_create(data_pin);
rt_int32_t temp_;
rt_int32_t humi_;
while (1)
{
if(dht_read(sensor))
{
temp_ = dht_get_temperature(sensor) / 10;
humi_ = dht_get_humidity(sensor) / 10;
temp = temp_;
humi = humi_;
// rt_kprintf(temp: %d, humi: %dn, temp, humi);
}
else
{
// rt_kprintf(read dht sensor failed.n);
}
rt_thread_mdelay(500);
}
dht_delete(sensor);
}
int dht11_init()
{
rt_err_t ret = rt_eok;
tid_dht11 = rt_thread_create(dht11,
dht11threadentry,
rt_null,
thread_stack_size,
thread_priority,
thread_timeslice);
if (tid_dht11 != rt_null)
{
rt_thread_startup(tid_dht11);
}
else
{
ret = rt_error;
}
return ret;
}
//init_app_export(dht11_init);
void pms_series_debug(pms_device_t dev)
{
rt_kprintf(beginn);
rt_kprintf(pm1_0_cf1 = %5dtpm2_5_cf1 = %5dtpm10_0_cf1 = %5dn,dev->pm1_0_cf1,dev->pm2_5_cf1,dev->pm10_0_cf1);
rt_kprintf(pm1_0_amb = %5dtpm2_5_amb = %5dtpm10_0_amb = %5dn,dev->pm1_0_amb,dev->pm2_5_amb,dev->pm10_0_amb);
rt_kprintf(air_0_3um = %5dtair_0_5um = %5dtair_1_0um = %5dn,dev->air_0_3um,dev->air_0_5um,dev->air_1_0um);
rt_kprintf(air_2_5um = %5dt,dev->air_2_5um);
rt_kprintf(version = %5d errorcode = %5dn,dev->version,dev->errorcode);
rt_kprintf(********************************over****************************n);
}
static void serial_thread_entry(void *parameter)
{
#ifndef pms_series_sample_using_dma
rt_err_t result;
char ch;
pms_device_t dev = parameter;
while (1)
{
while (rt_device_read(dev->serial, 0, &ch, 1) == 0)
{
rt_sem_control(&pms_sem, rt_ipc_cmd_reset, rt_null);
rt_sem_take(&pms_sem, rt_waiting_forever);
}
result = pms_get_byte(dev,ch);
if (result == rt_eok)
{
// pms_series_debug(dev); // for debug
pm2_5 = dev->pm2_5_cf1;
pm10 = dev->pm10_0_cf1;
// rt_kprintf(air_2_5um = %dn,pm2_5);
}
}
#endif
#ifdef pms_series_sample_using_dma
struct rx_msg msg;
rt_err_t result;
rt_uint32_t rx_length;
static rt_uint8_t rx_buffer[rt_serial_rb_bufsz + 1];
pms_device_t dev = parameter;
while (1)
{
rt_memset(&msg, 0, sizeof(msg));
result = rt_mq_recv(&pms_mq, &msg, sizeof(msg), rt_waiting_forever);
if (result == rt_eok)
{
rx_length = rt_device_read(msg.dev, 0, rx_buffer, msg.size);
rx_buffer[rx_length] = '�';
result = frame_check(dev,rx_buffer,rx_length);
if (result == rt_eok)
{
pms_series_debug(dev);
rt_kprintf(rx buff success);
}
else
{
rt_kprintf(rx buff error);
}
}
}
#endif
}
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
rt_assert(dev);
#ifndef pms_series_sample_using_dma
if (size > 0)
{
rt_sem_release(&pms_sem);
}
return rt_eok;
#endif
#ifdef pms_series_sample_using_dma
rt_err_t result;
struct rx_msg msg;
msg.dev = dev;
msg.size = size;
result = rt_mq_send(&pms_mq, &msg, sizeof(msg));
if ( result == -rt_efull)
{
rt_kprintf(message queue full!n);
}
return result;
#endif
}
int pms1003init()
{
static pms_device_t dev = null;
rt_err_t ret = rt_eok;
dev = pms_init(pms_series_uart);
#ifndef pms_series_sample_using_dma
rt_sem_init(&pms_sem, pms_sem, 0, rt_ipc_flag_fifo);
rt_device_open(dev->serial, rt_device_flag_int_rx);
rt_device_set_rx_indicate(dev->serial, uart_input);
#endif
#ifdef pms_series_sample_using_dma
static char msg_pool[256];
rt_err_t result;
result = rt_mq_init(&pms_mq, pms_mq,
msg_pool,
sizeof(struct rx_msg),
sizeof(msg_pool),
rt_ipc_flag_fifo);
if (result != rt_eok)
{
rt_kprintf(init message queue failed.n);
}
result = rt_device_open(dev->serial, rt_device_flag_dma_rx);
if (result != rt_eok)
{
rt_kprintf(open device failed.n);
}
result = rt_device_set_rx_indicate(dev->serial, uart_input);
if (result != rt_eok)
{
rt_kprintf(set rx indicate failed.n);
}
#endif
rt_thread_t thread = rt_thread_create(pms1003, serial_thread_entry, dev, 1024, 3, 10);
if (thread != rt_null)
{
rt_thread_startup(thread);
}
else
{
ret = rt_error;
}
return ret;
}
//init_app_export(pms1003init);
char tmp_buff[18]={'�'};
char pm_buff[16]={'�'};
char pm10_buff[16]={'�'};
static int f_clean = 0;
static void oledthreadentry(void *parameter)
{
u8g2_t u8g2;
u8g2_setup_ssd1306_i2c_128x64_noname_f( &u8g2, u8g2_r0, u8x8_byte_rtthread_hw_i2c, u8x8_gpio_and_delay_rtthread);
u8g2_initdisplay(&u8g2);
u8g2_setpowersave(&u8g2, 0);//是否开启省电模式 , 1 表示启用显示器的省电模式,屏幕上看不到任何东西, 0 表示禁用省电模式
u8g2_clearbuffer(&u8g2);
u8g2_setfont(&u8g2, u8g2_font_unifont_t_arabic); //u8g2_font_ncenb08_tr u8g2_font_unifont_t_symbols
while (1)
{
sprintf(tmp_buff, temp:%dt humi:%dt, temp, humi);
sprintf(pm_buff, pm2.5:%d, pm2_5);
sprintf(pm10_buff, pm10:%d, pm10);
rt_thread_mdelay(300);
if (1 == f_clean)
{
u8g2_clearbuffer(&u8g2);
}
else if (50 == f_clean)
{
u8g2_clearbuffer(&u8g2);
f_clean = 0;
}
u8g2_drawstr(&u8g2, 1, 10, &tmp_buff);
u8g2_sendbuffer(&u8g2);
u8g2_drawstr(&u8g2, 1, 30, &pm_buff);
u8g2_sendbuffer(&u8g2);
u8g2_drawstr(&u8g2, 1, 50, &pm10_buff);
u8g2_sendbuffer(&u8g2);
rt_kprintf(f_clean:%d n,f_clean++);
}
}
int oled_init()
{
rt_err_t ret = rt_eok;
tid_oled = rt_thread_create(oled,
oledthreadentry,
rt_null,
1024,
2,
thread_timeslice);
if (tid_oled != rt_null)
{
rt_thread_startup(tid_oled);
}
else
{
ret = rt_error;
}
return ret;
}
//init_app_export(oled_init);
void hal_entry(void)
{
rt_kprintf(nhello rt-thread!n);
rt_uint32_t led1_pin = rt_pin_get(led1_pin);
dht11_init();
pms1003init();
oled_init();
while (1)
{
rt_pin_write(led1_pin, pin_high);
rt_thread_mdelay(500);
rt_pin_write(led1_pin, pin_low);
rt_thread_mdelay(500);
}
}
void irq_callback_test(void *args)
{
rt_kprintf(n irq03 triggered n);
}
void icu_sample(void)
{
/* init */
rt_uint32_t pin = rt_pin_get(user_input);
rt_kprintf(n pin number : 0x%04x n, pin);
rt_err_t err = rt_pin_attach_irq(pin, pin_irq_mode_rising, irq_callback_test, rt_null);
if (rt_eok != err)
{
rt_kprintf(n attach irq failed. n);
}
err = rt_pin_irq_enable(pin, pin_irq_enable);
if (rt_eok != err)
{
rt_kprintf(n enable irq failed. n);
}
}
msh_cmd_export(icu_sample, icu sample);
dht11.c/*
copyright (c) 2006-2021, rt-thread development teamspdx-license-identifier: apache-2.0change logs:date author notes2023-03-08 dyc the first version
/
#include dht11.h
#include
#include hal_data.h
#include
#define dbg_tag sensor.asair.dhtxx
#ifdef pkg_using_dhtxx_debug
#define dbg_lvl dbg_log
#else
#define dbg_lvl dbg_error
#endif
#include
/ timing /
#define dht1x_begin_time 20 / ms /
#define dht2x_begin_time 1 / ms /
#define dhtxx_pull_time 30 / us /
#define dhtxx_reply_time 100 / us /
#define measure_time 40 / us /
rt_weak void rt_hw_us_delay(rt_uint32_t us)
{
rt_uint32_t delta;
us = us * (systick->load / (1000000 / rt_tick_per_second));
delta = systick->val;
while (delta - systick->val < us) continue;
}
/ *this function will split a number into two part according to times.@param num the number will be split@param integer the integer part@param decimal the decimal part@param times how many times of the real number (you should use 10 in this case)@return 0 if num is positive, 1 if num is negative
*/
int split_int(const int num, int *integer, int *decimal, const rt_uint32_t times)
{
int flag = 0;
if (num < 0) flag = 1;
int anum = num<0 ? -num : num;
integer = anum / times;
decimal = anum % times;
return flag;
}
/this function will convert temperature in degree celsius to kelvin.@param c the temperature indicated by degree celsius@return the result
/
float convert_c2k(float c)
{
return c + 273.15;
}
/ *this function will convert temperature in degree celsius to fahrenheit.@param c the temperature indicated by degree celsius@return the result
/
float convert_c2f(float c)
{
return c * 1.8 + 32;
}
/ *this function will convert temperature in degree fahrenheit to celsius.@param f the temperature indicated by degree fahrenheit@return the result
/
float convert_f2c(float f)
{
return (f - 32) * 0.55555;
}
/ *this function will read a bit from sensor.@param pin the pin of dout@return the bit value
/
static uint8_t dht_read_bit(const rt_base_t pin)
{
uint8_t retry = 0;
while(rt_pin_read(pin) && retry < dhtxx_reply_time)
{
retry++;
rt_hw_us_delay(1);
}
retry = 0;
while(!rt_pin_read(pin) && retry < dhtxx_reply_time)
{
retry++;
rt_hw_us_delay(1);
}
rt_hw_us_delay(measure_time);
return rt_pin_read(pin);
}
/ *this function will read a byte from sensor.@param pin the pin of dout@return the byte
*/
static uint8_t dht_read_byte(const rt_base_t pin)
{
uint8_t i, byte = 0;
for(i=0; i<8; i++)
{
byte
/ mcu request sampling /
rt_pin_mode(dev->pin, pin_mode_output);
rt_pin_write(dev->pin, pin_low);
if (dev->type == dht11) {
rt_thread_mdelay(dht1x_begin_time); / tbe /
} else {
rt_thread_mdelay(dht2x_begin_time);
}
#ifdef pkg_using_dhtxx_interrupt_disable
level = rt_hw_interrupt_disable();
#endif
rt_pin_mode(dev->pin, pin_mode_input_pullup);
rt_hw_us_delay(dhtxx_pull_time); / tgo /
/ waiting for sensor reply /
while (rt_pin_read(dev->pin) && retry = dhtxx_reply_time) return rt_false;
retry = 0;
while (!rt_pin_read(dev->pin) && retry = dhtxx_reply_time) return rt_false;
/ read data /
for(i=0; i {
dev->data[i] = dht_read_byte(dev->pin);
}
#ifdef pkg_using_dhtxx_interrupt_disable
rt_hw_interrupt_enable(level);
#endif
/ checksum */
for(i=0; i {
sum += dev->data[i];
}
if(sum != dev->data[4]) return rt_false;
return rt_true;
}
/**this function will get the humidity from dhtxx sensor.@param dev the device to be operated@return the humidity value
/
rt_int32_t dht_get_humidity(dht_device_t const dev)
{
rt_assert(dev);
rt_int32_t humi = 0;
switch(dev->type)
{
case dht11:
humi = dev->data[0] * 10 + dev->data[1];
break;
default:
break;
}
return humi;
}
/ *this function will get the temperature from dhtxx sensor.@param dev the device to be operated@return the temperature value
/
rt_int32_t dht_get_temperature(dht_device_t const dev)
{
rt_assert(dev);
rt_int32_t temp = 0;
switch(dev->type)
{
case dht11:
temp = dev->data[2] * 10 + (dev->data[3] & 0x7f);
if(dev->data[3] & 0x80) {
temp = -temp;
}
break;
default:
break;
}
return temp;
}
/ *this function will init dhtxx sensor device.@param dev the device to init@param pin the pin of dout@return the device handler
*/
rt_err_t dht_init(struct dht_device *dev, const rt_base_t pin)
{
if(dev == null)
return -rt_error;
dev->type = dht_type;
dev->pin = pin;
rt_memset(dev->data, 0, dht_data_size);
rt_pin_mode(dev->pin, pin_mode_input_pullup);
return rt_eok;
}
// 1、初始化类型
dht_device_t dht_create(const rt_base_t pin)
{
dht_device_t dev;
dev = rt_calloc(1, sizeof(struct dht_device));
if (dev == rt_null)
{
log_e(can't allocate memory for dhtxx device);
return rt_null;
}
dev->type = dht_type;
dev->pin = pin;
rt_memset(dev->data, 0, dht_data_size);
rt_pin_mode(dev->pin, pin_mode_input_pullup);
return dev;
}
void dht_delete(dht_device_t dev)
{
if (dev)
rt_free(dev);
}
dht11.h/*
copyright (c) 2006-2021, rt-thread development teamspdx-license-identifier: apache-2.0change logs:date author notes2023-03-08 dyc the first version
/
#ifndef src_dht11_h_
#define src_dht11_h_
#include
#include
#include
#include
#include
#define dhtlib_version 0.9.0
#define dht_data_size 5
/ sensor model type */
#define dht11 0
#define dht_type dht11
struct dht_device
{
rt_base_t pin;
rt_uint8_t type;
rt_uint8_t data[dht_data_size];
rt_mutex_t lock;
};
typedef struct dht_device *dht_device_t;
dht_device_t dht_create(const rt_base_t pin);
void dht_delete(dht_device_t dev);
rt_err_t dht_init(struct dht_device *dev, const rt_base_t pin);
rt_bool_t dht_read(dht_device_t dev);
rt_int32_t dht_get_humidity(dht_device_t dev);
rt_int32_t dht_get_temperature(dht_device_t dev);
float convert_c2k(float c);//将摄氏温度转为开氏温度
float convert_c2f(float c);//将摄氏温度转为华氏温度
float convert_f2c(float f);//将华氏温度转为摄氏温度
rt_int32_t split_int(const rt_int32_t num, rt_int32_t *integer,
rt_int32_t *decimal, const rt_uint32_t times);
rt_err_t rt_hw_dht_init(const char *name, struct rt_sensor_config cfg);
#endif / src_dht11_h_ */
pms1003.c/*
copyright (c) 2006-2021, rt-thread development team
spdx-license-identifier: apache-2.0
change logs:
date author notes
2023-03-08 dyc the first version
*/
//#define dbg_section_name pms_series
//#define dbg_level dbg_log
//#define dbg_color
#include
#include
#include pms1003.h
#define rt_serial_rb_bufsz 64
#define comm_start1 0x42
#define comm_start2 0x4d
#define frame_head1 0x00
#define frame_head2 0x01
#define frame_lenh 0x02
#define frame_lenl 0x03
#define frame_receive 0x04
#define frame_check 0x05
rt_err_t frame_check(pms_device_t dev,rt_uint8_t *buf,rt_uint16_t len)
{
rt_uint16_t sum=0;
rt_assert(dev);
for(uint8_t i=0;i> 8)))
{
dev->pm1_0_cf1 = ((rt_uint16_t)(buf[4]) return rt_eok;
}
return rt_error;
}
rt_err_t pms_get_byte(pms_device_t dev, char data)
{
rt_err_t result;
static uint8_t state = frame_head1;
static uint8_t cnt = 0;
static rt_uint8_t buf[40] = {0};
rt_assert(dev);
if(state == frame_head1 && data == comm_start1)
{
buf[cnt++] = data;
state = frame_head2;
}
else if (state == frame_head2 && data == comm_start2)
{
buf[cnt++] = data;
state = frame_lenh;
}
else if (state == frame_lenh)
{
buf[cnt++] = data;
state = frame_lenl;
}
else if (state == frame_lenl)
{
buf[cnt++] = data;
state = frame_receive;
}
else if (state == frame_receive)
{
buf[cnt++] = data;
if(cnt >= comm_len - 1)
state = frame_check;
}
else if (state == frame_check)
{
buf[cnt++] = data;
state = frame_head1;
cnt = 0;
result = frame_check(dev, buf, comm_len);
if (result == rt_eok)
{
log_d(check success);
return result;
}
else
{
log_e(check error);
}
}
else {}
return result;
}
pms_device_t pms_init(const char *uart_name)
{
pms_device_t dev;
rt_assert(uart_name);
dev = rt_calloc(1, sizeof(struct pms_device));
if (dev == rt_null)
{
log_e(can't allocate memory for pms device %s,uart_name);
return rt_null;
}
dev->serial = rt_device_find(uart_name);
if (!dev->serial)
{
rt_free(dev);
rt_kprintf(find %s failed!n, uart_name);
}
else
{
dev->config.baud_rate = baud_rate_9600;
dev->config.data_bits = data_bits_8;
dev->config.stop_bits = stop_bits_1;
dev->config.parity = parity_none;
dev->config.bit_order = bit_order_lsb;
dev->config.invert = nrz_normal;
dev->config.rx_bufsz = rt_serial_rb_bufsz;
dev->config.reserved = 0;
rt_device_control(dev->serial, rt_device_ctrl_config, &dev->config);
}
return dev;
}
void pms_deinit(pms_device_t dev)
{
rt_assert(dev);
rt_free(dev);
}
pms1003.h
/*
copyright (c) 2006-2021, rt-thread development team
spdx-license-identifier: apache-2.0
change logs:
date author notes
2023-03-08 dyc the first version
*/
#ifndef src_pms1003_h_
#define src_pms1003_h_
#define dbg_tag pms_series
#define dbg_lvl dbg_info
#include
#include
#include
#define comm_len 32
struct pms_device
{
rt_device_t serial;
struct serial_configure config;
rt_uint16_t len;
rt_uint16_t pm1_0_cf1;
rt_uint16_t pm2_5_cf1;
rt_uint16_t pm10_0_cf1;
rt_uint16_t pm1_0_amb;
rt_uint16_t pm2_5_amb;
rt_uint16_t pm10_0_amb;
rt_uint16_t air_0_3um;
rt_uint16_t air_0_5um;
rt_uint16_t air_1_0um;
rt_uint16_t air_2_5um;
rt_uint16_t air_5_0um;
rt_uint16_t air_10_0um;
rt_uint8_t version;
rt_uint8_t errorcode;
rt_uint16_t checksum;
};
typedef struct pms_device *pms_device_t;
pms_device_t pms_init(const char *uart_name);
rt_err_t frame_check(pms_device_t dev,rt_uint8_t buf,rt_uint16_t len);
rt_err_t pms_get_byte(pms_device_t dev, char data);
void pms_deinit(pms_device_t dev);
#endif / src_pms1003_h_ */
五、烧录验证与扩展
基本功能做完了,由于后续买的co2, 甲醛, iaq模块还在路上,后续到了会继续往该系统中添加,还要与esp8266 模块通信,完成本地系统数据远程访问,通过blinker实现数据的可视化,随时随地查看室内空气质量。
汽车电子“供热”问题是怎样的
2021双十二5000元左右投影仪推荐
全国照明电器标准化技术委员会(SAC/TC 224)召开年度会议
成功案例 I Opra Turbines:燃气轮机的气体扩散分析和防爆措施
小米6抢不到,荣耀9未开售!双双上榜京东618手机排行没毛病
CPK-RA2L1评估板(5)室内空气质量监测系统设计
中周变压器是什么_中周变压器的原理_中周变压器作用
基于OSFP-XD的1.6T光模块方案
从零到python机器学习大神的7个步骤
DS2141A , DS2143 , DS2151 , DS
钛深科技获数千万元Pre-A轮融资,因为这个黑科技?
OpenHarmony高校技术俱乐部分论坛召开,共话OpenHarmony高校生态发展
广和通基于联发科技 T830平台的5G模组FG370率先通过CE认证测试
要对空调行业有信心 但首先技术要过关
微雪电子TSOP56测试座简介
华为P20 Lite 2019曝光
浅谈关于功率分析仪选型的问题
谷歌Chrome OS更新的两项实用功能
江苏工业烤箱
雷达水位计在河道水位监测中的应用详情