基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(二)FreeRTOS v9.0.0 的移植

来源:互联网 发布:什么是php网站 编辑:程序博客网 时间:2024/06/06 06:31

本文详细绍了基于STM32F107VC的金牛开发板的FreeRTOS v9.0.0 的移植过程。

**IDE环境为: MDK v5.23;
硬件环境:基于STM32F107VC的金牛开发板;
所用固件库版本号是STM32F10X_StdPeriph_Lib_V3.5.0**

下载工具用的是开发板自带的D版的Jlink。

一、工程模板的建立:

(参考:http://blog.csdn.net/u014563989/article/details/51000138)
STM32工程模板用野火M3工程模板作为基础,在此之上做一些更改:
下载地址:https://pan.baidu.com/share/link?shareid=4218340238&uk=1194094710&fid=909646254491523

这里写图片描述

然后改一下文件名为STM32F107_FreeRTOS_v9.0.0:

这里写图片描述

进去之后看到:

这里写图片描述

其结构内容如下:
CMSIS:微控制器软件接口标准库相关文件(详细解释请参考:http://blog.chinaunix.net/uid-27710926-id-4231846.html);
FWlib:固件库(版本号为v3.5.0);
Listing:编译链接信息列表;
Output:编译中间文件和bin档(或hex档)。
USER:工程模板和用户源代码。

下面对它的目录结构做如下修改:
1、把USER文件夹改为project,意为此处放置工程文件,而不是放源代码;
2、增加BSP文件夹,作为板卡支持包目录,放置与开发板特定配置下的相关源代码;
3、增加APP文件夹,作为应用软件源代码目录;
4、增加third_party文件夹,作为第三方库管理目录,放置第三方库源码。

改后目录结构如图:

这里写图片描述

接下来,把相应文件做调整,并修改工名:
把project目录下的main.c、stm32f10x_conf.h、stm32f10x_it.h、stm32f10x_it.h四个文件剪切到BSP目录下:

这里写图片描述

project目录下只留下扩展名为.uvopt和.ubproj的两个文件,其他的都删除:

这里写图片描述

然后把两个文件都改名为FreeRTOS_v9.0.0,如图:

这里写图片描述

接下来双击FreeRTOS_v9.0.0.uvproj文件,打开工程:

这里写图片描述

点击品字形图标:

这里写图片描述

看到如下对话框:

这里写图片描述

然后双击左边那个Target1,改名为FreeRTOS_v9.0.0:

这里写图片描述

中间的列表删掉STARTUPCODE,双击修改USER为BSP,并在右边的列表中的main.c和stm32f10x_it.c文件删除,重新加入(两个文件已经由前面的步骤放置在了电脑的BSP目录下):

这里写图片描述

然后,把金牛板的启动文件STM32F10x.s修改一下放置在BSP目录下,该文件内容如下:

;/*****************************************************************************/;/* STM32F10x.s: Startup file for ST STM32F10x device series                  */;/*****************************************************************************/;/* <<< Use Configuration Wizard in Context Menu >>>                          */;/*****************************************************************************/;/* This file is part of the uVision/ARM development tools.                   */;/* Copyright (c) 2005-2007 Keil Software. All rights reserved.               */;/* This software may only be used under the terms of a valid, current,       */;/* end user licence from KEIL for a compatible version of KEIL software      */;/* development tools. Nothing else gives you the right to use this software. */;/*****************************************************************************/;// <h> Stack Configuration;//   <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>;// </h>Stack_Size      EQU     0x00000400                AREA    STACK, NOINIT, READWRITE, ALIGN=3Stack_Mem       SPACE   Stack_Size__initial_sp;// <h> Heap Configuration;//   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>;// </h>Heap_Size       EQU     0x00000200                AREA    HEAP, NOINIT, READWRITE, ALIGN=3__heap_baseHeap_Mem        SPACE   Heap_Size__heap_limit                ;IMPORT xPortPendSVHandler                ;IMPORT xPortSysTickHandler                ;IMPORT vPortSVCHandler                ;IMPORT vUARTInterruptHandler                ;IMPORT TIM4_IRQHandler                ;IMPORT vTimer2IntHandler                PRESERVE8                THUMB; Vector Table Mapped to Address 0 at Reset                AREA    RESET, DATA, READONLY                EXPORT  __Vectors                EXPORT  __Vectors_End                EXPORT  __Vectors_Size__Vectors       DCD     __initial_sp              ; Top of Stack                DCD     Reset_Handler             ; Reset Handler                DCD     NMI_Handler               ; NMI Handler                DCD     HardFault_Handler         ; Hard Fault Handler                DCD     MemManage_Handler         ; MPU Fault Handler                DCD     BusFault_Handler          ; Bus Fault Handler                DCD     UsageFault_Handler        ; Usage Fault Handler                DCD     0                         ; Reserved                DCD     0                         ; Reserved                DCD     0                         ; Reserved                DCD     0                         ; Reserved                DCD     0                         ;vPortSVCHandler           ; SVCall Handler                DCD     DebugMon_Handler          ; Debug Monitor Handler                DCD     0                         ; Reserved                DCD     0                         ;xPortPendSVHandler        ; PendSV Handler                DCD     0                         ;xPortSysTickHandler       ; SysTick Handler                ; External Interrupts                DCD     WWDG_IRQHandler           ; Window Watchdog                DCD     PVD_IRQHandler            ; PVD through EXTI Line detect                DCD     TAMPER_IRQHandler         ; Tamper                DCD     RTC_IRQHandler            ; RTC                DCD     FLASH_IRQHandler          ; Flash                DCD     RCC_IRQHandler            ; RCC                DCD     EXTI0_IRQHandler          ; EXTI Line 0                DCD     EXTI1_IRQHandler          ; EXTI Line 1                DCD     EXTI2_IRQHandler          ; EXTI Line 2                DCD     EXTI3_IRQHandler          ; EXTI Line 3                DCD     EXTI4_IRQHandler          ; EXTI Line 4                DCD     DMAChannel1_IRQHandler    ; DMA Channel 1                DCD     DMAChannel2_IRQHandler    ; DMA Channel 2                DCD     DMAChannel3_IRQHandler    ; DMA Channel 3                DCD     DMAChannel4_IRQHandler    ; DMA Channel 4                DCD     DMAChannel5_IRQHandler    ; DMA Channel 5                DCD     DMAChannel6_IRQHandler    ; DMA Channel 6                DCD     DMAChannel7_IRQHandler    ; DMA Channel 7                DCD     ADC_IRQHandler            ; ADC                DCD     USB_HP_CAN_TX_IRQHandler  ; USB High Priority or CAN TX                DCD     USB_LP_CAN_RX0_IRQHandler ; USB Low  Priority or CAN RX0                DCD     CAN_RX1_IRQHandler        ; CAN RX1                DCD     CAN_SCE_IRQHandler        ; CAN SCE                DCD     EXTI9_5_IRQHandler        ; EXTI Line 9..5                DCD     TIM1_BRK_IRQHandler       ; TIM1 Break                DCD     TIM1_UP_IRQHandler        ; TIM1 Update                DCD     TIM1_TRG_COM_IRQHandler   ; TIM1 Trigger and Commutation                DCD     TIM1_CC_IRQHandler        ; TIM1 Capture Compare                ;                DCD     0                         ;vTimer2IntHandler         ; TIM2                DCD     TIM3_IRQHandler           ; TIM3                DCD     0                         ;TIM4_IRQHandler           ; TIM4                DCD     I2C1_EV_IRQHandler        ; I2C1 Event                DCD     I2C1_ER_IRQHandler        ; I2C1 Error                DCD     I2C2_EV_IRQHandler        ; I2C2 Event                DCD     I2C2_ER_IRQHandler        ; I2C2 Error                DCD     SPI1_IRQHandler           ; SPI1                DCD     SPI2_IRQHandler           ; SPI2                DCD     0                         ;vUARTInterruptHandler     ; USART1                DCD     USART2_IRQHandler         ; USART2                DCD     USART3_IRQHandler         ; USART3                DCD     EXTI15_10_IRQHandler      ; EXTI Line 15..10                DCD     RTCAlarm_IRQHandler       ; RTC Alarm through EXTI Line                DCD     USBWakeUp_IRQHandler      ; USB Wakeup from suspend                ;-------------------added @2017.08.1                DCD     0                          ; Reserved                DCD     0                          ; Reserved                DCD     0                          ; Reserved                DCD     0                          ; Reserved                DCD     0                          ; Reserved                DCD     0                          ; Reserved                DCD     0                          ; Reserved                DCD     TIM5_IRQHandler            ; TIM5                DCD     SPI3_IRQHandler            ; SPI3                DCD     UART4_IRQHandler           ; UART4                DCD     UART5_IRQHandler           ; UART5                DCD     TIM6_IRQHandler            ; TIM6                DCD     TIM7_IRQHandler            ; TIM7                DCD     DMA2_Channel1_IRQHandler   ; DMA2 Channel1                DCD     DMA2_Channel2_IRQHandler   ; DMA2 Channel2                DCD     DMA2_Channel3_IRQHandler   ; DMA2 Channel3                DCD     DMA2_Channel4_IRQHandler   ; DMA2 Channel4                DCD     DMA2_Channel5_IRQHandler   ; DMA2 Channel5                DCD     0                          ;ETH_IRQHandler             ; Ethernet                DCD     ETH_WKUP_IRQHandler        ; Ethernet Wakeup through EXTI line                DCD     CAN2_TX_IRQHandler         ; CAN2 TX                DCD     CAN2_RX0_IRQHandler        ; CAN2 RX0                DCD     CAN2_RX1_IRQHandler        ; CAN2 RX1                DCD     CAN2_SCE_IRQHandler        ; CAN2 SCE                DCD     OTG_FS_IRQHandler          ; USB OTG FS__Vectors_End__Vectors_Size  EQU  __Vectors_End - __Vectors                AREA    |.text|, CODE, READONLY; Reset handlerReset_Handler   PROC                EXPORT  Reset_Handler             [WEAK]        IMPORT  SystemInit                IMPORT  __main                 LDR     R0, =SystemInit                 BLX     R0                LDR     R0, =__main                BX      R0                ENDP; Dummy Exception Handlers (infinite loops which can be modified)                NMI_Handler     PROC                EXPORT  NMI_Handler               [WEAK]                B       .                ENDPHardFault_Handler\                PROC                EXPORT  HardFault_Handler         [WEAK]                B       .                ENDPMemManage_Handler\                PROC                EXPORT  MemManage_Handler         [WEAK]                B       .                ENDPBusFault_Handler\                PROC                EXPORT  BusFault_Handler          [WEAK]                B       .                ENDPUsageFault_Handler\                PROC                EXPORT  UsageFault_Handler        [WEAK]                B       .                ENDPSVC_Handler     PROC                EXPORT  SVC_Handler               [WEAK]                B       .                ENDPDebugMon_Handler\                PROC                EXPORT  DebugMon_Handler          [WEAK]                B       .                ENDPPendSV_Handler  PROC                EXPORT  PendSV_Handler            [WEAK]                B       .                ENDPSysTick_Handler PROC                EXPORT  SysTick_Handler           [WEAK]                B       .                ENDPDefault_Handler PROC                EXPORT  WWDG_IRQHandler           [WEAK]                EXPORT  PVD_IRQHandler            [WEAK]                EXPORT  TAMPER_IRQHandler         [WEAK]                EXPORT  RTC_IRQHandler            [WEAK]                EXPORT  FLASH_IRQHandler          [WEAK]                EXPORT  RCC_IRQHandler            [WEAK]                EXPORT  EXTI0_IRQHandler          [WEAK]                EXPORT  EXTI1_IRQHandler          [WEAK]                EXPORT  EXTI2_IRQHandler          [WEAK]                EXPORT  EXTI3_IRQHandler          [WEAK]                EXPORT  EXTI4_IRQHandler          [WEAK]                EXPORT  DMAChannel1_IRQHandler    [WEAK]                EXPORT  DMAChannel2_IRQHandler    [WEAK]                EXPORT  DMAChannel3_IRQHandler    [WEAK]                EXPORT  DMAChannel4_IRQHandler    [WEAK]                EXPORT  DMAChannel5_IRQHandler    [WEAK]                EXPORT  DMAChannel6_IRQHandler    [WEAK]                EXPORT  DMAChannel7_IRQHandler    [WEAK]                EXPORT  ADC_IRQHandler            [WEAK]                EXPORT  USB_HP_CAN_TX_IRQHandler  [WEAK]                EXPORT  USB_LP_CAN_RX0_IRQHandler [WEAK]                EXPORT  CAN_RX1_IRQHandler        [WEAK]                EXPORT  CAN_SCE_IRQHandler        [WEAK]                EXPORT  EXTI9_5_IRQHandler        [WEAK]                EXPORT  TIM1_BRK_IRQHandler       [WEAK]                EXPORT  TIM1_UP_IRQHandler        [WEAK]                EXPORT  TIM1_TRG_COM_IRQHandler   [WEAK]                EXPORT  TIM1_CC_IRQHandler        [WEAK]                EXPORT  TIM2_IRQHandler           [WEAK]                EXPORT  TIM3_IRQHandler           [WEAK]                ;EXPORT  TIM4_IRQHandler           [WEAK]                EXPORT  I2C1_EV_IRQHandler        [WEAK]                EXPORT  I2C1_ER_IRQHandler        [WEAK]                EXPORT  I2C2_EV_IRQHandler        [WEAK]                EXPORT  I2C2_ER_IRQHandler        [WEAK]                EXPORT  SPI1_IRQHandler           [WEAK]                EXPORT  SPI2_IRQHandler           [WEAK]                EXPORT  USART1_IRQHandler         [WEAK]                EXPORT  USART2_IRQHandler         [WEAK]                EXPORT  USART3_IRQHandler         [WEAK]                EXPORT  EXTI15_10_IRQHandler      [WEAK]                EXPORT  RTCAlarm_IRQHandler       [WEAK]                EXPORT  USBWakeUp_IRQHandler      [WEAK]                ;-------------added @2017.08.13-----------------------------                EXPORT  TIM5_IRQHandler            [WEAK]                EXPORT  SPI3_IRQHandler            [WEAK]                EXPORT  UART4_IRQHandler           [WEAK]                EXPORT  UART5_IRQHandler           [WEAK]                EXPORT  TIM6_IRQHandler            [WEAK]                EXPORT  TIM7_IRQHandler            [WEAK]                EXPORT  DMA2_Channel1_IRQHandler   [WEAK]                EXPORT  DMA2_Channel2_IRQHandler   [WEAK]                EXPORT  DMA2_Channel3_IRQHandler   [WEAK]                EXPORT  DMA2_Channel4_IRQHandler   [WEAK]                EXPORT  DMA2_Channel5_IRQHandler   [WEAK]                EXPORT  ETH_IRQHandler             [WEAK]                EXPORT  ETH_WKUP_IRQHandler        [WEAK]                EXPORT  CAN2_TX_IRQHandler         [WEAK]                EXPORT  CAN2_RX0_IRQHandler        [WEAK]                EXPORT  CAN2_RX1_IRQHandler        [WEAK]                EXPORT  CAN2_SCE_IRQHandler        [WEAK]                EXPORT  OTG_FS_IRQHandler          [WEAK]WWDG_IRQHandlerPVD_IRQHandlerTAMPER_IRQHandlerRTC_IRQHandlerFLASH_IRQHandlerRCC_IRQHandlerEXTI0_IRQHandlerEXTI1_IRQHandlerEXTI2_IRQHandlerEXTI3_IRQHandlerEXTI4_IRQHandlerDMAChannel1_IRQHandlerDMAChannel2_IRQHandlerDMAChannel3_IRQHandlerDMAChannel4_IRQHandlerDMAChannel5_IRQHandlerDMAChannel6_IRQHandlerDMAChannel7_IRQHandlerADC_IRQHandlerUSB_HP_CAN_TX_IRQHandlerUSB_LP_CAN_RX0_IRQHandlerCAN_RX1_IRQHandlerCAN_SCE_IRQHandlerEXTI9_5_IRQHandlerTIM1_BRK_IRQHandlerTIM1_UP_IRQHandlerTIM1_TRG_COM_IRQHandlerTIM1_CC_IRQHandlerTIM2_IRQHandlerTIM3_IRQHandler;TIM4_IRQHandlerI2C1_EV_IRQHandlerI2C1_ER_IRQHandlerI2C2_EV_IRQHandlerI2C2_ER_IRQHandlerSPI1_IRQHandlerSPI2_IRQHandlerUSART1_IRQHandlerUSART2_IRQHandlerUSART3_IRQHandlerEXTI15_10_IRQHandlerRTCAlarm_IRQHandlerUSBWakeUp_IRQHandler;---------added  @2017.08.13--------------------------TIM5_IRQHandlerSPI3_IRQHandlerUART4_IRQHandlerUART5_IRQHandlerTIM6_IRQHandlerTIM7_IRQHandlerDMA2_Channel1_IRQHandlerDMA2_Channel2_IRQHandlerDMA2_Channel3_IRQHandlerDMA2_Channel4_IRQHandlerDMA2_Channel5_IRQHandlerETH_IRQHandlerETH_WKUP_IRQHandlerCAN2_TX_IRQHandlerCAN2_RX0_IRQHandlerCAN2_RX1_IRQHandlerCAN2_SCE_IRQHandlerOTG_FS_IRQHandler                B       .                ENDP                ALIGN; User Initial Stack & Heap                IF      :DEF:__MICROLIB                EXPORT  __initial_sp                EXPORT  __heap_base                EXPORT  __heap_limit                ELSE                IMPORT  __use_two_region_memory                EXPORT  __user_initial_stackheap__user_initial_stackheap                LDR     R0, =  Heap_Mem                LDR     R1, =(Stack_Mem + Stack_Size)                LDR     R2, = (Heap_Mem +  Heap_Size)                LDR     R3, = Stack_Mem                BX      LR                ALIGN                ENDIF                END

该文件会在以后的使用中,为启用某些中断或者修改堆栈设置做修改,暂且如此。

然后把该文件加入工程中,放置在BSP管理项中:

这里写图片描述

此文件代替了原野火模板中的startup_stm32f10x_hd.s启动文件。
并且,查询资料可知STM32F107VC这款芯片属于cl版本,因此,需要cl版的启动文件。
金牛版的stm32F10x.s就是这个版本的。
并且,原野火模板目标芯片是STM32F103VE,跟我的板子不匹配,需要修改。
另外,在编译配置中需要修改全局宏定义以跟CL版相匹配。
点击魔法棒的那个图标(目标选项),做如下修改:

在Device选项卡里面选STM32F107VC:

这里写图片描述

在Target选项卡中选择Use MicroLIB

这里写图片描述

在C/C++选项卡里面的
Proprecessor Symbols设置项的Define栏,修改STM32F10X_HD为STM32F10X_CL:

这里写图片描述

然后就是修改include搜索目录:
点击Include Paths设置项右边的省略号按钮看到:

这里写图片描述

双击USER,修改为BSP。

然后修改一下编译输出文件名和相关设置,点击Output选项卡,设置如下:

这里写图片描述

修改完之后,编译一下,通过,OK。

接下来,用金牛版的跑马灯的代码验证一下能否正让开发板常工作。
修改整个main.c文件如下:

/******************** (C) COPYRIGHT 2012 WildFire Team ************************** * ÎļþÃû  £ºmain.c * ÃèÊö    £ºÓÃ3.5.0°æ±¾½¨µÄ¹¤³ÌÄ£°å¡£          * ʵÑéƽ̨£ºÒ°»ðSTM32¿ª·¢°å * ¿â°æ±¾  £ºST3.5.0 * * ×÷Õß    £ºwildfire team  * ÂÛ̳    £ºhttp://www.amobbs.com/forum-1008-1.html * ÌÔ±¦    £ºhttp://firestm32.taobao.com**********************************************************************************/#include "stm32f10x.h"void GPIO_Configuration(void){    GPIO_InitTypeDef GPIO_InitStructure;    /* Configure IO connected to LD1, LD2, LD3 and LD4 leds *********************/      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_7;    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    GPIO_Init(GPIOD, &GPIO_InitStructure);}//??????void NVIC_Configuration(void){     /* Configure the NVIC Preemption Priority Bits */      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);    #ifdef  VECT_TAB_RAM        /* Set the Vector Table base location at 0x20000000 */       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);     #else  /* VECT_TAB_FLASH  */      /* Set the Vector Table base location at 0x08000000 */       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);       #endif}void RCC_Configuration(void){    SystemInit();       RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA                            |RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC                           |RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE                           |RCC_APB2Periph_ADC1  | RCC_APB2Periph_AFIO                            |RCC_APB2Periph_SPI1, ENABLE );  // RCC_APB2PeriphClockCmd(RCC_APB2Periph_ALL ,ENABLE );     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4                            |RCC_APB1Periph_USART3|RCC_APB1Periph_TIM2                                                         , ENABLE );     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);}void Init_All_Periph(void){    RCC_Configuration();        GPIO_Configuration();    NVIC_Configuration();}void Delay(vu32 nCount){  for(; nCount != 0; nCount--);}int main(void){      Init_All_Periph();    while(1)    {        /* Turn on LD1 */        GPIO_SetBits(GPIOD, GPIO_Pin_2);        /* Insert delay */        Delay(0xAFFFF);        /* Turn on LD2 and LD3 */        GPIO_SetBits(GPIOD, GPIO_Pin_3 | GPIO_Pin_4);        /* Turn off LD1 */        GPIO_ResetBits(GPIOD, GPIO_Pin_2);        /* Insert delay */        Delay(0xAFFFF);        /* Turn on LD4 */        GPIO_SetBits(GPIOD, GPIO_Pin_7);        /* Turn off LD2 and LD3 */        GPIO_ResetBits(GPIOD, GPIO_Pin_4 | GPIO_Pin_3);        /* Insert delay */        Delay(0xAFFFF);        /* Turn off LD4 */        GPIO_ResetBits(GPIOD, GPIO_Pin_7);      }}/******************* (C) COPYRIGHT 2012 WildFire Team *****END OF FILE************/

ok,已经编译出来hex可执行文件啦。

用Jlink把hex档烧到开发板上,然后重新上电,跑马灯炮起来了!

为STM32F107芯片的金牛开发板建立原始模板完成了!

以上作为一个版本,源代码下载地址:
STM32F107_FreeRTOS_v9.0.0_V3.5.0固件库原始模板.rar

二、移植FreeRTOS v9.0.0

1、操作系统基础性移植

参考文章:
1、http://blog.csdn.net/ZCShouCSDN/article/details/54667930
2、http://www.cnblogs.com/foxclever/p/5784326.html
3、https://andyhuzhill.github.io/freertos/2013/07/30/freertostransplant
4、http://blog.csdn.net/zhzht19861011/article/details/50134883

FreeRTOS最新版目前为v9.0.0,下载地址:https://sourceforge.net/projects/freertos/files/latest/download?source=files

下载后,解压看到:
这里写图片描述

我们所需要的源码在FreeRTOS\Source目录下:

这里写图片描述

把整个文件夹复制一份到我们工程根目录下,并更名为FreeRTOS:

这里写图片描述

在IDE工程里对FreeRTOS_v9.0.0右击添加两个组一个命名为FreeRTOS/Source,另一个命名为FreeRTOS/Ports

这里写图片描述

在FreeRTOS/Source组中添加刚复制过来的FreeRTOS源代码目录下的croutine.c、event_groups.c、list.c、queue.c、tasks.c这五个文件:

这里写图片描述

在 组中加入port.c和heap_4.c(为什么用heap_4.c可以参考本部分的第2篇参考文章)这两个文件,它们所在的路径为:
port在FreeRTOS\portable\RVDS\ARM_CM3下;
heap_4.c在FreeRTOS\portable\MemMang下。

这里写图片描述

接下来,需要修改include的路径:
如上述修改include路径一样,点魔法棒,选c/c++选项卡,加入
FreeRTOS\include
FreeRTOS\portable\RVDS\ARM_CM3

这两个目录:
这里写图片描述

至此,FreeRTOS主要部分已经完成,但是此时编译的话,会出错,提示缺少FreeRTOSConfig.h这个文件,这个文件在哪里呢?在FreeRTOS官方源代码的各个Demo中。

由于本文使用的芯片是STM32F107VC,所以,它在官方源代码的FreeRTOSv9.0.0\FreeRTOS\Demo\CORTEX_STM32F107_GCC_Rowley目录中:

这里写图片描述

跟FreeRTOS配置相关的文件还包括STM32F10x.s、timertest.c。
把这三个文件复制到我们BSP目录下:

这里写图片描述

还要修改一下timertest.c里面的内容:

注释掉:

#include "stm32f10x_lib.h"#include "stm32f10x_map.h"

这两行。

把147行的TIM2_IRQChannel改为TIM2_IRQn,不然编译会出错。因为固件库的命名跟以前不一样了。

改后这个timertest.c完整源代码如下:

/*    FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.    All rights reserved    VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.    This file is part of the FreeRTOS distribution.    FreeRTOS is free software; you can redistribute it and/or modify it under    the terms of the GNU General Public License (version 2) as published by the    Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.    ***************************************************************************    >>!   NOTE: The modification to the GPL is included to allow you to     !<<    >>!   distribute a combined work that includes FreeRTOS without being   !<<    >>!   obliged to provide the source code for proprietary components     !<<    >>!   outside of the FreeRTOS kernel.                                   !<<    ***************************************************************************    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    FOR A PARTICULAR PURPOSE.  Full license text is available on the following    link: http://www.freertos.org/a00114.html    ***************************************************************************     *                                                                       *     *    FreeRTOS provides completely free yet professionally developed,    *     *    robust, strictly quality controlled, supported, and cross          *     *    platform software that is more than just the market leader, it     *     *    is the industry's de facto standard.                               *     *                                                                       *     *    Help yourself get started quickly while simultaneously helping     *     *    to support the FreeRTOS project by purchasing a FreeRTOS           *     *    tutorial book, reference manual, or both:                          *     *    http://www.FreeRTOS.org/Documentation                              *     *                                                                       *    ***************************************************************************    http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading    the FAQ page "My application does not run, what could be wrong?".  Have you    defined configASSERT()?    http://www.FreeRTOS.org/support - In return for receiving this top quality    embedded software for free we request you assist our global community by    participating in the support forum.    http://www.FreeRTOS.org/training - Investing in training allows your team to    be as productive as possible as early as possible.  Now you can receive    FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers    Ltd, and the world's leading authority on the world's leading RTOS.    http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,    including FreeRTOS+Trace - an indispensable productivity tool, a DOS    compatible FAT file system, and our tiny thread aware UDP/IP stack.    http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.    Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.    http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High    Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS    licenses offer ticketed support, indemnification and commercial middleware.    http://www.SafeRTOS.com - High Integrity Systems also provide a safety    engineered and independently SIL3 certified version for use in safety and    mission critical applications that require provable dependability.    1 tab == 4 spaces!*//* High speed timer test as described in main.c. *//* Scheduler includes. */#include "FreeRTOS.h"/* Library includes. *///#include "stm32f10x_lib.h"#include "stm32f10x_tim.h"//#include "stm32f10x_map.h"/* The set frequency of the interrupt.  Deviations from this are measured asthe jitter. */#define timerINTERRUPT_FREQUENCY        ( ( unsigned short ) 20000 )/* The expected time between each of the timer interrupts - if the jitter waszero. */#define timerEXPECTED_DIFFERENCE_VALUE  ( configCPU_CLOCK_HZ / timerINTERRUPT_FREQUENCY )/* The highest available interrupt priority. */#define timerHIGHEST_PRIORITY           ( 0 )/* Misc defines. */#define timerMAX_32BIT_VALUE            ( 0xffffffffUL )#define timerTIMER_1_COUNT_VALUE        ( * ( ( unsigned long * ) ( TIMER1_BASE + 0x48 ) ) )/* The number of interrupts to pass before we start looking at the jitter. */#define timerSETTLE_TIME            5/*-----------------------------------------------------------*//* * Configures the two timers used to perform the test. */void vSetupHighFrequencyTimer( void );/* Stores the value of the maximum recorded jitter between interrupts. */volatile unsigned short usMaxJitter = 0;/* Variable that counts at 20KHz to provide the time base for the run timestats. */unsigned long ulRunTimeStatsClock = 0UL;/*-----------------------------------------------------------*/void vSetupHighFrequencyTimer( void ){unsigned long ulFrequency;TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;    /* Enable timer clocks */    RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2, ENABLE );    RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3, ENABLE );    /* Initialise data. */    TIM_DeInit( TIM2 );    TIM_DeInit( TIM3 );    TIM_TimeBaseStructInit( &TIM_TimeBaseStructure );    /* Time base configuration for timer 2 - which generates the interrupts. */    ulFrequency = configCPU_CLOCK_HZ / timerINTERRUPT_FREQUENCY;    TIM_TimeBaseStructure.TIM_Period = ( unsigned short ) ( ulFrequency & 0xffffUL );    TIM_TimeBaseStructure.TIM_Prescaler = 0x0;    TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;    TIM_TimeBaseInit( TIM2, &TIM_TimeBaseStructure );    TIM_ARRPreloadConfig( TIM2, ENABLE );    /* Configuration for timer 3 which is used as a high resolution time    measurement. */    TIM_TimeBaseStructure.TIM_Period = ( unsigned short ) 0xffff;    TIM_TimeBaseInit( TIM3, &TIM_TimeBaseStructure );    TIM_ARRPreloadConfig( TIM3, ENABLE );    /* Enable TIM2 IT.  TIM3 does not generate an interrupt. */    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = timerHIGHEST_PRIORITY;    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    NVIC_Init( &NVIC_InitStructure );    TIM_ITConfig( TIM2, TIM_IT_Update, ENABLE );    /* Finally, enable both timers. */    TIM_Cmd( TIM2, ENABLE );    TIM_Cmd( TIM3, ENABLE );}/*-----------------------------------------------------------*/void TIM2_IRQHandler( void ){static unsigned short usLastCount = 0, usSettleCount = 0, usMaxDifference = 0;unsigned short usThisCount, usDifference;    /* Capture the free running timer 3 value as we enter the interrupt. */    usThisCount = TIM3->CNT;    if( usSettleCount >= timerSETTLE_TIME )    {        /* What is the difference between the timer value in this interrupt        and the value from the last interrupt. */        usDifference = usThisCount - usLastCount;        /* Store the difference in the timer values if it is larger than the        currently stored largest value.  The difference over and above the        expected difference will give the 'jitter' in the processing of these        interrupts. */        if( usDifference > usMaxDifference )        {            usMaxDifference = usDifference;            usMaxJitter = usMaxDifference - timerEXPECTED_DIFFERENCE_VALUE;        }    }    else    {        /* Don't bother storing any values for the first couple of        interrupts. */        usSettleCount++;    }    /* Remember what the timer value was this time through, so we can calculate    the difference the next time through. */    usLastCount = usThisCount;    /* Keep a count of the number of interrupts as a time base for the run time    stats collection. */    ulRunTimeStatsClock++;    TIM_ClearITPendingBit( TIM2, TIM_IT_Update );}

按F7键编译链接,出现两个错误:

..\Output\FreeRTOS_v9.0.0.: Error: L6218E: Undefined symbol vApplicationStackOverflowHook (referred from tasks.o)...\Output\FreeRTOS_v9.0.0.: Error: L6218E: Undefined symbol vApplicationTickHook (referred from tasks.o).

这是FreeRTOS核心模块tasks.c调用的两个函数,还没有定义。
vApplicationStackOverflowHook这个是用户应用程序栈溢出钩子函数。
vApplicationTickHook是用户应用程序的系统节拍钩子函数。
(关于这两个函数的作用请参考:http://www.jianshu.com/p/1b8203d953fd)

这两个函数在官方demo的main.c文件中定义,位置在:
FreeRTOSv9.0.0\FreeRTOS\Demo\CORTEX_STM32F107_GCC_Rowley目录下。
在main.c中可以看到:

void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ){    /* This function will get called if a task overflows its stack.   If the    parameters are corrupt then inspect pxCurrentTCB to find which was the    offending task. */    ( void ) pxTask;    printf("ÈÎÎñ£º%s ·¢ÏÖÕ»Òç³ö\n", pcTaskName);    for( ;; );}/*-----------------------------------------------------------*/void vApplicationTickHook( void ){#if 0char *pcMessage = "Status: PASS";static unsigned long ulTicksSinceLastDisplay = 0;portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;    /* Called from every tick interrupt as described in the comments at the top    of this file.    Have enough ticks passed to make it time to perform our health status    check again? */    ulTicksSinceLastDisplay++;    if( ulTicksSinceLastDisplay >= mainCHECK_DELAY )    {        /* Reset the counter so these checks run again in mainCHECK_DELAY        ticks time. */        ulTicksSinceLastDisplay = 0;        /* Has an error been found in any task? */        if( xAreGenericQueueTasksStillRunning() != pdTRUE )        {            pcMessage = "ERROR: GEN Q";        }        else if( xAreQueuePeekTasksStillRunning() != pdTRUE )        {            pcMessage = "ERROR: PEEK Q";        }        else if( xAreBlockingQueuesStillRunning() != pdTRUE )        {            pcMessage = "ERROR: BLOCK Q";        }        else if( xAreSemaphoreTasksStillRunning() != pdTRUE )        {            pcMessage = "ERROR: SEMAPHR";        }        else if( xArePollingQueuesStillRunning() != pdTRUE )        {            pcMessage = "ERROR: POLL Q";        }        else if( xAreIntegerMathsTaskStillRunning() != pdTRUE )        {            pcMessage = "ERROR: INT MATH";        }        else if( xAreRecursiveMutexTasksStillRunning() != pdTRUE )        {            pcMessage = "ERROR: REC MUTEX";        }        /* Send the message to the OLED gatekeeper for display.  The        xHigherPriorityTaskWoken parameter is not actually used here        as this function is running in the tick interrupt anyway - but        it must still be supplied. */        xHigherPriorityTaskWoken = pdFALSE;        //xQueueSendFromISR( xLCDQueue, &pcMessage, &xHigherPriorityTaskWoken );    }#endif}

第二个函数实际上是空函数。
把这两个函数复制到我们工程的main.c中。

main.c中包含头文件如下:

#include "stm32f10x.h"#include "FreeRTOS.h"#include "task.h"#include "queue.h"#include "semphr.h"#include <stdio.h>

然后编译一下,暂时通过,没有错误了。
接下来暂时修改一下启动文件,STM32f10x.s,把暂时用不到的中断函数屏蔽掉:
注释掉:

                ;IMPORT vUARTInterruptHandler                ;IMPORT vTimer2IntHandler

屏蔽掉TIM2中断服务函数:

DCD     0                         ;vTimer2IntHandler         ; TIM2

和串口1中断服务函数:

DCD     0                         ;vUARTInterruptHandler     ; USART1

接下来,就是在main.c文件中,处理系统初始化,函数为prvSetupHardware。这部分可以参考demo中的相关部分,并根据自己的开发板进行调整。我修改如下:

static void prvSetupHardware( void ){    /* Start with the clocks in their expected state. */    RCC_DeInit();    /* Enable HSE (high speed external clock). */    RCC_HSEConfig( RCC_HSE_ON );    /* Wait till HSE is ready. */    while( RCC_GetFlagStatus( RCC_FLAG_HSERDY ) == RESET )    {    }    /* 2 wait states required on the flash. */    *( ( unsigned long * ) 0x40022000 ) = 0x02;    /* HCLK = SYSCLK */    RCC_HCLKConfig( RCC_SYSCLK_Div1 );    /* PCLK2 = HCLK */    RCC_PCLK2Config( RCC_HCLK_Div1 );    /* PCLK1 = HCLK/2 */    RCC_PCLK1Config( RCC_HCLK_Div2 );    /* Enable PLL. */    RCC_PLLCmd( ENABLE );    /* Wait till PLL is ready. */    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)    {    }    /* Select PLL as system clock source. */    RCC_SYSCLKConfig( RCC_SYSCLKSource_PLLCLK );    /* Wait till PLL is used as system clock source. */    while( RCC_GetSYSCLKSource() != 0x08 )    {    }    /* Enable GPIOA, GPIOB, GPIOC, GPIOD, GPIOE and AFIO clocks */    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC                            | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE );    /* Set the Vector Table base address at 0x08000000 */    NVIC_SetVectorTable( NVIC_VectTab_FLASH, 0x0 );    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );    /* Configure HCLK clock as SysTick clock source. */    SysTick_CLKSourceConfig( SysTick_CLKSource_HCLK );    GPIO_Configuration();}

接下来,写个测试程序来测试一下FreeRTOS能否正常跑起来。
测试程序是使板子上的第一个LED灯进行闪烁:

#define ledSTACK_SIZE       configMINIMAL_STACK_SIZE#define ledFLASH_RATE_BASE  ( ( TickType_t ) 333 )static TaskHandle_t xHandleTaskLED=NULL;static void vTaskLED(void* pvParameters){    TickType_t xFlashRate, xLastFlashTime;    xFlashRate = ledFLASH_RATE_BASE + ( ledFLASH_RATE_BASE * ( TickType_t ) 2 );    xFlashRate /= portTICK_PERIOD_MS;    xFlashRate /= ( TickType_t ) 2;    xLastFlashTime = xTaskGetTickCount();    while(1)    {        /* Turn on LD1 */        GPIO_SetBits(GPIOD, GPIO_Pin_2);        /* Insert delay */        //vTaskDelay(300);        vTaskDelayUntil( &xLastFlashTime, xFlashRate );        /* Turn off LD1 */        GPIO_ResetBits(GPIOD, GPIO_Pin_2);        /* Insert delay */        //vTaskDelay(300);        vTaskDelayUntil( &xLastFlashTime, xFlashRate );    }}

main函数如下:

int main(void){      __set_PRIMASK(1);//½ûֹȫ¾ÖÖÐ¶Ï    prvSetupHardware();     xTaskCreate(vTaskLED,"vTaskLED",ledSTACK_SIZE,NULL,3,&xHandleTaskLED);    vTaskStartScheduler();//Æô¶¯ÈÎÎñµ÷¶ÈÆ÷}

完整的main.c文件内容如下:

#include "stm32f10x.h"#include "FreeRTOS.h"#include "task.h"#include "queue.h"#include "semphr.h"#include <stdio.h>void GPIO_Configuration(void){    GPIO_InitTypeDef GPIO_InitStructure;    /* Configure IO connected to LD1, LD2, LD3 and LD4 leds *********************/      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_7;    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    GPIO_Init(GPIOD, &GPIO_InitStructure);}//??????void NVIC_Configuration(void){     /* Configure the NVIC Preemption Priority Bits */      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);    #ifdef  VECT_TAB_RAM        /* Set the Vector Table base location at 0x20000000 */       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);     #else  /* VECT_TAB_FLASH  */      /* Set the Vector Table base location at 0x08000000 */       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);       #endif}void RCC_Configuration(void){    SystemInit();       RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA                            |RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC                           |RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE                           |RCC_APB2Periph_ADC1  | RCC_APB2Periph_AFIO                            |RCC_APB2Periph_SPI1, ENABLE );  // RCC_APB2PeriphClockCmd(RCC_APB2Periph_ALL ,ENABLE );     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4                            |RCC_APB1Periph_USART3|RCC_APB1Periph_TIM2                                                         , ENABLE );     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);}void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ){    /* This function will get called if a task overflows its stack.   If the    parameters are corrupt then inspect pxCurrentTCB to find which was the    offending task. */    ( void ) pxTask;    printf("ÈÎÎñ£º%s ·¢ÏÖÕ»Òç³ö\n", pcTaskName);    for( ;; );}/*-----------------------------------------------------------*/void vApplicationTickHook( void ){}static void prvSetupHardware( void ){    /* Start with the clocks in their expected state. */    RCC_DeInit();    /* Enable HSE (high speed external clock). */    RCC_HSEConfig( RCC_HSE_ON );    /* Wait till HSE is ready. */    while( RCC_GetFlagStatus( RCC_FLAG_HSERDY ) == RESET )    {    }    /* 2 wait states required on the flash. */    *( ( unsigned long * ) 0x40022000 ) = 0x02;    /* HCLK = SYSCLK */    RCC_HCLKConfig( RCC_SYSCLK_Div1 );    /* PCLK2 = HCLK */    RCC_PCLK2Config( RCC_HCLK_Div1 );    /* PCLK1 = HCLK/2 */    RCC_PCLK1Config( RCC_HCLK_Div2 );    /* Enable PLL. */    RCC_PLLCmd( ENABLE );    /* Wait till PLL is ready. */    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)    {    }    /* Select PLL as system clock source. */    RCC_SYSCLKConfig( RCC_SYSCLKSource_PLLCLK );    /* Wait till PLL is used as system clock source. */    while( RCC_GetSYSCLKSource() != 0x08 )    {    }    /* Enable GPIOA, GPIOB, GPIOC, GPIOD, GPIOE and AFIO clocks */    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC                            | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE );    /* Set the Vector Table base address at 0x08000000 */    NVIC_SetVectorTable( NVIC_VectTab_FLASH, 0x0 );    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );    /* Configure HCLK clock as SysTick clock source. */    SysTick_CLKSourceConfig( SysTick_CLKSource_HCLK );    GPIO_Configuration();}#define ledSTACK_SIZE       configMINIMAL_STACK_SIZE#define ledFLASH_RATE_BASE  ( ( TickType_t ) 333 )static TaskHandle_t xHandleTaskLED=NULL;static void vTaskLED(void* pvParameters){    TickType_t xFlashRate, xLastFlashTime;    xFlashRate = ledFLASH_RATE_BASE + ( ledFLASH_RATE_BASE * ( TickType_t ) 2 );    xFlashRate /= portTICK_PERIOD_MS;    xFlashRate /= ( TickType_t ) 2;    xLastFlashTime = xTaskGetTickCount();    while(1)    {        /* Turn on LD1 */        GPIO_SetBits(GPIOD, GPIO_Pin_2);        /* Insert delay */        //vTaskDelay(300);        vTaskDelayUntil( &xLastFlashTime, xFlashRate );        /* Turn off LD1 */        GPIO_ResetBits(GPIOD, GPIO_Pin_2);        /* Insert delay */        //vTaskDelay(300);        vTaskDelayUntil( &xLastFlashTime, xFlashRate );    }}int main(void){      __set_PRIMASK(1);//½ûֹȫ¾ÖÖÐ¶Ï    prvSetupHardware();     xTaskCreate(vTaskLED,"vTaskLED",ledSTACK_SIZE,NULL,3,&xHandleTaskLED);    vTaskStartScheduler();//Æô¶¯ÈÎÎñµ÷¶ÈÆ÷}/******************* (C) COPYRIGHT 2012 WildFire Team *****END OF FILE************/

编译链接后得到hex档,烧到板子上,运行OK!说明FreeRTOS已经跑起来了,一切正常。

这里做个说明,timertest.c中的那个定时器实际并没有启动,因此这部分的功能在我们的工程中并不使用,但是看有关资料介绍,这个timer测试可以用于操作系统的任务分析,所以,暂时保留在工程中。

以上作为一个FreeRTOS基础性移植版本,源代码:
STM32F107_FreeRTOS_v9.0.0_LED-demo-OK.rar

2、为操作系统加入串口debug信息输出功能。

这部分简单说就是利用串口1,为C语言库中的printf函数增加功能性实现函数:
int fputc(int ch, FILE *f);

首先需要对USART1进行配置并实现串口中断服务函数。我们还是省点力气,在官方demo的代码中做个修改好了。
这部分在官方STM32F107demo工程中没有实现,但是在STM32F103工程中有一个demo实现(serial.c),具体位置在:
FreeRTOSv9.0.0\FreeRTOS\Demo\CORTEX_STM32F103_Keil\serial目录下。
相应的头文件(serial.h)位置:
FreeRTOSv9.0.0\FreeRTOS\Demo\Common\include目录下。

因为这两款芯片的USART配置是相同的,可以直接使用。
把这两个文件都拷贝到我们工程的BSP目录下,并把serial.c加入编译工程中的BSP组。

但直接编译出错,问题是固件库不匹配造成的头文件错误和结构体变量错误。
经过修改后的serial.c完整内容如下:

/*    FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.    All rights reserved    VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.    This file is part of the FreeRTOS distribution.    FreeRTOS is free software; you can redistribute it and/or modify it under    the terms of the GNU General Public License (version 2) as published by the    Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.    ***************************************************************************    >>!   NOTE: The modification to the GPL is included to allow you to     !<<    >>!   distribute a combined work that includes FreeRTOS without being   !<<    >>!   obliged to provide the source code for proprietary components     !<<    >>!   outside of the FreeRTOS kernel.                                   !<<    ***************************************************************************    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    FOR A PARTICULAR PURPOSE.  Full license text is available on the following    link: http://www.freertos.org/a00114.html    ***************************************************************************     *                                                                       *     *    FreeRTOS provides completely free yet professionally developed,    *     *    robust, strictly quality controlled, supported, and cross          *     *    platform software that is more than just the market leader, it     *     *    is the industry's de facto standard.                               *     *                                                                       *     *    Help yourself get started quickly while simultaneously helping     *     *    to support the FreeRTOS project by purchasing a FreeRTOS           *     *    tutorial book, reference manual, or both:                          *     *    http://www.FreeRTOS.org/Documentation                              *     *                                                                       *    ***************************************************************************    http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading    the FAQ page "My application does not run, what could be wrong?".  Have you    defined configASSERT()?    http://www.FreeRTOS.org/support - In return for receiving this top quality    embedded software for free we request you assist our global community by    participating in the support forum.    http://www.FreeRTOS.org/training - Investing in training allows your team to    be as productive as possible as early as possible.  Now you can receive    FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers    Ltd, and the world's leading authority on the world's leading RTOS.    http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,    including FreeRTOS+Trace - an indispensable productivity tool, a DOS    compatible FAT file system, and our tiny thread aware UDP/IP stack.    http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.    Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.    http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High    Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS    licenses offer ticketed support, indemnification and commercial middleware.    http://www.SafeRTOS.com - High Integrity Systems also provide a safety    engineered and independently SIL3 certified version for use in safety and    mission critical applications that require provable dependability.    1 tab == 4 spaces!*//*    BASIC INTERRUPT DRIVEN SERIAL PORT DRIVER FOR UART0.*//* Scheduler includes. */#include "FreeRTOS.h"#include "queue.h"#include "semphr.h"/* Library includes. */#include "stm32f10x.h"/* Demo application includes. */#include "serial.h"/*-----------------------------------------------------------*//* Misc defines. */#define serINVALID_QUEUE                ( ( QueueHandle_t ) 0 )#define serNO_BLOCK                     ( ( TickType_t ) 0 )#define serTX_BLOCK_TIME                ( 40 / portTICK_PERIOD_MS )/*-----------------------------------------------------------*//* The queue used to hold received characters. */static QueueHandle_t xRxedChars;static QueueHandle_t xCharsForTx;/*-----------------------------------------------------------*//* UART interrupt handler. */void vUARTInterruptHandler( void );/*-----------------------------------------------------------*//* * See the serial2.h header file. */xComPortHandle xSerialPortInitMinimal( unsigned long ulWantedBaud, unsigned portBASE_TYPE uxQueueLength ){xComPortHandle xReturn;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;USART_ClockInitTypeDef USART_ClockInitStructure;    /* Create the queues used to hold Rx/Tx characters. */    xRxedChars = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( signed char ) );    xCharsForTx = xQueueCreate( uxQueueLength + 1, ( unsigned portBASE_TYPE ) sizeof( signed char ) );    /* If the queue/semaphore was created correctly then setup the serial port    hardware. */    if( ( xRxedChars != serINVALID_QUEUE ) && ( xCharsForTx != serINVALID_QUEUE ) )    {        /* Enable USART1 clock */        RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE );         /* Configure USART1 Rx (PA10) as input floating */        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;        GPIO_Init( GPIOA, &GPIO_InitStructure );        /* Configure USART1 Tx (PA9) as alternate function push-pull */        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        GPIO_Init( GPIOA, &GPIO_InitStructure );        USART_InitStructure.USART_BaudRate = ulWantedBaud;        USART_InitStructure.USART_WordLength = USART_WordLength_8b;        USART_InitStructure.USART_StopBits = USART_StopBits_1;        USART_InitStructure.USART_Parity = USART_Parity_No ;        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;        USART_ClockInitStructure.USART_Clock = USART_Clock_Disable;        USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;        USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge;        USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;        USART_Init( USART1, &USART_InitStructure );        USART_ClockInit( USART1, &USART_ClockInitStructure );        USART_ITConfig( USART1, USART_IT_RXNE, ENABLE );        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_KERNEL_INTERRUPT_PRIORITY;        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;        NVIC_Init( &NVIC_InitStructure );        USART_Cmd( USART1, ENABLE );            }    else    {        xReturn = ( xComPortHandle ) 0;    }    /* This demo file only supports a single port but we have to return    something to comply with the standard demo header file. */    return xReturn;}/*-----------------------------------------------------------*/signed portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, signed char *pcRxedChar, TickType_t xBlockTime ){    /* The port handle is not required as this driver only supports one port. */    ( void ) pxPort;    /* Get the next character from the buffer.  Return false if no characters    are available, or arrive before xBlockTime expires. */    if( xQueueReceive( xRxedChars, pcRxedChar, xBlockTime ) )    {        return pdTRUE;    }    else    {        return pdFALSE;    }}/*-----------------------------------------------------------*/void vSerialPutString( xComPortHandle pxPort, const signed char * const pcString, unsigned short usStringLength ){signed char *pxNext;    /* A couple of parameters that this port does not use. */    ( void ) usStringLength;    ( void ) pxPort;    /* NOTE: This implementation does not handle the queue being full as no    block time is used! */    /* The port handle is not required as this driver only supports UART1. */    ( void ) pxPort;    /* Send each character in the string, one at a time. */    pxNext = ( signed char * ) pcString;    while( *pxNext )    {        xSerialPutChar( pxPort, *pxNext, serNO_BLOCK );        pxNext++;    }}/*-----------------------------------------------------------*/signed portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, signed char cOutChar, TickType_t xBlockTime ){signed portBASE_TYPE xReturn;    if( xQueueSend( xCharsForTx, &cOutChar, xBlockTime ) == pdPASS )    {        xReturn = pdPASS;        USART_ITConfig( USART1, USART_IT_TXE, ENABLE );    }    else    {        xReturn = pdFAIL;    }    return xReturn;}/*-----------------------------------------------------------*/void vSerialClose( xComPortHandle xPort ){    /* Not supported as not required by the demo application. */}/*-----------------------------------------------------------*/void vUARTInterruptHandler( void ){portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;char cChar;    if( USART_GetITStatus( USART1, USART_IT_TXE ) == SET )    {        /* The interrupt was caused by the THR becoming empty.  Are there any        more characters to transmit? */        if( xQueueReceiveFromISR( xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )        {            /* A character was retrieved from the queue so can be sent to the            THR now. */            USART_SendData( USART1, cChar );        }        else        {            USART_ITConfig( USART1, USART_IT_TXE, DISABLE );                }           }    if( USART_GetITStatus( USART1, USART_IT_RXNE ) == SET )    {        cChar = USART_ReceiveData( USART1 );        xQueueSendFromISR( xRxedChars, &cChar, &xHigherPriorityTaskWoken );    }       portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );}

头文件不用修改。

编译通过。

接下来就是要修改启动文件STM3210x.s,去掉串口1中断服务函数的屏蔽:

                IMPORT vUARTInterruptHandler
DCD     vUARTInterruptHandler     ; USART1

接下来,实现串口1初始化函数、 fputc函数,和其他常用函数。这部分内容放在utils.c中。
相关头文件utils.h内容:

utils.h:

#ifndef __PRINTF_UTILS_H__#define __PRINTF_UTILS_H__extern void FreeRTOS_printf_service_init(void);extern const char *getCurrentFileName(const char* strFileName);#endif

utils.c内容:

#include <stdarg.h>#include <stddef.h>#include <stdio.h>#include "stm32f10x.h"#include "FreeRTOS.h"#include "serial.h"#define FreeRTOS_printf_BAUD_RATE       ( 115200 )#define FreeRTOS_printf_BUFFER_LEN       (128)/* Handle to the com port used by both tasks. */                    static xComPortHandle xPort = NULL;void FreeRTOS_printf_service_init(void){    xPort = xSerialPortInitMinimal( FreeRTOS_printf_BAUD_RATE, FreeRTOS_printf_BUFFER_LEN );}/* ·¢ËÍÊý¾Ý£¬Èç¹û·¢Ë͵ÄÊÇÍ˸ñ¼ü¡£ÎªÁËʹ½ÓÊÕ¶ËÏÔʾΪɾ³ýÇ°Ãæ×Ö·ûµÄЧ¹û£¬ÔòÏÈÍ˸ñÔÙÏÔʾ¿Õ¸ñ£¬È»ºóÔÙÍ˸ñ¡£·ñÔòµÄ»°£¬Ö±½ÓÍ˸ñ£¬×Ö·û²»ÄÜɾ³ý£¬ÈÔÈ»ÄÜÔÚ´®¿ÚÖÕ¶ËÏÔʾ*/int fputc(int ch, FILE *f){    if(ch=='\n')    {            USART_SendData(USART1, '\r');// USART1 ¿ÉÒÔ»»³É USART2 µÈ                while (!(USART1->SR & USART_FLAG_TXE));    }    else if(ch=='\b')    {            USART_SendData(USART1, '\b');// USART1 ¿ÉÒÔ»»³É USART2 µÈ                while (!(USART1->SR & USART_FLAG_TXE));            USART_SendData(USART1, ' ');// USART1 ¿ÉÒÔ»»³É USART2 µÈ                while (!(USART1->SR & USART_FLAG_TXE));                     }    else if(ch=='\r')    {        return (ch);    }    USART_SendData(USART1, (unsigned char) ch);// USART1 ¿ÉÒÔ»»³É USART2 µÈ    while (!(USART1->SR & USART_FLAG_TXE));    return (ch);}// ½ÓÊÕÊý¾Ýint GetKey (void)  {    while (!(USART1->SR & USART_FLAG_RXNE));    return ((int)(USART1->DR & 0x1FF));}#include <string.h>//ÓÃÀ´»ñÈ¡__FILE__ÖеIJ»´ø·¾¶µÄÎļþÃûconst char *getCurrentFileName(const char* strFileName){    const char *p = strrchr(strFileName,'\\');    if(p==NULL)        return strFileName;    return ++p;}#include <stdio.h>  /* _exit - Simple implementation. Does not return.*/void _exit (int status){  (void)status;  while (1);}/* * abort -- go out via exit... */void abort(void){  _exit(1);}void _assert(const char *mesg, const char *file, int line){   printf("%s, %s, %d\n", mesg, file, line);    abort();}

到这里串口调试功能已经具备了。

为以后方便使用,我们再写个调试打印宏,放在dprintf.h中:

#ifndef __DPRINTF_H__#define __DPRINTF_H__#ifdef __cplusplusextern "C"{#endif#ifdef _DEBUG#include <stdarg.h>#include <stdio.h>extern const char *getCurrentFileName(const char* strFileName);#define dprintf(fmt,...) printf("%s,line:%d,"fmt,getCurrentFileName(__FILE__),__LINE__,##__VA_ARGS__)#else#define dprintf(fmt,...)#endif#ifdef __cplusplus}#endif#endif

把dprintf.h放在BSP目录下。

在使用dprintf打印调试信息时,在添加这个头文件前加一行宏代码:

#define _DEBUG

使能dprintf。

接下来修改main.c,对USART1的初始化进行调用,顺便写个测试代码。
完整main.c如下:

#include "stm32f10x.h"#include "FreeRTOS.h"#include "task.h"#include "queue.h"#include "semphr.h"#include "utils.h"#define _DEBUG#include "dprintf.h"void GPIO_Configuration(void){    GPIO_InitTypeDef GPIO_InitStructure;    /* Configure IO connected to LD1, LD2, LD3 and LD4 leds *********************/      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_7;    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    GPIO_Init(GPIOD, &GPIO_InitStructure);}//??????void NVIC_Configuration(void){     /* Configure the NVIC Preemption Priority Bits */      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);    #ifdef  VECT_TAB_RAM        /* Set the Vector Table base location at 0x20000000 */       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);     #else  /* VECT_TAB_FLASH  */      /* Set the Vector Table base location at 0x08000000 */       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);       #endif}void RCC_Configuration(void){    SystemInit();       RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA                            |RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC                           |RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE                           |RCC_APB2Periph_ADC1  | RCC_APB2Periph_AFIO                            |RCC_APB2Periph_SPI1, ENABLE );  // RCC_APB2PeriphClockCmd(RCC_APB2Periph_ALL ,ENABLE );     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4                            |RCC_APB1Periph_USART3|RCC_APB1Periph_TIM2                                                         , ENABLE );     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);}void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ){    /* This function will get called if a task overflows its stack.   If the    parameters are corrupt then inspect pxCurrentTCB to find which was the    offending task. */    ( void ) pxTask;    printf("ÈÎÎñ£º%s ·¢ÏÖÕ»Òç³ö\n", pcTaskName);    for( ;; );}/*-----------------------------------------------------------*/void vApplicationTickHook( void ){}static void prvSetupHardware( void ){    /* Start with the clocks in their expected state. */    RCC_DeInit();    /* Enable HSE (high speed external clock). */    RCC_HSEConfig( RCC_HSE_ON );    /* Wait till HSE is ready. */    while( RCC_GetFlagStatus( RCC_FLAG_HSERDY ) == RESET )    {    }    /* 2 wait states required on the flash. */    *( ( unsigned long * ) 0x40022000 ) = 0x02;    /* HCLK = SYSCLK */    RCC_HCLKConfig( RCC_SYSCLK_Div1 );    /* PCLK2 = HCLK */    RCC_PCLK2Config( RCC_HCLK_Div1 );    /* PCLK1 = HCLK/2 */    RCC_PCLK1Config( RCC_HCLK_Div2 );    /* Enable PLL. */    RCC_PLLCmd( ENABLE );    /* Wait till PLL is ready. */    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)    {    }    /* Select PLL as system clock source. */    RCC_SYSCLKConfig( RCC_SYSCLKSource_PLLCLK );    /* Wait till PLL is used as system clock source. */    while( RCC_GetSYSCLKSource() != 0x08 )    {    }    /* Enable GPIOA, GPIOB, GPIOC, GPIOD, GPIOE and AFIO clocks */    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC                            | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE );    /* Set the Vector Table base address at 0x08000000 */    NVIC_SetVectorTable( NVIC_VectTab_FLASH, 0x0 );    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );    /* Configure HCLK clock as SysTick clock source. */    SysTick_CLKSourceConfig( SysTick_CLKSource_HCLK );    GPIO_Configuration();}#define ledSTACK_SIZE       configMINIMAL_STACK_SIZE#define ledFLASH_RATE_BASE  ( ( TickType_t ) 333 )static TaskHandle_t xHandleTaskLED=NULL;static void vTaskLED(void* pvParameters){    TickType_t xFlashRate, xLastFlashTime;    xFlashRate = ledFLASH_RATE_BASE + ( ledFLASH_RATE_BASE * ( TickType_t ) 2 );    xFlashRate /= portTICK_PERIOD_MS;    xFlashRate /= ( TickType_t ) 2;    xLastFlashTime = xTaskGetTickCount();    while(1)    {        /* Turn on LD1 */        GPIO_SetBits(GPIOD, GPIO_Pin_2);        /* Insert delay */        //vTaskDelay(300);        vTaskDelayUntil( &xLastFlashTime, xFlashRate );        /* Turn off LD1 */        GPIO_ResetBits(GPIOD, GPIO_Pin_2);        /* Insert delay */        //vTaskDelay(300);        vTaskDelayUntil( &xLastFlashTime, xFlashRate );    }}int main(void){      __set_PRIMASK(1);//½ûֹȫ¾ÖÖÐ¶Ï    prvSetupHardware();     FreeRTOS_printf_service_init();    printf("###############################################\r\n");    printf("##    hello! welcome to FreeRTOS v9.0.0      ##\r\n");    printf("###############################################\r\n");    printf("\r\n\r\n");    dprintf("\n");    xTaskCreate(vTaskLED,"vTaskLED",ledSTACK_SIZE,NULL,3,&xHandleTaskLED);    vTaskStartScheduler();//Æô¶¯ÈÎÎñµ÷¶ÈÆ÷}/******************* (C) COPYRIGHT 2012 WildFire Team *****END OF FILE************/

整个工程编译一下,hex档烧到开发板上。然后连好串口线,电脑上打开串口终端,波特率设置为115200(在serial.c中设定,如果需要设置为其他值,需要修改相应位置),数据位为8,停止位为1,奇偶校验为无(none)。

开发板上电,看到串口终端显示:

这里写图片描述

开发板上的LED1灯也在不断闪烁。

FreeRTOS的移植到此大功告成。

完整源代码:
STM32F107_FreeRTOS_v9.0.0_UART1-dprintf-OK.rar

唉,文章写得是不是太详细了,太罗嗦了,突然发现内容写了好多。

下篇将在此次移植基础上加入SD卡驱动和FatFS文件系统,并实现对ini配置文件的读写。

阅读全文
0 0
原创粉丝点击