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,就可以干好多事情了.