随着国家对环境大气监测越来越重视,一种新型移动监测车出现了,他满足了可以随处走动,随时随地的监测数据,本次就是在此方案的影响下完成本次的环境监测小车。当然这里我只是做了一个简单的模型,已经做到了采集温湿度传感器上云,后续可以自己添加一些传感器,真实采集大气的环境的TVOC传感器,还可以加入GPS上传小车行进轨迹。
本次方案主要使用的是沁恒的CH32V307开发板,外接温度湿度传感器,使用板载TFT,LCD显示,板载的ESP8266作为上云连接,对接腾讯云上传温湿度数据小车状态数据,同时通过其控制了小车,但是稍微有点延时,所以我添加了一块ESP32开发板,通过蓝牙控制小车。
这是本次官方的开发板,板载资源十分丰富,有摄像头,SPI falsh。TF卡,wifi模块同时外拓了很多的IO口。还有自带一个网口。可以说这些板载资源已经够开发了,可以实现很多的功能,本次由于时间关系我有一个功能未添加,后续可以添加上,就是把记录数据全部保存到本地的SD卡中,这样再win平台也能查询,本地也可以根据这个完成曲线显示。
本次为了不联网下也能控制小车,我使用了一款乐鑫开发板,ESP32,其集成经典蓝牙和低功耗蓝牙,我用来开发了蓝牙接收数据通过串口发送给CH32V307开发板,从而很快的控制小车动作。
SHT20温湿度传感器,数字式传感器,IIC接口,通过移植我们很好的就获取了其中的温湿度数值,由于手上缺少一些传感器,所以就没做TVOC,PM2.5这些传感器获取,使用这个替代下。
小车底盘我们选择最通用的亚克力板拼成的小车模型,直流电机驱动。
首先此次开发板是RISC-V内核的单片机,所以沁恒有自己的一套IDE而且不收费的,所以我们直接去官网下载即可。此款IDE名称是MounRiver Studio。使用起来还是有很方便之处的。
首先就是看下我们的Drivers目录,这里添加了我们的小车控制代码,json数据解析代码,还有温湿度传感器的代码。
#include "car.h"
#include "lcd.h"
u8 car_state = 0;
s8 lcd_car_state = -1;
void car_gpio_init()
{
GPIO_InitTypeDef GPIO_InitStructure={0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
GPIO_InitStructure.GPIO_Pin = left_advance_pin; /* */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(left_advance_prot, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = left_retreat_pin; /* */
GPIO_Init(left_retreat_prot, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = right_advance_pin; /* */
GPIO_Init(right_advance_prot, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = right_retreat_pin; /* */
GPIO_Init(right_retreat_prot, &GPIO_InitStructure);
car_stop();
}
//小车停止
void car_stop()
{
car_state = 0;
left_advance_off();
left_retreat_off();
right_advance_off();
right_retreat_off();
}
//小车前进
void car_advance()
{
car_state = 1;
left_advance_on();
right_advance_on();
}
//小车后退
void car_retreat()
{
car_state = 2;
left_retreat_on();
right_retreat_on();
}
//小车左转
void car_left()
{
car_state = 3;
left_advance_on();
right_retreat_on();
}
//小车右转
void car_right()
{
car_state = 4;
left_retreat_on();
right_advance_on();
}
void car_uart_receive(u8 data)
{
if(data == 0x00)
{
lcd_car_state = 0;
car_stop();
}
else if(data == 0x01)
{
lcd_car_state = 1;
car_advance();
}
else if(data == 0x02)
{
lcd_car_state = 2;
car_retreat();
}
else if(data == 0x03)
{
lcd_car_state = 3;
car_left();
}
else if(data == 0x04)
{
lcd_car_state = 4;
car_right();
}
}
小车代码,我是使用一款驱动芯片直接4个IO口就能控制两路电机,中间我添加了一个串口接收,这样ESP32蓝牙过来的串口数据也可以控制小车。
void lcd_display(void *arg)
{
car_gpio_init();
LCD_Init();
LCD_Fill(0,0,LCD_W,LCD_H,BLACK);
Draw_Circle(70,20,12,WHITE); //前进圆
Draw_Circle(20,70,12,WHITE); //右转圆
Draw_Circle(120,70,12,WHITE); //左转圆
Draw_Circle(70,70,12,WHITE); //停止圆
Draw_Circle(70,120,12,WHITE); //后退圆
LCD_Draw_ALLCircle(70,70,12,RED); //停止圆
LCD_ShowChinese(145,10,"温度",WHITE,BLACK,24,0); //
LCD_ShowString(195,10,":",WHITE,BLACK,24,0); //
LCD_ShowChinese(145,70,"湿度",WHITE,BLACK,24,0); //
LCD_ShowString(195,70,":",WHITE,BLACK,24,0); //
LCD_ShowString(210,35,"C",YELLOW,BLACK,24,0);
LCD_ShowString(210,105,"%",LIGHTGREEN,BLACK,24,0);
LCD_ShowChinese(0,140,"小车状态",WHITE,BLACK,24,0);
LCD_ShowString(100,140,":",WHITE,BLACK,24,0);
LCD_ShowChinese(115,140,"停止",BRED,BLACK,24,0);
// LCD_ShowString(30,140,"TencentOS_Tiny V2.4.5",WHITE,BLACK,16,0);
// LCD_ShowString(30,140+16,"CH32V_EVB_AIoT RevB02",WHITE,BLACK,16,0);
// LCD_ShowString(30,140+16+16,"CH32V307",WHITE,BLACK,16,0);
while (1)
{
if(lcd_car_state == 0)
{
lcd_car_state = -1;
car_stop();
LCD_Draw_ALLCircle(70,20,12,BLACK); //前进圆
LCD_Draw_ALLCircle(120,70,12,BLACK); //右转圆
LCD_Draw_ALLCircle(20,70,12,BLACK); //左转圆
LCD_Draw_ALLCircle(70,70,12,BLACK); //停止圆
LCD_Draw_ALLCircle(70,120,12,BLACK); //后退圆
Draw_Circle(70,20,12,WHITE); //前进圆
Draw_Circle(120,70,12,WHITE); //右转圆
Draw_Circle(20,70,12,WHITE); //左转圆
Draw_Circle(70,70,12,WHITE); //停止圆
Draw_Circle(70,120,12,WHITE); //后退圆
LCD_Draw_ALLCircle(70,70,12,RED); //停止圆
LCD_ShowChinese(115,140,"停止",BRED,BLACK,24,0);
}
else if(lcd_car_state == 1)
{
lcd_car_state = -1;
LCD_Draw_ALLCircle(70,20,12,BLACK); //前进圆
LCD_Draw_ALLCircle(120,70,12,BLACK); //右转圆
LCD_Draw_ALLCircle(20,70,12,BLACK); //左转圆
LCD_Draw_ALLCircle(70,70,12,BLACK); //停止圆
LCD_Draw_ALLCircle(70,120,12,BLACK); //后退圆
Draw_Circle(70,20,12,WHITE); //前进圆
Draw_Circle(120,70,12,WHITE); //右转圆
Draw_Circle(20,70,12,WHITE); //左转圆
Draw_Circle(70,70,12,WHITE); //停止圆
Draw_Circle(70,120,12,WHITE); //后退圆
// LCD_Draw_ALLCircle(70,70,12,RED); //停止圆
LCD_Draw_ALLCircle(70,20,12,GREEN); //前进圆
LCD_ShowChinese(115,140,"前进",BLUE,BLACK,24,0);
}
else if(lcd_car_state == 2)
{
lcd_car_state = -1;
LCD_Draw_ALLCircle(70,20,12,BLACK); //前进圆
LCD_Draw_ALLCircle(120,70,12,BLACK); //右转圆
LCD_Draw_ALLCircle(20,70,12,BLACK); //左转圆
LCD_Draw_ALLCircle(70,70,12,BLACK); //停止圆
LCD_Draw_ALLCircle(70,120,12,BLACK); //后退圆
Draw_Circle(70,20,12,WHITE); //前进圆
Draw_Circle(120,70,12,WHITE); //右转圆
Draw_Circle(20,70,12,WHITE); //左转圆
Draw_Circle(70,70,12,WHITE); //停止圆
Draw_Circle(70,120,12,WHITE); //后退圆
LCD_Draw_ALLCircle(70,120,12,GREEN); //后退圆
LCD_ShowChinese(115,140,"后退",BLUE,BLACK,24,0);
}
else if(lcd_car_state == 3)
{
lcd_car_state = -1;
LCD_Draw_ALLCircle(70,20,12,BLACK); //前进圆
LCD_Draw_ALLCircle(120,70,12,BLACK); //右转圆
LCD_Draw_ALLCircle(20,70,12,BLACK); //左转圆
LCD_Draw_ALLCircle(70,70,12,BLACK); //停止圆
LCD_Draw_ALLCircle(70,120,12,BLACK); //后退圆
Draw_Circle(70,20,12,WHITE); //前进圆
Draw_Circle(120,70,12,WHITE); //右转圆
Draw_Circle(20,70,12,WHITE); //左转圆
Draw_Circle(70,70,12,WHITE); //停止圆
Draw_Circle(70,120,12,WHITE); //后退圆
LCD_Draw_ALLCircle(20,70,12,GREEN); //左转圆
LCD_ShowChinese(115,140,"左转",BLUE,BLACK,24,0);
}
else if(lcd_car_state == 4)
{
lcd_car_state = -1;
LCD_Draw_ALLCircle(70,20,12,BLACK); //前进圆
LCD_Draw_ALLCircle(120,70,12,BLACK); //右转圆
LCD_Draw_ALLCircle(20,70,12,BLACK); //左转圆
LCD_Draw_ALLCircle(70,70,12,BLACK); //停止圆
LCD_Draw_ALLCircle(70,120,12,BLACK); //后退圆
Draw_Circle(70,20,12,WHITE); //前进圆
Draw_Circle(120,70,12,WHITE); //右转圆
Draw_Circle(20,70,12,WHITE); //左转圆
Draw_Circle(70,70,12,WHITE); //停止圆
Draw_Circle(70,120,12,WHITE); //后退圆
LCD_Draw_ALLCircle(120,70,12,GREEN); //右转圆
LCD_ShowChinese(115,140,"右转",BLUE,BLACK,24,0);
}
LCD_ShowFloatNum1(150,35,sht20Info.tempreture,4,YELLOW,BLACK,24); //
LCD_ShowFloatNum1(150,105,sht20Info.humidity,4,LIGHTGREEN,BLACK,24); //
tos_task_delay(1000);
}
}
LCD显示我是直接专门开了一个任务,用于刷新LCD显示的,目前安排了连接wifi的提示,5个圆代表了我们小车的不同运行状态。侧面我做了温湿度数据显示。
void default_message_handler(mqtt_message_t* msg)
{
cJSON* cjson_root = NULL;
cJSON* cjson_method = NULL;
cJSON* cjson_status = NULL;
cJSON* cjson_params = NULL;
cJSON* cjson_switch = NULL;
char* status = NULL;
char* method = NULL;
k_event_flag_t event_flag = report_fail;
int StateOfTheCar;
printf("callback:\r\n");
printf("---------------------------------------------------------\r\n");
printf("\ttopic:%s\r\n", msg->topic);
printf("\tpayload:%s\r\n", msg->payload);
printf("---------------------------------------------------------\r\n");
/* 使用cjson解析上报响应数据 */
cjson_root = cJSON_Parse(msg->payload+1);
if (cjson_root == NULL) {
printf("report reply message parser fail1\r\n");
event_flag = report_fail;
goto exit;
}
/* 提取method */
cjson_method = cJSON_GetObjectItem(cjson_root, "method");
method = cJSON_GetStringValue(cjson_method);
if (cjson_method == NULL || method == NULL) {
printf("report reply status parser fail2\r\n");
event_flag = report_fail;
goto exit;
}
if (strstr(method, "control"))
{
cjson_params = cJSON_GetObjectItem(cjson_root, "params");
cjson_switch = cJSON_GetObjectItem(cjson_params, "StateOfTheCar");
if (cjson_params == NULL || cjson_switch == NULL) {
printf("control data parser fail4\r\n");
cJSON_Delete(cjson_root);
return;
}
StateOfTheCar = cjson_switch->valueint;
printf("StateOfTheCar:%d\r\n",StateOfTheCar);
if(StateOfTheCar == 0x00)
{
lcd_car_state = 0;
car_stop();
}
else if(StateOfTheCar == 0x01)
{
lcd_car_state = 1;
car_advance();
}
else if(StateOfTheCar == 0x02)
{
lcd_car_state = 2;
car_retreat();
}
else if(StateOfTheCar == 0x03)
{
lcd_car_state = 3;
car_left();
}
else if(StateOfTheCar == 0x04)
{
lcd_car_state = 4;
car_right();
}
cJSON_Delete(cjson_root);
return;
}
exit:
cJSON_Delete(cjson_root);
cjson_root = NULL;
status = NULL;
method = NULL;
}
这个是腾讯平台下发控制小车解析JSON数据。
#define REPORT_DATA_TEMPLATE "{\\\"method\\\":\\\"report\\\"\\,\\\"clientToken\\\":\\\"00000001\\\"\\,\\\"params\\\":{\\\"temperature\\\":\\\"%.2f\\\"\\,\\\"humidity\\\":\\\"%.2f\\\"\\,\\\"StateOfTheCar\\\":\\\"%d\\\"}}"
这个是上传的物模型,主要三种数据传输上去,一个是温度,一个湿度,一个小车状态。
至此底层的开发就这样了。
腾讯云物联网平台开发,需要我们自己新建项目,产品。联网方式我们选择WIFI联网。数据使用腾讯云的物模型即可。
然后就是添加我们的功能,功能也是物模型,传输数据解析与这些都有关系的。尤其是标识符需要注意。
之后就是我们的H5面板,腾讯连连方便我们开发微信小程序控制小车。查阅数据。这里我使用的是标准面板。
最后就是新建设备,设备建好之后,设备内容需要我们自己更换,这个是在底层,不然也是通信不上的。
先看下我们腾讯连连的面板,上线后设备就是这样的。状态由于没有和按钮同步,所以我就在外面添加了,可以在外面看到小车各种状态。
本次基于RISC-V开发过程很是顺利,得益于一个好的IDE,一个好的OS,TencentOS Tiny提供了完善的驱动,上云和下发数据解析都能直接完成。加上腾讯的物联网平台可以直接用小程序进行联控更加方便。本次的IDE主要在浮点数需要设置,其他地方,提示跳转都是很方便的,由于时间的关系,自己仅构想了这个简单的应用,最后的数据保存,可以利用两个,一个SPI Flash 和TF卡,保存数据这个功能,在实际中还是很有用的。本次开发就到这里了。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。