RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植
前言
stm32CubeMx在stm32开发上提供了很大的便利性,咱们能够用它来配置一些外设,系统时钟。RTT是一款很棒的RTOS,可是Device框架对我这些初学者来讲仍是有必定的难度,有时咱们只需使用RTOS的核心功能就行,而RTT能够很方便地包含进本身的工程中来。下面是移植过程的一些笔记。本文大部份内容都能在RTT官网文档中找到,可是有些细节的部分可能文档中没提到,下面结合CubeMx的LL库移植RTT和Finsh。
感受CubeMx的LL库和stm32的标准库比较类似,LL库比HAL库底层,代码简洁,可是也会有些问题,好比在串口发送数据的时候不能直接使用库提供发送函数,而须要咱们额外写,好比添加发送完成标志检测等,要否则因为发送数据操做太快致使串口发送会出错。
本文假设已经安装了CubeMx和MDK,而且相关pack也已经安装好了。
shell
CubeMx配置
CubeMx我用的是旧版,讲真CubeMx界面是越更新越丑,也有一些难以忍受的bug,用起来也不方便。因此仍是旧版的好使。
我用的板子是STM32F411CEU6的最小系统板。系统主频最大100Mhz。
配置系统时钟外部时钟25Mhz:
配置串口,打开接收中断(记得勾选全局中断)。
直接生成MDK5工程便可。
框架
将RTTHREAD NANO加进工程中
中断与异常处理
RT-Thread 会接管异常处理函数 HardFault_Handler() 和 PendSV_Handler(),这两个函数由 RT-Thread 实现,因此须要删除工程里中断服务例程文件 stm32f4xx_it.c中的这两个函数还有就是删除要用到的串口中断函数,避免在编译时产生重复定义错误。若是此时对工程进行编译,没有出现函数重复定义的错误,则不用作修改。
接下来就是系统时钟,rtt用stm32的嘀嗒时钟为其提供时基。因此咱们还要改嘀嗒时钟配置和中端函数,在中断文件中咱们也删除void SysTick_Handler(void)函数,而后在RTT的board文件中改,另外咱们将main中时钟配置函数也复制过去:
而后在usart.c中实现Finsh输出,输入函数。这里重写串口数据发送函数不然数据发送会出错。主要是添加标志位检测,防止发送数据过快。
函数
void uart_send(uint8_t c) { uint32_t t=0; LL_USART_TransmitData8(USART1,c); while(LL_USART_IsActiveFlag_TC(USART1) == (uint16_t)RESET) { t++; if(t>0xffff)return; } } void rt_hw_console_output(const char *str) { rt_size_t i = 0, size = 0; char a = '\r'; size = rt_strlen(str); for (i = 0; i < size; i++) { if (*(str + i) == '\n') { uart_send((uint8_t)a); } uart_send((uint8_t )(*(str + i))); } } //数据接收采用中断+ ringbuffer 缓冲的方式,具体代码和官网文档同样 //使用的时候要先初始化: rt_ringbuffer_init(&uart_rxcb, uart_rx_buf, UART_RX_BUF_LEN); rt_sem_init(&(shell_rx_sem), "shell_rx", 0, 0); char rt_hw_console_getchar(void) { char ch = 0; /* 从 ringbuffer 中拿出数据 */ while (rt_ringbuffer_getchar(&uart_rxcb, (rt_uint8_t *)&ch) != 1) { rt_sem_take(&shell_rx_sem, RT_WAITING_FOREVER); } return ch; } /* uart 中断 */ void USART1_IRQHandler(void) { int ch = -1; // rt_base_t level; /* enter interrupt */ rt_interrupt_enter(); //在中断中必定要调用这对函数,进入中断 if(LL_USART_IsActiveFlag_RXNE(USART1) && LL_USART_IsEnabledIT_RXNE(USART1)) { while (1) { ch = -1; if (LL_USART_IsActiveFlag_RXNE(USART1) != RESET) { ch = LL_USART_ReceiveData8(USART1); } if (ch == -1) { break; } /* 读取到数据,将数据存入 ringbuffer */ rt_ringbuffer_putchar(&uart_rxcb, ch); } rt_sem_release(&shell_rx_sem); } /* USER CODE END USART1_IRQn 1 */ /* leave interrupt */ rt_interrupt_leave(); //在中断中必定要调用这对函数,离开中断 }
而后咱们使用RTT的初始化机制:
main函数中延时函数改rtt的延时函数rt_thread_mdelay();这个函数会让当前线程让出CPU控制权。
这里基本就完成RTT+Finsh移植了
而后编译下载:发现能出RTT的LOGO
,但不能输入:
后来发现串口中断那里还要加两条语句打开串口中断:
LL_USART_EnableIT_RXNE(USART1); //接收中断
LL_USART_EnableIT_PE(USART1);//串口总中断
从新编译下载:
能够看到能输出也能接收命令输入了。
测试
总结
LL库比较接近寄存器操做的了。
最后工程代码我已经上传到这里了。能够到个人资源那找。
ui