基于stm32F407的hal库,移植FreeRTOS的具体步骤和遇到的问题(看正点原子的视频)

1. 资料准备

因为板子是stm32F407的第二版的,所以开始下的资料是旧版本的,但是旧版本的FreeRTOS工程没有hal库的,都是标准库的,这里是下载stm32F407最新版的资料,进行移植。

资料可以在正点原子官网下载,如下:
http://www.openedv.com/docs/boards/stm32/index.html
在这里插入图片描述
一定要下载最新的资料(开始用旧版本的移植不成功)。

准备stm32F407 hal库的 实验8 基本定时器实验和 实验37 内存管理实验两个工程,以及FreeRTOS的源码,以内存管理实验为模版,进行移植。

2. 实验流程

  1. 添加 FreeRTOS 源码
  2. 添加FreeRTOSConfig.h配置文件
  3. 修改SYSTEM文件
  4. 修改中断相关文件
  5. 添加应用程序
    在这里插入图片描述

2.1 添加 FreeRTOS 源码

在Middlewares文件夹中新建一个FreeRTOS文件夹,把FreeRTOS源码中的source中文件都拷贝到新建的FreeRTOS文件夹中,删去其余不是.c的文件。

在这里插入图片描述
portable文件夹里面的东西是连接软件层面的FreeRTOS 操作系统和硬件层面的芯片的桥梁,这里只保留portable文件夹中的RVDS、MemMang、Keil三个文件夹(因为stm32F4只用到这三个文件夹)。
在这里插入图片描述

2.2 将文件添加到工程

在工程中新建两个分组,Middlewares/FreeRTOS_CORE 和 Middlewares/FreeRTOS_PORT。

在这里插入图片描述
将.c文件添加到Middlewares/FreeRTOS_CORE 分组中。
在这里插入图片描述
将MemMang文件夹下的heap_4.c添加到Middlewares/FreeRTOS_PORT分组中。
在这里插入图片描述
将RVDS文件夹下的ARM_CM4F下的port.c添加到Middlewares/FreeRTOS_PORT分组中。
在这里插入图片描述

2.3 添加头文件路径

添加头文件路径FreeRTOS/include和port.c的文件路径。
在这里插入图片描述

2.4 添加 FreeRTOSConfig.h文件

在FreeRTOS的例程中找到该文件FreeRTOSConfig.h,放到移植工程即可,这里放到user文件夹中。
在这里插入图片描述
在这里插入图片描述

2.5 修改SYSTEM文件

  1. 修改sys.h文件
/**
 1. SYS_SUPPORT_OS用于定义系统文件夹是否支持OS
 2. 0,不支持OS
 3. 1,支持OS
 */
//#define SYS_SUPPORT_OS       0
#define SYS_SUPPORT_OS         1
  1. 修改usart.c 文件,删掉OSIntEnter()和 OSIntExit()两个函数
void USART_UX_IRQHandler(void)
{ 
    uint32_t timeout = 0;
    uint32_t maxDelay = 0x1FFFF;
//#if SYS_SUPPORT_OS                              /* 使用OS */
//    OSIntEnter();    
//#endif
    HAL_UART_IRQHandler(&g_uart1_handle);       /* 调用HAL库中断处理公用函数 */
    timeout = 0;
    while (HAL_UART_GetState(&g_uart1_handle) != HAL_UART_STATE_READY) /* 等待就绪 */
    {
        timeout++;                              /* 超时处理 */
        if(timeout > maxDelay)
        {
            break;
        }
    }
    timeout=0;
    /* 一次处理完成之后,重新开启中断并设置RxXferCount为1 */
    while (HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE) != HAL_OK)
    {
        timeout++;                              /* 超时处理 */
        if (timeout > maxDelay)
        {
            break;
        }
    }
//#if SYS_SUPPORT_OS                              /* 使用OS */
//    OSIntExit();
//#endif
}
  1. 将 usart.c中包含的关于 OS 的头文件删除
///* 如果使用os,则包括下面的头文件即可 */
//#if SYS_SUPPORT_OS
//#include "includes.h"                               /* os 使用 */
//#endif
  1. 修改delay.c 文件,删除如下代码
//static uint16_t g_fac_ms = 0;
///*
// *  当delay_us/delay_ms需要支持OS的时候需要三个与OS相关的宏定义和函数来支持
// *  首先是3个宏定义:
// *      delay_osrunning    :用于表示OS当前是否正在运行,以决定是否可以使用相关函数
// *      delay_ostickspersec:用于表示OS设定的时钟节拍,delay_init将根据这个参数来初始化systick
// *      delay_osintnesting :用于表示OS中断嵌套级别,因为中断里面不可以调度,delay_ms使用该参数来决定如何运行
// *  然后是3个函数:
// *      delay_osschedlock  :用于锁定OS任务调度,禁止调度
// *      delay_osschedunlock:用于解锁OS任务调度,重新开启调度
// *      delay_ostimedly    :用于OS延时,可以引起任务调度.
// *
// *  本例程仅作UCOSII和UCOSIII的支持,其他OS,请自行参考移植
// */
// 
///* 支持UCOSII */
//#ifdef  OS_CRITICAL_METHOD                      /* OS_CRITICAL_METHOD定义了,说明要支持UCOSII */
//#define delay_osrunning     OSRunning           /* OS是否运行标记,0,不运行;1,在运行 */
//#define delay_ostickspersec OS_TICKS_PER_SEC    /* OS时钟节拍,即每秒调度次数 */
//#define delay_osintnesting  OSIntNesting        /* 中断嵌套级别,即中断嵌套次数 */
//#endif

///* 支持UCOSIII */
//#ifdef  CPU_CFG_CRITICAL_METHOD                 /* CPU_CFG_CRITICAL_METHOD定义了,说明要支持UCOSIII */
//#define delay_osrunning     OSRunning           /* OS是否运行标记,0,不运行;1,在运行 */
//#define delay_ostickspersec OSCfg_TickRate_Hz   /* OS时钟节拍,即每秒调度次数 */
//#define delay_osintnesting  OSIntNestingCtr     /* 中断嵌套级别,即中断嵌套次数 */
//#endif

///**
// * @brief     us级延时时,关闭任务调度(防止打断us级延迟)
// * @param     无  
// * @retval    无
// */  
//void delay_osschedlock(void)
//{
//#ifdef CPU_CFG_CRITICAL_METHOD          /* 使用UCOSIII */
//    OS_ERR err;
//    OSSchedLock(&err);                  /* UCOSIII的方式,禁止调度,防止打断us延时 */
//#else                                   /* 否则UCOSII */
//    OSSchedLock();                      /* UCOSII的方式,禁止调度,防止打断us延时 */
//#endif
//}

///**
// * @brief     us级延时时,恢复任务调度
// * @param     无
// * @retval    无
// */  
//void delay_osschedunlock(void)
//{
//#ifdef CPU_CFG_CRITICAL_METHOD          /* 使用UCOSIII */
//    OS_ERR err;
//    OSSchedUnlock(&err);                /* UCOSIII的方式,恢复调度 */
//#else                                   /* 否则UCOSII */
//    OSSchedUnlock();                    /* UCOSII的方式,恢复调度 */
//#endif
//}

///**
// * @brief     us级延时时,恢复任务调度
// * @param     ticks : 延时的节拍数
// * @retval    无
// */  
//void delay_ostimedly(uint32_t ticks)
//{
//#ifdef CPU_CFG_CRITICAL_METHOD
//    OS_ERR err; 
//    OSTimeDly(ticks, OS_OPT_TIME_PERIODIC, &err);   /* UCOSIII延时采用周期模式 */
//#else
//    OSTimeDly(ticks);                               /* UCOSII延时 */
//#endif 
//}

  1. 添加 FreeRTOS 的相关代码(在delay.c文件中)
extern void xPortSysTickHandler(void);
  1. 修改SysTick_Handler()函数
void SysTick_Handler(void)
{
    HAL_IncTick();
//    if (delay_osrunning == 1)       /* OS开始跑了,才执行正常的调度处理 */
//    {
//        OSIntEnter();               /* 进入中断 */
//        OSTimeTick();               /* 调用ucos的时钟服务程序 */
//        OSIntExit();                /* 触发任务切换软中断 */
//    }
	/* OS 开始跑了,才执行正常的调度处理 */
    if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
      {
         xPortSysTickHandler();
      }
}
  1. 修改delay_init()函数
void delay_init(uint16_t sysclk)
{
reload *= 1000000 / configTICK_RATE_HZ;
//    g_fac_ms = 1000 / delay_ostickspersec; 
}
 /* 删除不用的 g_fac_ms 相关代码 */
  1. 修改delay_us()函数
void delay_us(uint32_t nus)
{
   // delay_osschedlock();                    /* 阻止OS调度,防止打断us延时 */
   // delay_osschedunlock();                  /* 恢复OS调度 */
}
  1. 修改delay_ms()函数
void delay_ms(uint16_t nms)
{
//    if (delay_osrunning && delay_osintnesting == 0)     /* 如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度) */
//    {
//        if (nms >= g_fac_ms)                            /* 延时的时间大于OS的最少时间周期 */
//        { 
//            delay_ostimedly(nms / g_fac_ms);            /* OS延时 */
//        }
//        nms %= g_fac_ms;                                /* OS已经无法提供这么小的延时了,采用普通方式延时 */
//    }                                        
//    delay_us((uint32_t)(nms * 1000));                   /* 普通方式延时 */
	uint32_t i;
 
 for (i=0; i<nms; i++)
 {
 delay_us(1000);
 }
}
  1. 包含头文件
/* 添加公共头文件 ( ucos需要用到) */
//#include "includes.h"
#include "FreeRTOS.h"
#include "task.h"
  1. 修改中断相关文件,修改stm32f4xx_it.c文件
//void SVC_Handler(void)
//{
//}

//void PendSV_Handler(void)
//{
//}

//void SysTick_Handler(void)
//{
//  HAL_IncTick();
//}
  1. 修改FreeRTOSConfig.h文件。
#define configPRIO_BITS __NVIC_PRIO_BITS
//#define __NVIC_PRIO_BITS            4U     
#define __NVIC_PRIO_BITS              4 

2.6 移除USMART调试组件

因为没有使用到 USMART 调试组件,所以把这个组件删掉。
在这里插入图片描述

注释掉main.c中的有关USMART代码。

//#include "./USMART/usmart.h"
//int main(void){
//    usmart_dev.init(84);                /* 初始化USMART */
}

2.7 添加定时器驱动

把基本定时器工程中的TIMER文件夹,复制到移植工程中的BSP文件夹中。
在这里插入图片描述
在这里插入图片描述
将定时器的相关驱动文件添加到工程的 Drivers/BSP 文件分组中。
在这里插入图片描述

3. 实验验证

把FreeRTOS例程中的demo复制到移植工程中User中。
在这里插入图片描述
在这里插入图片描述

将demo的驱动文件添加到工程的User文件分组中。

在这里插入图片描述

删减之后的部分代码如下:

int main(void)
{
 HAL_Init(); /* 初始化 HAL 库 */
 sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
 delay_init(72); /* 延时初始化 */
 usart_init(115200); /* 串口初始化为 115200 */
 led_init(); /* 初始化 LED */
 lcd_init(); /* 初始化 LCD */
 key_init(); /* 初始化按键 */
 sram_init(); /* SRAM 初始化 */
 my_mem_init(SRAMIN); /* 初始化内部 SRAM 内存池 */
 my_mem_init(SRAMEX); /* 初始化外部 SRAM 内存池 */
 freertos_demo(); /* 运行 FreeRTOS 例程 */
}
void freertos_demo(void)
{
    xTaskCreate((TaskFunction_t )start_task,            /* 任务函数 */
                (const char*    )"start_task",          /* 任务名称 */
                (uint16_t       )START_STK_SIZE,        /* 任务堆栈大小 */
                (void*          )NULL,                  /* 传入给任务函数的参数 */
                (UBaseType_t    )START_TASK_PRIO,       /* 任务优先级 */
                (TaskHandle_t*  )&StartTask_Handler);   /* 任务句柄 */
    vTaskStartScheduler();
}

void task1(void *pvParameters)
{
    while(1)
    {
        LED0_TOGGLE();                                                  /* LED0闪烁 */
        vTaskDelay(1000);                                               /* 延时1000ticks */
    }
}
void task2(void *pvParameters)
{
    while(1)
    {
       		 LED1_TOGGLE();                                         /* LED1闪烁 */
			 vTaskDelay(500);                                      /* 延时500ticks */
			 
    }
}

把程序烧到开发板中,实验结果如下,可以看到与预设程序一致,红色LED,1000ms亮灭一次,蓝色LED,500ms亮灭一次(可以在如下视频看到)。

FreeRTOS移植

4. 总结

  1. 遇到如下报大量语法错误,原因是keil编译器问题,把编译器的版本设置为V5即可。
    在这里插入图片描述
    在这里插入图片描述
  2. 最后把程序烧到开发板中,如果LED灯没有亮,复位几次,观察LED是否亮。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值