1.RT-thread简介
T-Thread(Real Time-Thread),是一个嵌入式实时多线程操作系统。在 RT-Thread 系统中,任务调度通过线程实现的。
RT-Thread 主要采用 C 语言编写,浅显易懂,方便移植。针对资源受限的微控制器(MCU)系统,可通过方便易用的工具,裁剪出仅需要 3KB Flash、1.2KB RAM 内存资源的 NANO 版本;而对于资源丰富的物联网设备,RT-Thread 又能使用在线的软件包管理工具,配合系统配置工具实现直观快速的模块化裁剪,无缝地导入丰富的软件功能包,实现类似 Android 的图形界面及触摸滑动效果、智能语音交互效果等复杂功能。
如果之前有过FreeRTOS后UCOS等嵌入式系统经验,那这款国产系统更容易上手咯,同时也为支持国产贡献一份力量吧。
2.用stm32CubeMx建一个最简单的工程吧
芯片:stm32l031k6t6(手上就只有这款咯,M0+ 32MHz,32KFlash,8KSRAM)
怎么感觉flash和RAM有点不够用咧,还是先做吧
导出到MDK-ARM中,编译0 error,0 warning
3.修改一下工程咯
把串口和spi驱动单独封装成一个文件(可以不做处理,这里纯属个人习惯)
-
添加RT-thread库到工程文档中
-
将stm32l0xx_it.c中重定义的函数删除、注释或weak一下
-
用rtconfig.h配置一下系统,把不需要的组件去除,鉴于用的芯片内存很小,我就把大部分功能去除了
4.RT-thread系统对外设初始化在board.c的rt_hw_board_init()函数中实现的,我们修改一下
5.实现一下串口咯,RT-thread中的串口打印函数是rt-kprintf
void rt_kprintf(const char *fmt, ...)
{
va_list args;
rt_size_t length;
static char rt_log_buf[RT_CONSOLEBUF_SIZE];
va_start(args, fmt);
/* the return value of vsnprintf is the number of bytes that would be
* written to buffer had if the size of the buffer been sufficiently
* large excluding the terminating null byte. If the output string
* would be larger than the rt_log_buf, we have to adjust the output
* length. */
length = rt_vsnprintf(rt_log_buf, sizeof(rt_log_buf) - 1, fmt, args);
if (length > RT_CONSOLEBUF_SIZE - 1)
length = RT_CONSOLEBUF_SIZE - 1;
#ifdef RT_USING_DEVICE
if (_console_device == RT_NULL)
{
rt_hw_console_output(rt_log_buf);
}
else
{
rt_uint16_t old_flag = _console_device->open_flag;
_console_device->open_flag |= RT_DEVICE_FLAG_STREAM;
rt_device_write(_console_device, 0, rt_log_buf, length);
_console_device->open_flag = old_flag;
}
#else
rt_hw_console_output(rt_log_buf);
#endif
va_end(args);
}
rt_hw_console_output()函数需要用户自己实现,实现函数如下
void rt_hw_console_output(const char *str){
rt_enter_critical();
while(*str != '\0'){
if(*str =='\r'){
HAL_UART_Transmit(&huart2, (uint8_t *)'\n', 1, 0xfff);
}
HAL_UART_Transmit(&huart2, (uint8_t *)(str++), 1, 0xfff);
}
rt_exit_critical();
}
下载测试一下,如下图,就是串口移植成功咯
6. 测试一下线程、消息队列
#include "main.h"
#include "slim_drv.h"
#include <rtthread.h>
#include <stdio.h>
static rt_thread_t thread1 = RT_NULL;
static rt_thread_t thread2 = RT_NULL;
static rt_thread_t thread3 = RT_NULL;
static rt_mq_t rt_mq = RT_NULL;
//function declaration
static void Thread1_entry(void *arg);
static void Thread2_entry(void *arg);
static void Thread3_entry(void *arg);
int main(void){
thread1 = rt_thread_create("thread1", Thread1_entry, RT_NULL, 512, 5, 10);
if(thread1 != RT_NULL){
rt_thread_startup(thread1);
rt_kprintf("thread1 create success\n");
}else{
rt_kprintf("thread1 create failed\n");
return -1;
}
thread2 = rt_thread_create("thread2", Thread2_entry, RT_NULL, 512, 3, 20);
if(thread2 != RT_NULL){
rt_thread_startup(thread2);
rt_kprintf("thread2 create success\n");
}else{
rt_kprintf("thread2 create failed\n");
return -1;
}
thread3 = rt_thread_create("thread3", Thread3_entry, RT_NULL, 512, 4, 10);
if(thread3 != RT_NULL){
rt_thread_startup(thread3);
rt_kprintf("thread3 create success\n");
}else{
rt_kprintf("thread3 create failed\n");
return -1;
}
rt_mq = rt_mq_create("mq", 256, 1, RT_IPC_FLAG_FIFO);
if(rt_mq != RT_NULL){
rt_kprintf("create MQ success\n");
}else{
rt_kprintf("create MQ failed\n");
}
rt_kprintf("\n");
return RT_EOK;
}
void Thread1_entry(void *arg){
uint8_t cnt = 0;
while(1){
rt_kprintf("Thread1 Cnt:%d\n",cnt++);
rt_thread_delay(2000);
}
}
void Thread2_entry(void *arg){
rt_err_t ret = RT_EOK;
char tx_buff[128] = {0};
uint32_t cnt = 1;
while(1){
sprintf(tx_buff, "Hello World! %d",cnt);
ret = rt_mq_send(rt_mq, tx_buff, 20);
rt_thread_delay(5000);
cnt *= 2;
if(cnt>0xffff){
cnt = 1;
}
}
}
static void Thread3_entry(void *arg){
rt_err_t ret = RT_EOK;
uint8_t r_queue[128] = {0};
uint32_t r_int = 0;
while(1){
ret = rt_mq_recv(rt_mq, r_queue, sizeof(r_queue), RT_WAITING_FOREVER);
if(RT_EOK == ret){
rt_kprintf("Rx OK: %s\n",r_queue);
}else{
rt_kprintf("Rx Err: %x\n",ret);
}
rt_thread_delay(10);
}
}
- 测试能正常运行。其他的消息邮箱、信号量、互斥量、事件、软定时器用法就不演示了,到文章开头的RT-thread文档点进去,自行学习调试