FreeRTOS应该是我见过最好移植的RTOS系统了,不会像uCos一样可能要修改一些库文件,危险性比较大.要下载FreeRTOS的最新源码可以到这个地址:https://sourceforge.net/projects/freertos/files/latest/download?source=files 当然,作为新手做实验可以下载我这个版本的,当然,为了方便上传,几百MB的DEMO已经去掉了,要完整还是去官网下载哈.下载地址:FreeRTOSV8.2.3
对了,做这个实验,用F407做简单演示,虽然我有F429,但是没现成比较干净的工程,所以,先这么干.移植很简单,把FreeRTOSV8.2.3FreeRTOSSourceportableRVDS目录下ARM_CM4F的port.c和portmacro.h,复制出来.再把内存管理算法FreeRTOSV8.2.3FreeRTOSSourceportableMemMang目录下heap_2.c复制出来,再把FreeRTOSV8.2.3FreeRTOSSource下的list.c,queue.c,tasks.c复制出来,这都是功能,当然还有timers.c这些也都是功能.但是暂时用不上.最后把FreeRTOSV8.2.3FreeRTOSSourceinclude所有文件复制出来,对了,还有一个比较重要的,可裁剪配置项.FreeRTOSConfig.h,这个文件本来应该人为创建,但是有官方参考:FreeRTOSConfig (<-使劲戳)
网上不少参考说要修改startup文件,新版已经不用了.只要到stm32f4xx_it.c删掉冲突的中断函数就可以了.再把刚才复制到的文件,引用到项目里面,就可以了.目前目录规模:
├─Application
│ └─main
├─Drivers
├─RTOS
│ ├─Include
│ └─Source
└─STM32_FWLib
├─CMSIS
│ └─startup
└─FWLib
├─inc
└─src
工程规模:
至此,编译,即可得到跑RTOS的工程.这个不用我们自己SysTick初始化哦,我们加入一个LED一闪一闪亮晶晶的程序.首先要声明一个队列,xQueueHandle类型的变量.当然,之前假定你已经初始化了LED的IO哦,程序如下:
static xQueueHandle xQueue = NULL; /* 发送任务与接收任务之间传送的数据 */ #define mainQUEUE_SEND_PARAMETER ( 0x1111UL ) #define mainQUEUE_RECEIVE_PARAMETER ( 0x22UL ) /* 向队列发送数据的频率。利用portTICK_RATE_MS将200ms转换为ticks数目*/ #define mainQUEUE_SEND_FREQUENCY_MS ( 2000 / portTICK_RATE_MS ) #define mainQUEUE_RECEIVE_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 ) #define mainQUEUE_SEND_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 ) static void prvQueueReceiveTask( void *pvParameters ) { unsigned long ulReceivedValue; /* 参数检查 */ configASSERT( ( ( unsigned long ) pvParameters ) == mainQUEUE_RECEIVE_PARAMETER ); for( ;; ) { /* 等待数据到达队列 - 如果在FreeRTOSConfig.h中将INCLUDE_vTaskSuspend置1。 该任务将永远阻塞*/ xQueueReceive( xQueue, &ulReceivedValue, portMAX_DELAY ); /* 如果队列中有数据,将其读出并检查其值是否正确 */ if( ulReceivedValue == 100UL ) { taskENTER_CRITICAL(); GPIO_ToggleBits(GPIOD,GPIO_Pin_12); taskEXIT_CRITICAL(); ulReceivedValue = 0U; } } } static void prvQueueSendTask( void *pvParameters ) { portTickType xNextWakeTime; const unsigned long ulValueToSend = 100UL; /* 参数检查 */ configASSERT( ( ( unsigned long ) pvParameters ) == mainQUEUE_SEND_PARAMETER ); /* 初始化xNextWakeTime(只做一次). */ xNextWakeTime = xTaskGetTickCount(); for( ;; ) { /* 将任务置于阻塞状态200ms,此时该任务不占用任何CPU时间此处使用 vTaskDelayUntil API函数可以保证任务被阻塞的时间恒定为200ms左右*/ vTaskDelayUntil( &xNextWakeTime, mainQUEUE_SEND_FREQUENCY_MS ); /* 将数据发送至队列 - 队列接收任务开启并切换LED显示。由于发送数据时,队列为空, 所以阻塞时间可以设置为0。*/ xQueueSend( xQueue, &ulValueToSend, 0U ); } } void LED_Toggle( void ) { /* 创建队列*/ xQueue = xQueueCreate( 1, sizeof( unsigned long ) ); if( xQueue != NULL ) { /* 创建任务 */ xTaskCreate( prvQueueReceiveTask, /* 执行任务的函数 */ ( const char * ) "Rx", /* 任务名称,主要用于调试 */ configMINIMAL_STACK_SIZE, /* 分配给任务的堆栈大小 */ ( void * ) mainQUEUE_RECEIVE_PARAMETER, /* 传递给任务的参数 */ mainQUEUE_RECEIVE_TASK_PRIORITY, /* 分内给任务的句柄 */ NULL ); /* 任务句柄,此处设置为NULL */ xTaskCreate( prvQueueSendTask, ( const char * ) "TX", configMINIMAL_STACK_SIZE, ( void * ) mainQUEUE_SEND_PARAMETER, mainQUEUE_SEND_TASK_PRIORITY, NULL ); /* 启动任务调度器 */ vTaskStartScheduler(); } /* 在调度器正常运行时,程序不会执行到此处。如果程序运行到这里,则说明 FreeRTOS分配给空闲任务和定时器任务的堆空间不足 */ for( ;; ); }
如此,我们有了RTOS,就可以干好多事情了.