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