2058|3

282

帖子

7

TA的资源

一粒金砂(高级)

楼主
 

【平头哥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)

最新回复

谢谢LZ,学习了   详情 回复 发表于 2022-4-23 14:57
点赞 关注
 
 

回复
举报

7047

帖子

11

TA的资源

版主

沙发
 

非常感谢你这个思路,我原来想起SPI是不能动的,没想到他的CS跟CLK可以变换。

 
 
 

回复

553

帖子

3

TA的资源

纯净的硅(初级)

板凳
 

需要用到串口的可能都需要借鉴你这个操作了

 
 
 

回复

4942

帖子

12

TA的资源

版主

4
 

谢谢LZ,学习了

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/6 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表