本队伍编号CICC3042,本文介绍在蜂鸟处理器上运行RT-Thread实时操作系统,并进行ESP8266 wifi模块开发。
在蜂鸟配套的sdk中提供了RT-Thread的移植 https://github.com/riscv-mcu/hbird-sdk/tree/0.1.2/application/rtthread/msh ,我们只需要在其基础上进行具体应用开发,很大程度上减少了用户的工作量。我们选择在官方提供的msh应用基础上开发,因为它包含了RT-Thread中的finsh组件,可以使用户和程序很好地交互。
RT-Thread学习可以参考以下连接:
旧文档中心 https://www.rt-thread.org/document/site/
新文档中心 https://docs.rt-thread.org/#/
RT-Thread官方账号在B站发布的视频教程 https://www.bilibili.com/video/BV1of4y1S7Ju/?spm_id_from=333.788.recommend_more_video.0
ESP8266 wifi模块可以实现无线通信,相比于网口传输更加便携,功能更强大、开发更方便,基于串口控制的方式决定了其适合数据传输量不大,通信速率要求不高的情况,在低功耗物联网系统中被经常使用。ESP8266模块通过定制的AT指令集进行开发,支持STA/AP/STA+AP三种工作模式,具体不再展开。
我们选用了安信可科技的ESP-01S模块( https://docs.ai-thinker.com/esp8266 ),对于基本的AT集的使用不需要自己烧录固件,可以做到开箱即用。拿到ESP-01S模块时可以首先通过USB-TTL转接口连接到电脑进行测试,AT指令集和测试方法可以参考RT-Thread官方发布的教程 https://www.bilibili.com/video/BV1of4y1S7Ju?p=18 。
测试完毕后将其连接到开发板,典型的连接方式如下所示(图片来自 https://www.bilibili.com/video/BV1of4y1S7Ju?p=18 )。在我们的应用中,ESP-01S的引脚都连接到FPGA开发板的PMOD接口。
ESP-01S模块可以基于串口通信,因此我们使用蜂鸟的UART1(对应gpioB[17:16])进行开发,首先对UART1进行初始化,将gpioB[17:16]配置为IOF模式,并通过INIT_BOARD_EXPORT使UART1初始化在操作系统启动过程中自动进行。
void wifi_init() {
gpio_iof_config(GPIOB, IOF_UART_MASK);
uart_init(UART1, 115200);
}
INIT_BOARD_EXPORT(wifi_init);
随后实现AT指令发送,为了方便指令测试,将cmd函数导出到msh中,这样可以在RT-Thread运行过程中通过终端直接发送指令到wifi模块。比如通过输入"cmd AT"加回车键,把AT指令发送到wifi模块,将接收并打印“OK”字符,表示模块可以正常访问。
void wifi_cmd(char *cmd, int wait_time) {
send_str(cmd);
rt_thread_mdelay(wait_time);
}
int cmd(int argc, char **argv) {
if(argc != 2) {
rt_kprintf("USE: %s
return RT_ERROR;
}
wifi_cmd(argv[1], 0);
return RT_EOK;
}
MSH_CMD_EXPORT(cmd, send wifi cmd.)
接下来需要实现接收ESP8266模块返回字符的函数,这里采用一个单独线程实现。由于蜂鸟没有像一些STM32单片机一样提供直接访问uart接收区的方法,我们需要通过连续读取单个字符来读出uart buffer中的内容,当遇到换行时打印接收的一行字符。
void recv_thread_entry(void *parameter) {
int i = 0;
char ch;
while (1) {
ch = wifi_read(UART1);
if (ch == '\r' || ch == '\n') {
recv_buff[i] = '\0';
if (rt_strlen(recv_buff) > 0) {
i = 0;
rt_kprintf("%s\n", recv_buff);
}
}
else {
recv_buff[i] = ch;
i++;
}
}
}
创建静态线程,并使其随系统启动:
int wifi_thread_init(void) {
rt_kprintf("wifi_thread_init\n");
rt_err_t ret = RT_EOK;
rt_thread_t tid = &recv_thread;
ret = rt_thread_init(&recv_thread,
"receive_thread",
recv_thread_entry, RT_NULL,
&recv_thread_stack[0], sizeof(recv_thread_stack),
RECV_THREAD_PRIORITY, 10);
if (tid != RT_NULL && ret == RT_EOK)
rt_thread_startup(tid);
return RT_EOK;
}
INIT_APP_EXPORT(wifi_thread_init);
以上完成了指令的发送和字符接收,实现了板子和ESP8266模块的通信,测试效果如下,可以在此基础上进一步开发。