【平头哥RVB2601创意应用开发】环境监测终端05-温湿度采集和显示
[复制链接]
本篇文章介绍使用RVB2601开发板UART1接口接收外接模块的温湿度数据,并显示到OLED上面。
1、硬件设计
本次使用的RVB2601开发板不带温湿度传感器,要想获得这两个参数,需要外接检测模块。检查了一下手头的资源,发现以前评测《安信可UWB室内定位模组》攒下的模块可以通过串口输出温湿度数据,软件接口也比较简单,就选它了。
图1、安信可UWB室内定位模组
再看RVB2601开发板,从CH2601的GPIO复用关系表格中可以看到,几乎每一个IO口都用上了,基本上没有空闲,尤其是我想用的串口。
图2、IO复用关系表
其中UART0用来做调试信息交互,基本不用指望了。UART1的收发引脚则被OLED和JTAG占用。后面仔细研究OLED程序发现驱动代码没有使用SPI接口,直接用IO模拟的SPI总线,这就给我了机会,可以用其他IO口替换掉被占用的串口引脚。考虑到我这个作品基本不用RGB三色灯,决定把这个灯的其中两个IO口转给OLED,这样就能空出UART1的收发引脚了。最终的接线后实物如下图。
图3、改造后的开发板
改造后的接线原理图如下,PA7,PA4分别接OLED的CS和CK,PA27,PA28为接UWB模块的收发串口。
图4、改造后的接线图
2、软件设计
首先是更改OLED的驱动程序,重新设置引脚定义,代码如下。重新编译下载,程序直接就好使,没有遇到任何问题。
//改OLED接口
static void oled_pinmux_init()
{
csi_pin_set_mux(PA7, PIN_FUNC_GPIO); //cs
csi_pin_set_mux(PA4, PIN_FUNC_GPIO); //clk
// csi_pin_set_mux(PA27, PIN_FUNC_GPIO); //cs
// csi_pin_set_mux(PA28, PIN_FUNC_GPIO); //clk
csi_pin_set_mux(PA29, PIN_FUNC_GPIO); //mosi
csi_pin_set_mux(PA30, PIN_FUNC_GPIO); //miso
}
static void oled_gpio_init()
{
//
csi_gpio_pin_init(&pin_cs, PA7);
csi_gpio_pin_dir(&pin_cs, GPIO_DIRECTION_OUTPUT);
csi_gpio_pin_init(&pin_clk, PA4);
csi_gpio_pin_dir(&pin_clk, GPIO_DIRECTION_OUTPUT);
// csi_gpio_pin_init(&pin_cs, PA27);
// csi_gpio_pin_dir(&pin_cs, GPIO_DIRECTION_OUTPUT);
// csi_gpio_pin_init(&pin_clk, PA28);
// csi_gpio_pin_dir(&pin_clk, GPIO_DIRECTION_OUTPUT);
csi_gpio_pin_init(&pin_mosi, PA29);
csi_gpio_pin_dir(&pin_mosi, GPIO_DIRECTION_OUTPUT);
csi_gpio_pin_init(&pin_miso, PA30); //dc
csi_gpio_pin_dir(&pin_miso, GPIO_DIRECTION_OUTPUT);
}
然后是编写UART1驱动程序。搞这个遇到麻烦。最开始查看官方提供的几个DEMO,均没有发现UART1相关代码,我试图用debug口的代码改造,发现关联很复杂,拆解起来太费劲了,只好求助官方的客服,提交工单走起。
客服给我提供的是这个教程:
https://yoc.docs.t-head.cn/yocbook/Chapter3-AliOS/CSI%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E6%8E%A5%E5%8F%A3/CSI2/UART.html
在最下面有中断模式的使用示例,我尝试移植到我的工程中,第一个遇到的麻烦就是例程中没有给出需要引用的头文件。编译完成出现一大堆错误和警告。客服给的解决办法是在整个工程文件中搜索,把所有报错信息挨个查找添加,这...是不是有点效率低下。我则简单粗暴,把这个库里几个c文件引用的头文件都添加上了,编译顺利通过。
然后又遇到问题。原计划按照以前做STM32的经验,串口不定长收数,最好是采用空闲中断+DMA方式,效率较高。而CSI2库这个例程只实现了固定长度的收发,超出这个长度串口就挂掉了,也没有提到如何实现空闲中断。然后全网搜索解决办法,没有任何有价值信息,甚至我连CH2601芯片的规格书都没有找到。没办法只好给客服留言,希望能获得帮助。
在查阅文档过程中,发现HAL硬件抽象层接口库又在CSI2库外面做了一层封装,似乎操作更简单一些。链接如下。
https://yoc.docs.t-head.cn/yocbook/Chapter3-AliOS/HAL%E7%A1%AC%E4%BB%B6%E6%8A%BD%E8%B1%A1%E5%B1%82%E6%8E%A5%E5%8F%A3/UART.html
深入研究发现可以使用HAL库的中断收数超时机制实现不定长数据接收,虽然效率低一些,但是对于本次应用,数据大概每秒一次,每次三十多个字节,效率问题几乎不用考虑。经过一通复制粘贴,终于实现了预期的目标。
3、数据解析
UWB模块发过来的数据如下格式:
T:25.898218
H:31.590054
OK
我需要从其中获取浮点数值。从网上查到一些例程,基本上都是挨个判断每个字符类型,然后截取,拼接,比较复杂。我想到strtof这个函数,可以直接从字符串获取浮点数,但是有个问题,在字符串中浮点数必须是数字或空格开头的,不然识别不成功。这里我用了一个比较笨的却有效的方法,直接把T:和H:替换成空格,然后就识别成功了。最终的成品代码如下。
#include <stdio.h>
#include <stdlib.h>
#include <aos/aos.h>
#include <aos/hal/uart.h>
#include "thp_get.h"
#define UART1_PORT_NUM 1
#define UART_BUF_SIZE 40
#define UART_TX_TIMEOUT 10
#define UART_RX_TIMEOUT 10
extern Result_S res_data;
/* define dev */
uart_dev_t uart1;
/* data buffer */
const char uart_tx_buf[] = "AT+tem_hum\r\n";
char uart_data_buf[UART_BUF_SIZE];
int application_start(void)
{
int ret = -1;
uint32_t rx_size = 0;
char *pEnd;
float ret1,ret2;
/* uart port set */
uart1.port = UART1_PORT_NUM;
/* uart attr config */
uart1.config.baud_rate = 115200;
uart1.config.data_width = DATA_WIDTH_8BIT;
uart1.config.parity = NO_PARITY;
uart1.config.stop_bits = STOP_BITS_1;
uart1.config.flow_control = FLOW_CONTROL_DISABLED;
uart1.config.mode = MODE_TX_RX;
/* init uart1 with the given settings */
ret = hal_uart_init(&uart1);
if (ret != 0) {
printf("uart1 init error !\n");
}
/* init the tx buffer */
memset(uart_data_buf,0,UART_BUF_SIZE);
/* scan uart1 every 2000ms, if data received send it back */
while(1)
{
hal_uart_send(&uart1, uart_tx_buf, 12, UART_TX_TIMEOUT);
ret = hal_uart_recv_II(&uart1, uart_data_buf, UART_BUF_SIZE,&rx_size, UART_RX_TIMEOUT);
if(rx_size != 0)
{
// printf("ret:%d,size:%d.\n",ret,rx_size);
// printf("%s\n",uart_data_buf);
uart_data_buf[0] = ' ';
uart_data_buf[1] = ' ';
uart_data_buf[11] = ' ';
uart_data_buf[12] = ' ';
uart_data_buf[13] = ' ';
uart_data_buf[14] = ' ';
ret1 = strtof(uart_data_buf, &pEnd);
ret2 = strtof(pEnd, &pEnd);
// printf("num1:%f\n", ret1);
// printf("num2:%f\n", ret2);
// printf("str:%s\n", pEnd);
res_data.temp = ret1;
res_data.humi = ret2;
}
memset(uart_data_buf,0,UART_BUF_SIZE);
/* sleep 2000ms */
aos_msleep(2000);
};
}
综上,通过串口实现了温湿度的数据采集。整体上我设置了一个全局的结构体变量,里面包含了温度,湿度,噪声水平。温湿度采集为一个单独的任务,获取到采集结果后存到全局结构体变量中,显示任务定时将这个结构体中的数值刷新到显示屏上。噪声水平检测在上一篇中已经介绍,采用的是同样的方法。
整体工作起来如下视频,可以看到,用手触摸传感器,温湿度会明显变化。
图5、演示视频
程序调好后,客服也发来了CH2601芯片的规格书,我放在附件中,用到的同学可以下载参考。
CH2601用户手册V1.0.pdf
(7.73 MB, 下载次数: 10)
|