手把手教你在STM32F4上跑freeRTOS
之前挖了图解freeRTOS的坑,挖了坑就得填。今天就从使用开始,先把freeRTOS用起来。先聊一聊在STM32F407上的如何电灯,如果只用freeRTOS点灯,无疑有点杀鸡用牛刀的感觉。但是想用freeRTOS做产品,先照类似步骤则可以验证最小系统,验证freeRTOS是否能正确跑起来,再在此基础上开始做应用开发,就把任务分解了。本文主要梳理一下如何利用官方移植例子,创建一个自己demo工程,对于没用过的有点参考价值。
准备工作
tools为AWS iot配置工具,quick start例子以及cmake FreeRTOS-Plus包含了MQTT,TCP,FAT等很多例子,先不去管 FreeRTOS为真正的操作系统源码以及多平台移植例子,如下:
Demo:大部分硬件平台的官方移植例子 Source:内核代码,包含硬件独立文件与可移植文件 Test:内核测试代码 license:MIT开源协议,可以直接商业应用。
建立工程
设置工程 右键选择Options,进入设置界面 设置单片机为STM32F407VG
Library Configuration使能CMSIS
添加源文件 4.1 新建freeRTOS文件夹 4.2 添加内核文件,在工程文件夹下新建freeRTOS文件夹,将下列文件拷贝过来
4.4 将freeRTOS下的include文件夹以及portable文件夹拷贝到当前工程下
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ ( SystemCoreClock )
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES ( 5 )
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 130 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 75 * 1024 ) )
#define configMAX_TASK_NAME_LEN ( 10 )
#define configUSE_TRACE_FACILITY 1
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_MUTEXES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_MALLOC_FAILED_HOOK 0
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_COUNTING_SEMAPHORES 1
#define configGENERATE_RUN_TIME_STATS 0/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )/* Software timer definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( 2 )
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 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 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1将IDLE_HOOK/TICK_HOOK禁止了,先不去关注这两个功能。 将STM32相关文件搬过来,如下加入到工程
建立main.c 正点原子的板子,有两个LED,我们就建立两个任务来闪灯吧,相当于hello world,容易理解。 /* 操作系统头文件. */
#include 'FreeRTOS.h'
#include 'task.h'
#include 'timers.h'
#include 'semphr.h'#include 'stm32f4xx.h'
//LED管脚
#define LED1_PIN GPIO_Pin_9
#define LED1_GPIO_PORT GPIOF
#define LED1_GPIO_CLK RCC_AHB1Periph_GPIOF
#define LED2_PIN GPIO_Pin_10
#define LED2_GPIO_PORT GPIOF
#define LED2_GPIO_CLK RCC_AHB1Periph_GPIOFstatic void prvLedInitialise()
{
GPIO_InitTypeDef GPIO_InitStructure;
/* LED1时能时钟 */
RCC_AHB1PeriphClockCmd(LED1_GPIO_CLK, ENABLE);
/* LED1 GPIO 配置为输出 */
GPIO_InitStructure.GPIO_Pin = LED1_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure);
/* LED2时能时钟 */
RCC_AHB1PeriphClockCmd(LED2_GPIO_CLK, ENABLE);
/* LED2 GPIO配置为输出 */
GPIO_InitStructure.GPIO_Pin = LED2_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStructure);
}static void prvSetupHardware( void )
{
/* 配置时钟,PLL,FLASH */
SystemInit();/* 配置NVIC优先级. */
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
/*LED GPIO配置*/
prvLedInitialise();
}//500ms LED1灯状态翻转一次
static void led1Task( void * pvParameters )
{
while(1)
{
LED1_GPIO_PORT->ODR ^= LED1_PIN;
vTaskDelay(500);
}
}
//1000ms LED2灯状态翻转一次
static void led2Task( void * pvParameters )
{
while(1)
{
LED2_GPIO_PORT->ODR ^= LED2_PIN;
vTaskDelay(1000);
}
}int main(void)
{
prvSetupHardware();
xTaskCreate(led1Task,'LED1',256,NULL,100,(TaskHandle_t *)NULL);
xTaskCreate(led2Task,'LED2',256,NULL,101,(TaskHandle_t *)NULL);
/* 启动任务调度器. */
vTaskStartScheduler();
}
$PROJ_DIR$\
$PROJ_DIR$\hal\CMSIS\Device\ST\STM32F4xx\Include
$PROJ_DIR$\hal\STM32F4xx_StdPeriph_Driver\inc
$PROJ_DIR$\freeRTOS\include
$PROJ_DIR$\freeRTOS\portable\IAR\ARM_CM4F
$PROJ_DIR$\Common\include示当前工程目录,利用这个变量就可以设置和工程相关的路径了,不要设置为绝对路径,否则如果工程拷贝到其他路径,就无法正确编译了。并设置两个宏: USE_STDPERIPH_DRIVER
STM32F4XX
编译运行
总结一下
作者:逸珺
来源:嵌入式客栈