stm32 f103 以他的全面的文檔,親民的價格,強大的功能。成爲無數微設備的方案首選。在市場上有極大的使用量。市場佔有率也是很是的高。freertos做爲一個開源的微型操做系統,憑藉着它的資源佔用小,功能強大,文檔齊全,成爲各大芯片公司都支持的操做系統,也是程序員操做系統學習的不二首選。因此,把這二者結合起來,除了能給咱們的產品提供強大的支撐以外,還積累的不少基礎技術。筆者花了很多心思才把這個移植好,在這裏作個記錄。但願能給你一些啓發。程序員
我這裏使用的是freertos的版本是9.0。移動植入以前,先看一下freertos的文件目錄:app
├── croutine.c ├── event_groups.c ├── include │ ├── FreeRTOS.h │ ├── StackMacros.h │ ├── croutine.h │ ├── deprecated_definitions.h │ ├── event_groups.h │ ├── list.h │ ├── mpu_prototypes.h │ ├── mpu_wrappers.h │ ├── portable.h │ ├── projdefs.h │ ├── queue.h │ ├── semphr.h │ ├── stdint.readme │ ├── task.h │ └── timers.h ├── list.c ├── portable │ ├── GCC │ │ └── ARM_CM3 │ │ ├── port.c │ │ └── portmacro.h │ ├── MemMang │ │ ├── heap_1.c │ │ ├── heap_2.c │ │ ├── heap_2.lst │ │ ├── heap_2.o │ │ ├── heap_3.c │ │ ├── heap_4.c │ │ └── heap_5.c │ └── readme.txt ├── queue.c ├── readme.txt ├── tasks.c └── timers.c
大體一看,這個操做系統是很是簡潔的。從文件名字就能夠看出:
queue.c 這個文件是隊列,負責線程之間的通訊和數據傳輸的。
task.c 就是線程及任務模塊,線程相關的都在這個文件裏面。
list.c 就是一個鏈表,用來實現可變數據的存放和操做。
根目錄下的和具體的芯片不要緊,和芯片的接口及相關的元素主要在兩個函數裏面。
一個是portable文件下的port.c 這個裏面要注意下,在stm32 f103中,這裏最重要的就是這裏的中斷處理函數的匹配了。在無操做系統的stm32 f103中,systick, SVC 和 PendSV 這三個中斷的處理函數 這三個函數通常在start.s文件或中斷向量表中vector.c 中。基本額寫法以下所示:函數
void SVC_Handler (void) attribute((weak)); void PendSV_Handler (void) attribute((weak)); void SysTick_Handler (void) attribute((weak));
在freertos中,須要替換成port.c 裏面的另外三個中斷處理函數:學習
voidxPortPendSVHandler( void ) attribute (( naked )); voidxPortSysTickHandler( void ); voidvPortSVCHandler( void ) attribute (( naked ));
另一個就是heap,heap主要是系統的內存管理單元。heap_1.c, heap_2.c and heap_3.c屬於三個基本的樣例子,用戶也能夠根據本身的實際狀況作修改。這裏的的heap雖然不少,可是每一個系統只會使用一個,具體使用哪個要看你的芯片平臺的屬性,stm32 f103 使用的是heap_2.c操作系統
第一步就是把代碼拷貝到目標文件中,編譯經過。這裏屬於一些基本功夫,詳細的步驟我就很少說了,謹記中斷處理函數的處理,這裏很是容易出問題。再者就是FreeRTOSconfig.h文件中的heap_size大小,不能太大,太大了這個芯片的資源不夠的。建議通常不要10k左右就好了吧。prototype
第二步就是FreeRTOSConfig.h文件的配置選擇,這裏面的是很是關鍵的,最容易出錯。下面是個人這個文件的配置:線程
#define configUSE_PREEMPTION 1 #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 #define configCPU_CLOCK_HZ ( ( unsigned long ) 72000000 ) #define configSYSTICK_CLOCK_HZ ( configCPU_CLOCK_HZ / 8 ) /* fix for vTaskDelay() */ #define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) #define configMAX_PRIORITIES ( 5 ) #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 ) #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) ) #define configMAX_TASK_NAME_LEN ( 16 ) #define configUSE_TRACE_FACILITY 0 #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 #define configUSE_MUTEXES 1 /* Co-routine definitions. */ #define configUSE_CO_ROUTINES 0 #define configMAX_CO_ROUTINE_PRIORITIES 2 /* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */ #define INCLUDE_vTaskPrioritySet 1 #define INCLUDE_uxTaskPriorityGet 1 #define INCLUDE_vTaskDelete 1 #define INCLUDE_vTaskCleanUpResources 0 #define INCLUDE_vTaskSuspend 0 #define INCLUDE_vTaskDelayUntil 1 #define INCLUDE_vTaskDelay 1
這裏要注意幾點: configCPU_CLOCK_HZ 就是CPU的的時鐘,系統的時鐘和CPU的時鐘是不一樣的,這裏作一個8分頻:#define configSYSTICK_CLOCK_HZ ( configCPU_CLOCK_HZ / 8 )
還有就是後面的heap大小和stack大小,要根據實際的產品狀況進行調整的。這個調整好了,可讓你的小芯片發揮出極大的威力。日誌
第三點,應用部分:
這裏手先看一下主函數:code
int main() { RCC_Configuration(); GPIO_Configuration(); usart1_init(); printf("start main sdf \n\r"); usart1_puts(" 512k flash, 64k ram ..........\n\r"); xTaskCreate(tadventure,"game",configMINIMAL_STACK_SIZE,NULL,configMAX_PRIORITIES-1,NULL); xTaskCreate(flasher,"flash",configMINIMAL_STACK_SIZE,NULL,configMAX_PRIORITIES-1,NULL); xTaskCreate(vT_usart, (const char*) "USART Task", configMINIMAL_STACK_SIZE, NULL, 1, NULL); vTaskStartScheduler(); while (1); return 0; }
三個task的處理函數:blog
static void flasher(void *arg __attribute__((unused))) { for (;;) { GPIO_ResetBits(GPIOA, GPIO_Pin_1); vTaskDelay(pdMS_TO_TICKS(400)); GPIO_SetBits(GPIOA, GPIO_Pin_1); vTaskDelay(pdMS_TO_TICKS(400)); } } static void tadventure(void *arg __attribute__((unused))) { { for (;;) { GPIO_ResetBits(GPIOA, GPIO_Pin_0); vTaskDelay(pdMS_TO_TICKS(1000)); GPIO_SetBits(GPIOA, GPIO_Pin_0); vTaskDelay(pdMS_TO_TICKS(1000)); } } static void vT_usart(void *p) { // Block for 500ms. const portTickType xDelay = 500 / portTICK_RATE_MS; for(;;) { usart1_puts("FreeRTOS V9.0.0 demo on STM32F103c8t6\r\n"); usart1_puts(" 64k flash, 20k ram ..........\r\n"); vTaskDelay(xDelay); } }
這裏的結果以下所示:
最大的問題就是一個是FreertosConfig.h文件設置錯誤致使的系統timer不對。 另外就是中斷的服務處理函數了,必定要換成本身的。