一、总体设计
本次有幸参与创新“芯”引擎 | 国民技术N32G457 RT-Thread设计大赛,室内植物机基于国民技术推出的N32G45XVL-STB开发套件,外接WiFi模组及土壤湿度传感器,监测植物生长环境湿度并上传至云端,同时利用支持云端下发控制命令实现远程控制。
二、硬件设计
系统硬件基于N32G45XVL-STB,MCU为N32G457,采用32-bit ARM Cortex-M4内核,集成高达512KB片内FLASH,144KB SRAM,多达17个高性能模拟器件,18个数字通讯接口,同时集成10/100M以太网接口,数字摄像头接口,内置10余种密码算法硬件加速引擎,支持存储加密、用户分区保护、安全启动等多种安全特性,可广泛应用于网络打印机、3D打印机、门禁考勤系统、LED户外显示屏、工业小型网关、DTU、PLC、充电桩等消费及工业互联应用领域。此外,板载祖传miniUSB接口CMSIS DAP仿真器。
硬件外设选择了ESP8266模块、土壤湿度传感器、一个板载的LED权当水泵了(反正都是PIN控制,又不是不能用),具体接口见下表。
【注意】要使用ADC,需要将VREF两个针脚接上3.3V和GND,否则ADC读不出数据。
三、软件设计和实现
借助于RT-Thread系统的各种软件模块,整个软件比较简洁,因为本来需要开发者自己实现的功能,RT-Thread都实现了,而且效果很赞。
端侧软件主要4个task:
1.main task:主要初始化环境,譬如LED配置,MQ的init,并且启动两大业务task,MQTT task和ADC task,之后便控制LED2不断闪烁。
/* set LED pin mode to output */
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_AFIO,ENABLE);
GPIO_ConfigPinRemap(GPIO_RMP_SW_JTAG_SW_ENABLE, ENABLE);
rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);
rt_pin_mode(LED2_PIN, PIN_MODE_OUTPUT);
//init MQ
rt_thread_mdelay(1000);
ret = rt_mq_init(&mq, "MsgQ", &msg_pool[0], 1, sizeof(msg_pool), RT_IPC_FLAG_PRIO);
if (ret != RT_EOK)
{
rt_kprintf("init message queue failed: %d.
", ret);
return -1;
}
//start MQTT task
rt_thread_mdelay(1000);
onenet_mqtt_init();
//start data upload task
rt_thread_mdelay(1000);
onenet_upload_cycle();
while (1)
{
rt_pin_write(LED1_PIN, PIN_LOW);
rt_thread_mdelay(1000);
rt_pin_write(LED1_PIN, PIN_HIGH);
rt_thread_mdelay(1000);
}
2.ADC task:采集ADC1的数据,并且在自动模式下根据土壤湿度传感器的度数是否超过阈值决定是否启动水泵(亮LED3),同时将具体数值通过消息队列发送给MQTT task。
/*try to find device*/
adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME);
/*enable device found*/
rt_adc_enable(adc_dev, ADC_DEV_CHANNEL);
while(1)
{
rt_thread_mdelay(2000);
/*read sample value of ADC*/
value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
//transfer
if (value > 30) value = 30;
tmp = 30 - value;
if (iMode == 0)
{
if(tmp <15)
{
rt_pin_write(LED2_PIN, PIN_HIGH);
}
else
{
rt_pin_write(LED2_PIN, PIN_LOW);
}
}
rt_kprintf("rt_adc_read :%d
",value);
result = rt_mq_send(&mq, (char *)&tmp, sizeof(tmp));
if (result != RT_EOK)
{
rt_kprintf("rt_mq_send ERR(%d)
", result);
}
else
{
rt_kprintf("ADC_task: send message - %d
", tmp);
}
}
3.MQTT task:基于pahoMQTT模块,注册处理MQTT下发信息的回调函数,接收中移物联网平台云端下发手动操作命令,启动/关停水泵(LED3)。
/* onenet mqtt command response callback function */
static void onenet_cmd_rsp_cb(uint8_t *recv_data, size_t recv_size, uint8_t **resp_data, size_t *resp_size)
{
char res_buf[] = { "cmd is received!
" };
LOG_D("recv data is %.*s
", recv_size, recv_data);
//handle cmd from cloud
if (strstr(recv_data, "ON") != NULL)
{
//set mode
iMode = 1;
//light LED
rt_pin_write(LED2_PIN, PIN_HIGH);
}
else if (strstr(recv_data, "OFF") != NULL)
{
//set mode
iMode = 0;
//light LED
rt_pin_write(LED2_PIN, PIN_LOW);
}
/* user have to malloc memory for response data */
*resp_data = (uint8_t *) ONENET_MALLOC(strlen(res_buf));
strncpy((char *)*resp_data, res_buf, strlen(res_buf));
*resp_size = strlen(res_buf);
}
4.upLoadX task:通过消息队列接收来自ADC task的湿度数据,通过onenet MQTT传输至中移物联网平台。
while (1)
{
//value = rand() % 100;
if (rt_mq_recv(&mq, (char *)&value, sizeof(value), RT_WAITING_FOREVER) == RT_EOK)
{
rt_kprintf("UpLoadX: recv msg from msg queue, the content:%d
", value);
}
if (onenet_mqtt_upload_digit("humidity", value) < 0)
{
LOG_E("upload has an error, stop uploading");
break;
}
else
{
LOG_D("buffer : {"humidity":%d}", value);
}
rt_thread_delay(rt_tick_from_millisecond(1000));
}
其他诸如WiFi账号输入、onenet密码生成、onenet设备创建等之类的操作,因为文档太傻瓜了,所以不再陈述。
再者,如RT-Thread组件配置,包括AT、cJSON、paho MQTT、Onenet等组件选择,POSIX、libc、串口等配置,也不能说的太多,因为RT-Thread Studio太好用了,亦不再陈述,毕竟太晚了,我还要王者峡谷浪一波。 最后RT-Thread Studio编译好的固件如下图,内存占用太少了,N32G457的144KB表示毫无压力,之前一个task设置4096还心疼大半天。
四、运行效果 最熟悉的配方、最熟悉的画面,只不过多年前第一次在串口上显示出RT字样的激动不再有,现在多了一份从容,也多了一份油腻。
来个ps cmd。
再来看看Onenet云端的数据。
最后本尊压轴出场(模拟干燥环境,水泵抽水,把那个绿灯LED3就是水泵,哈哈)。
五、一些感想 RT-Thread很赞!RT-Thread Studio很赞!N32G457很惊喜!我不是逢迎,因为我前阵子在使用其他RTOS、还有其他非STM的MCU,都快用哭了,只有对比才知道好在哪里,那感觉,就是舒坦。 此外,能不能报个硬件BUG,这个板子的RESET拿到就不能用,只能用短接大法,哭了。
|