STM32F103 移植UCOSIII LED例子测试 在GNU编译下实现

STM32F103 移植UCOSIII GNU编译实现  


1、准备移植文件,从micrium官网下载在UCOSIII移植文件。

    当前进入网站首页时,选择STM 法意半导体 芯片生产商查看全部型号。

    

下图,这里我们选择STM32F107 它使用的是UCOSIII V3.03.01 版本,IDE使用了

Atollic TrueSTUDIO V3.x   是市售增强C / C ++ IDE基于Eclipse ®,CDT ™,GCC和GDB。2017年以来已停止更新,ST已收购。

IAR (EWARM) V6.x     是IARSystems 公司为ARM 微处理器开发的一个集成开发环境。

Keil MDK V3.x       是美国Keil Software公司出品的单片机C语言软件开发系统。

以上三种IED 使用的编译链接器不相同,有GNU 、IAR、 RealView 、后面讲到选择uC-CPU文件夹里面的程序时,需要特别留意

自己IDE环境。

   下载完毕后解压

   


2、整理和拷贝UCOSIII移植文件。

  在程序目录下建立自定义文件夹如下:

   

   在自定义的文件夹中,我们将官网下载的Ucosiii源码复制到文件中,详情见以下说明:

UCOSIII
  ├文件夹1:[UCOSIII_BSP]  <-----------------------里面的bsp.c、bsp.h是自定义的程序。
  │ ├(1)bsp.c
  │ ├(2)bsp.h
  │ └█
  ├文件夹2:[UCOSIII_CONFIG]  <------------------MicriumSoftwareEvalBoardsMicriumuC-Eval-STM32F107uCOS-III
  │ ├(1)app_cfg.h
  │ ├(2)cpu_cfg.h
  │ ├(3)includes.h
  │ ├(4)lib_cfg.h
  │ ├(5)os_app_hooks.c
  │ ├(6)os_app_hooks.h
  │ ├(7)os_cfg.h
  │ ├(8)os_cfg_app.h
  │ └█
  ├文件夹3:[UCOSIII_CORE]   <--------------------MicriumSoftwareuCOS-IIISource
  │ ├(1)os.h
  │ ├(2)os_cfg_app.c
  │ ├(3)os_core.c
  │ ├(4)os_dbg.c
  │ ├(5)os_flag.c
  │ ├(6)os_int.c
  │ ├(7)os_mem.c
  │ ├(8)os_msg.c
  │ ├(9)os_mutex.c
  │ ├(10)os_pend_multi.c
  │ ├(11)os_prio.c
  │ ├(12)os_q.c
  │ ├(13)os_sem.c
  │ ├(14)os_stat.c
  │ ├(15)os_task.c
  │ ├(16)os_tick.c
  │ ├(17)os_time.c
  │ ├(18)os_tmr.c
  │ ├(19)os_type.h
  │ ├(20)os_var.c
  │ └█
  ├文件夹4:[UCOSIII_CPU]  <--------------------MicriumSoftwareuC-CPU
  │ ├(1)cpu.h
  │ ├(2)cpu_a.s
  │ ├(3)cpu_c.c
  │ ├(4)cpu_core.c
  │ ├(5)cpu_core.h

  │ ├(6)cpu_def.h
  │ └█
  ├文件夹5:[UCOSIII_LIB]  <--------------------MicriumSoftwareuC-LIB
  │ ├(1)lib_ascii.c
  │ ├(2)lib_ascii.h
  │ ├(3)lib_def.h
  │ ├(4)lib_math.c
  │ ├(5)lib_math.h
  │ ├(6)lib_mem.c
  │ ├(7)lib_mem.h
  │ ├(8)lib_mem_a.s
  │ ├(9)lib_str.c
  │ ├(10)lib_str.h
  │ └█
  ├文件夹6:[UCOSIII_PORT]  <--------------------uCOS-IIIPortsARM-Cortex-M3GenericGNU
  │ ├(1)os_cpu.h
  │ ├(2)os_cpu_a.s
  │ ├(3)os_cpu_c.c
  │ └█
  └█

 这里需要特别说明文件夹6:确认自己的IDE 使用的编译器是GNU 、IAR、 RealView哪一种,对应着拷贝,使用不同的代码,移植会有

一些差异,具体可以参照其它教程,这里我们选择GNU编译的代码,即 ;uCOS-IIIPortsARM-Cortex-M3GenericGNU  的    os_cpu.h  、  os_cpu_a.s  、 os_cpu_c.c  。

拷贝到UCOSIII文件夹到工程后,根据自己IDE设置方法将UCOSIII这个文件夹添加到IDE编译路径,不同的IDE是不同的,比如 我这边使用的是Clion 通过修改CMakelists.txt 增加代码的路径。

 2.1修改 UCOSIII_BSP 的代码

官方的Bsp.c文件中,有很多代码是我们不需要用到的,我们只用到DWT的代码,应该参照官网源码,我们做以下修改。

 Bsp.h

#ifndef  BSP_PRESENT
#define  BSP_PRESENT

#ifdef   BSP_MODULE
#define  BSP_EXT
#else
#define  BSP_EXT  extern
#endif

#include  <stdio.h>
#include  <stdarg.h>
#include  <cpu.h>
#include  <cpu_core.h>
#include  <lib_def.h>
#include  <lib_ascii.h>
//#include  <stm32f10x_conf.h>  //标准库方式的
#include "stm32f1xx_hal.h"  //对应HAL库 主要目的是为了获取系统时钟源

#endif  

  Bsp.c 

#define   BSP_MODULE
#include  <bsp.h>


#define  BSP_REG_DEM_CR                           (*(CPU_REG32 *)0xE000EDFC)	//DEMCR寄存器
#define  BSP_REG_DWT_CR                           (*(CPU_REG32 *)0xE0001000)  	//DWT控制寄存器
#define  BSP_REG_DWT_CYCCNT                       (*(CPU_REG32 *)0xE0001004)	//DWT时钟计数寄存器	
#define  BSP_REG_DBGMCU_CR                        (*(CPU_REG32 *)0xE0042004)
 
//DEMCR寄存器的第24位,如果要使用DWT ETM ITM和TPIU的话DEMCR寄存器的第24位置1
#define  BSP_BIT_DEM_CR_TRCENA                    DEF_BIT_24			

//DWTCR寄存器的第0位,当为1的时候使能CYCCNT计数器,使用CYCCNT之前应当先初始化
#define  BSP_BIT_DWT_CR_CYCCNTENA                 DEF_BIT_00

/*
*********************************************************************************************************
*                                            BSP_CPU_ClkFreq()
* Description : Read CPU registers to determine the CPU clock frequency of the chip.
* Argument(s) : none.
* Return(s)   : The CPU clock frequency, in Hz.
* Caller(s)   : Application.
* Note(s)     : none.
*********************************************************************************************************
*/

CPU_INT32U  BSP_CPU_ClkFreq (void)
{
//    RCC_ClocksTypeDef  rcc_clocks;
//
//    RCC_GetClocksFreq(&rcc_clocks);		//获取各个时钟频率
//
//    return ((CPU_INT32U)rcc_clocks.HCLK_Frequency);  //返回HCLK时钟频率
    //RCC_ClkInitTypeDef rcc_clocks ;

    //HAL_RCC_GetOscConfig();
    //HAL_RCC_GetHCLKFreq();		//获取各个时钟频率
    return ((CPU_INT32U)HAL_RCC_GetHCLKFreq());  //返回HCLK时钟频率

}




/*$PAGE*/
/*
*********************************************************************************************************
*                                          CPU_TS_TmrInit()
* Description : Initialize & start CPU timestamp timer.
* Argument(s) : none.
* Return(s)   : none.
* Caller(s)   : CPU_TS_Init().
*               This function is an INTERNAL CPU module function & MUST be implemented by application/
*               BSP function(s) [see Note #1] but MUST NOT be called by application function(s).
* Note(s)     : (1) CPU_TS_TmrInit() is an application/BSP function that MUST be defined by the developer
*                   if either of the following CPU features is enabled :
*                   (a) CPU timestamps
*                   (b) CPU interrupts disabled time measurements
*                   See 'cpu_cfg.h  CPU TIMESTAMP CONFIGURATION  Note #1'
*                     & 'cpu_cfg.h  CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION  Note #1a'.
*               (2) (a) Timer count values MUST be returned via word-size-configurable 'CPU_TS_TMR'
*                       data type.
*                       (1) If timer has more bits, truncate timer values' higher-order bits greater
*                           than the configured 'CPU_TS_TMR' timestamp timer data type word size.
*                       (2) Since the timer MUST NOT have less bits than the configured 'CPU_TS_TMR'
*                           timestamp timer data type word size; 'CPU_CFG_TS_TMR_SIZE' MUST be
*                           configured so that ALL bits in 'CPU_TS_TMR' data type are significant.
*                           In other words, if timer size is not a binary-multiple of 8-bit octets
*                           (e.g. 20-bits or even 24-bits), then the next lower, binary-multiple
*                           octet word size SHOULD be configured (e.g. to 16-bits).  However, the
*                           minimum supported word size for CPU timestamp timers is 8-bits.
*                       See also 'cpu_cfg.h   CPU TIMESTAMP CONFIGURATION  Note #2'
*                              & 'cpu_core.h  CPU TIMESTAMP DATA TYPES     Note #1'.
*                   (b) Timer SHOULD be an 'up'  counter whose values increase with each time count.
*                   (c) When applicable, timer period SHOULD be less than the typical measured time
*                       but MUST be less than the maximum measured time; otherwise, timer resolution
*                       inadequate to measure desired times.
*                   See also 'CPU_TS_TmrRd()  Note #2'.
*********************************************************************************************************
*/

#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
void  CPU_TS_TmrInit (void)
{
    CPU_INT32U  fclk_freq;


    fclk_freq = BSP_CPU_ClkFreq();

    BSP_REG_DEM_CR     |= (CPU_INT32U)BSP_BIT_DEM_CR_TRCENA; //使用DWT  /* Enable Cortex-M4's DWT CYCCNT reg.                   */
    BSP_REG_DWT_CYCCNT  = (CPU_INT32U)0u;					 //初始化CYCCNT寄存器
    BSP_REG_DWT_CR     |= (CPU_INT32U)BSP_BIT_DWT_CR_CYCCNTENA;//开启CYCCNT

    CPU_TS_TmrFreqSet((CPU_TS_TMR_FREQ)fclk_freq);
}
#endif


/*$PAGE*/
/*
*********************************************************************************************************
*                                           CPU_TS_TmrRd()
* Description : Get current CPU timestamp timer count value.
* Argument(s) : none.
* Return(s)   : Timestamp timer count (see Notes #2a & #2b).
* Caller(s)   : CPU_TS_Init(),
*               CPU_TS_Get32(),
*               CPU_TS_Get64(),
*               CPU_IntDisMeasStart(),
*               CPU_IntDisMeasStop().
*               This function is an INTERNAL CPU module function & MUST be implemented by application/
*               BSP function(s) [see Note #1] but SHOULD NOT be called by application function(s).
* Note(s)     : (1) CPU_TS_TmrRd() is an application/BSP function that MUST be defined by the developer
*                   if either of the following CPU features is enabled :
*                   (a) CPU timestamps
*                   (b) CPU interrupts disabled time measurements
*                   See 'cpu_cfg.h  CPU TIMESTAMP CONFIGURATION  Note #1'
*                     & 'cpu_cfg.h  CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION  Note #1a'.
*               (2) (a) Timer count values MUST be returned via word-size-configurable 'CPU_TS_TMR'
*                       data type.
*                       (1) If timer has more bits, truncate timer values' higher-order bits greater
*                           than the configured 'CPU_TS_TMR' timestamp timer data type word size.
*                       (2) Since the timer MUST NOT have less bits than the configured 'CPU_TS_TMR'
*                           timestamp timer data type word size; 'CPU_CFG_TS_TMR_SIZE' MUST be
*                           configured so that ALL bits in 'CPU_TS_TMR' data type are significant.
*                           In other words, if timer size is not a binary-multiple of 8-bit octets
*                           (e.g. 20-bits or even 24-bits), then the next lower, binary-multiple
*                           octet word size SHOULD be configured (e.g. to 16-bits).  However, the
*                           minimum supported word size for CPU timestamp timers is 8-bits.
*                       See also 'cpu_cfg.h   CPU TIMESTAMP CONFIGURATION  Note #2'
*                              & 'cpu_core.h  CPU TIMESTAMP DATA TYPES     Note #1'.
*                   (b) Timer SHOULD be an 'up'  counter whose values increase with each time count.
*                       (1) If timer is a 'down' counter whose values decrease with each time count,
*                           then the returned timer value MUST be ones-complemented.
*                   (c) (1) When applicable, the amount of time measured by CPU timestamps is
*                           calculated by either of the following equations :
*                           (A) Time measured  =  Number timer counts  *  Timer period
*                                   where
*
*                                       Number timer counts     Number of timer counts measured
*                                       Timer period            Timer's period in some units of
*                                                                   (fractional) seconds
*                                       Time measured           Amount of time measured, in same
*                                                                   units of (fractional) seconds
*                                                                   as the Timer period
*
*                                                  Number timer counts
*                           (B) Time measured  =  ---------------------
*                                                    Timer frequency
*
*                                   where
*
*                                       Number timer counts     Number of timer counts measured
*                                       Timer frequency         Timer's frequency in some units
*                                                                   of counts per second
*                                       Time measured           Amount of time measured, in seconds
*
*                       (2) Timer period SHOULD be less than the typical measured time but MUST be less
*                           than the maximum measured time; otherwise, timer resolution inadequate to
*                           measure desired times.
*********************************************************************************************************
*/

#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
CPU_TS_TMR  CPU_TS_TmrRd (void)
{
    CPU_TS_TMR  ts_tmr_cnts;


    ts_tmr_cnts = (CPU_TS_TMR)BSP_REG_DWT_CYCCNT;

    return (ts_tmr_cnts);
}
#endif


/*$PAGE*/
/*
*********************************************************************************************************
*                                         CPU_TSxx_to_uSec()
* Description : Convert a 32-/64-bit CPU timestamp from timer counts to microseconds.
* Argument(s) : ts_cnts   CPU timestamp (in timestamp timer counts [see Note #2aA]).
* Return(s)   : Converted CPU timestamp (in microseconds           [see Note #2aD]).
* Caller(s)   : Application.
*               This function is an (optional) CPU module application programming interface (API)
*               function which MAY be implemented by application/BSP function(s) [see Note #1] &
*               MAY be called by application function(s).
* Note(s)     : (1) CPU_TS32_to_uSec()/CPU_TS64_to_uSec() are application/BSP functions that MAY be
*                   optionally defined by the developer when either of the following CPU features is
*                   enabled :
*                   (a) CPU timestamps
*                   (b) CPU interrupts disabled time measurements
*                   See 'cpu_cfg.h  CPU TIMESTAMP CONFIGURATION  Note #1'
*                     & 'cpu_cfg.h  CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION  Note #1a'.
*               (2) (a) The amount of time measured by CPU timestamps is calculated by either of
*                       the following equations :
*
*                                                                        10^6 microseconds
*                       (1) Time measured  =   Number timer counts   *  -------------------  *  Timer period
*                                                                            1 second
*
*                                              Number timer counts       10^6 microseconds
*                       (2) Time measured  =  ---------------------  *  -------------------
*                                                Timer frequency             1 second
*
*                               where
*
*                                   (A) Number timer counts     Number of timer counts measured
*                                   (B) Timer frequency         Timer's frequency in some units
*                                                                   of counts per second
*                                   (C) Timer period            Timer's period in some units of
*                                                                   (fractional)  seconds
*                                   (D) Time measured           Amount of time measured,
*                                                                   in microseconds
*
*                   (b) Timer period SHOULD be less than the typical measured time but MUST be less
*                       than the maximum measured time; otherwise, timer resolution inadequate to
*                       measure desired times.
*
*                   (c) Specific implementations may convert any number of CPU_TS32 or CPU_TS64 bits
*                       -- up to 32 or 64, respectively -- into microseconds.
*********************************************************************************************************
*/

#if (CPU_CFG_TS_32_EN == DEF_ENABLED)
CPU_INT64U  CPU_TS32_to_uSec (CPU_TS32  ts_cnts)
{
    CPU_INT64U  ts_us;
    CPU_INT64U  fclk_freq;


    fclk_freq = BSP_CPU_ClkFreq();
    ts_us     = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);

    return (ts_us);
}
#endif


#if (CPU_CFG_TS_64_EN == DEF_ENABLED)
CPU_INT64U  CPU_TS64_to_uSec (CPU_TS64  ts_cnts)
{
    CPU_INT64U  ts_us;
    CPU_INT64U  fclk_freq;


    fclk_freq = BSP_CPU_ClkFreq();
    ts_us     = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);

    return (ts_us);
}
#endif

 


3、修改UCOSiii关联的代码。

完成第2大点的步骤,UCOSiii的文件算是全部准备好了,下来我们将相关代码来匹配当前的环境。

3.1  UCOSIII/UCOSIII_CONFIG/includes.h 修改

  将#include <stm32f10x_lib.h> 注释掉,我们不需要使用。

  

3.2  UCOSIII/UCOSIII_PORT/os_cpu_a.s 及  Core/Src/stm32f1xx_it.c 修改

  os_cpu_a.s  

  OS_CPU_PendSVHandler 改为 PendSV_Handler

  

       

    在ucos的源码都定义好了名称是OS_CPU_PendSVHandler,在文件os_cpu_a.s中如3.2上图所示。但是stm32中也定义了异常中断,在stm32的启动文件startup_stm32xxx.s中

  可以看到如下图所示,其名称为PendSVHandler(或PendSV_Handler)与前者的名字不同而已。由于stm32是先从启动文件开始运行,中断异常自然是按启动文件中定义的为准,所以后面

  ucos在进行任务切换的时候触发了异常中断,而ucos异常中断函数相当于是没用的,所以如果将OS_CPU_PendSVHandler 改为 PendSV_Handler 出现了卡死情况。

  

  stm32f1xx_it.c

  将 void PendSV_Handler(void) 注释掉如下图,原因是:stm32f1xx_it.c 和 os_cpu_a.s 中重复定义了 PendSV_Handler 这个函数。

  

3.3  延时delay.c 程序的修改。

  delay.c是用于时间延时控制的,STM32 delay.c的网上有很多教程,这里就不另外展开了。

  3.3.1 SysTick_Handler (void) 重名修改。

  自定义的Delay.c 延时程序中使用了void SysTick_Handler(void) 函数系统滴答计时器如右图。因为自定义的Delay.c 和 stm32f1xx_it.c 中存在同名冲突,  所以需要屏蔽掉stm32f1xx_it.c 中的函数如左图。

  屏蔽掉stm32f1xx_it.c的函数后,HAL的时钟也不启用,其它程序不能使用HAL的Delay() 函数功能。

       

  3.3.2 Delay.c 支持 Ucosiii 功能启用。

    自定义的 sys.h 的 SYSTEM_SUPPORT_OS = 1 支持Ucosiii

   


3、Main.c创建任务运行Ucosiii

  

#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "sys.h"      // 时钟配置、GPIO位带 【时钟配置不用这里的】
#include "delay.h"
#include "includes.h"

void SystemClock_Config(void);
static void MX_GPIO_Init(void);

void flesh_LED(int Delay);
void flesh_LEDB8(int Delay);

/*----------------------------------------------------------------------------*/
#define START_TASK_PRIO		3           //任务优先级
#define START_STK_SIZE 		512         //任务堆栈大小
OS_TCB StartTaskTCB;                        //任务控制块
CPU_STK START_TASK_STK[START_STK_SIZE];     //任务堆栈
void start_task(void *p_arg);               //任务函数
/*----------------------------------------------------------------------------*/
#define LED0_TASK_PRIO		4           //任务优先级
#define LED0_STK_SIZE 		128         //任务堆栈大小
OS_TCB Led0TaskTCB;                         //任务控制块
CPU_STK LED0_TASK_STK[LED0_STK_SIZE];       //任务堆栈
void led0_task(void *p_arg);                //任务函数
/*----------------------------------------------------------------------------*/
#define LED1_TASK_PRIO		5           //任务优先级
#define LED1_STK_SIZE 		128         //任务堆栈大小
OS_TCB Led1TaskTCB;                         //任务控制块
CPU_STK LED1_TASK_STK[LED1_STK_SIZE];       //任务堆栈
void led1_task(void *p_arg);                //任务函数
/*----------------------------------------------------------------------------*/

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick.
     * 重置所有外围设备,初始化Flash接口和Systick*/
    HAL_Init();

    /* 系统时钟初始化 */
    SystemClock_Config();

    /* 系统初始化*/
    delay_init(72);//初始化延时函数

    /*初始化设置外围设备---------------------------------------------------------*/
    MX_GPIO_Init();

    /*任务开启------------------------------------------------------------------*/
    OS_ERR err;
    CPU_SR_ALLOC();
    HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2); //中断分组配置
    OSInit(&err);		                            //初始化UCOSIII
    OS_CRITICAL_ENTER();                            //进入临界区
    //创建开始任务
    OSTaskCreate((OS_TCB 	* )&StartTaskTCB,		//任务控制块
                 (CPU_CHAR	* )"start task", 		//任务名字
                 (OS_TASK_PTR )start_task, 			//任务函数
                 (void		* )0,					//传递给任务函数的参数
                 (OS_PRIO	  )START_TASK_PRIO,     //任务优先级
                 (CPU_STK   * )&START_TASK_STK[0],//任务堆栈基地址
                 (CPU_STK_SIZE)START_STK_SIZE/10,	//任务堆栈深度限位
                 (CPU_STK_SIZE)START_STK_SIZE,		//任务堆栈大小
                 (OS_MSG_QTY  )0,					//任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
                 (OS_TICK	  )0,				    //当使能时间片轮转时的时间片长度,为0时为默认长度,
                 (void   	* )0,					//用户补充的存储区
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
                 (OS_ERR 	* )&err);				//存放该函数错误时的返回值
    OS_CRITICAL_EXIT();	                            //退出临界区
    OSStart(&err);                                  //开启UCOSIII
    while (1)
    {
    }

}


//开始任务
void start_task(void *p_arg)
{
    OS_ERR err;
    CPU_SR_ALLOC();
    p_arg = p_arg;

    CPU_Init();
#if OS_CFG_STAT_TASK_EN > 0u
    OSStatTaskCPUUsageInit(&err);  	//统计任务
#endif

#ifdef CPU_CFG_INT_DIS_MEAS_EN		//如果使能了测量中断关闭时间
    CPU_IntDisMeasMaxCurReset();
#endif

#if	OS_CFG_SCHED_ROUND_ROBIN_EN  //当使用时间片轮转的时候
    //使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5ms
    OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);
#endif

    OS_CRITICAL_ENTER();	//进入临界区
    //创建LED0任务
    OSTaskCreate((OS_TCB 	* )&Led0TaskTCB,
                 (CPU_CHAR	* )"led0 task",
                 (OS_TASK_PTR )led0_task,
                 (void		* )0,
                 (OS_PRIO	  )LED0_TASK_PRIO,
                 (CPU_STK   * )&LED0_TASK_STK[0],
                 (CPU_STK_SIZE)LED0_STK_SIZE/10,
                 (CPU_STK_SIZE)LED0_STK_SIZE,
                 (OS_MSG_QTY  )0,
                 (OS_TICK	  )0,
                 (void   	* )0,
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                 (OS_ERR 	* )&err);

    //创建LED1任务
    OSTaskCreate((OS_TCB 	* )&Led1TaskTCB,
                 (CPU_CHAR	* )"led1 task",
                 (OS_TASK_PTR )led1_task,
                 (void		* )0,
                 (OS_PRIO	  )LED1_TASK_PRIO,
                 (CPU_STK   * )&LED1_TASK_STK[0],
                 (CPU_STK_SIZE)LED1_STK_SIZE/10,
                 (CPU_STK_SIZE)LED1_STK_SIZE,
                 (OS_MSG_QTY  )0,
                 (OS_TICK	  )0,
                 (void   	* )0,
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                 (OS_ERR 	* )&err);
    OS_TaskSuspend((OS_TCB*)&StartTaskTCB,&err);		//挂起开始任务
    OS_CRITICAL_EXIT();	//进入临界区
}


/**
  * @brief 任务0 PB8 LED闪烁
  */
void led0_task(void *p_arg)
{
    OS_ERR err;
    p_arg = p_arg;
    while(1)
    {
        flesh_LEDB8(100);
    }
}

/**
  * @brief 任务1  PC13 LED闪烁
  */
void led1_task(void *p_arg)
{
    OS_ERR err;
    p_arg = p_arg;
    while(1)
    {
        flesh_LED(500);
    }
}



/**
  * @brief LED闪烁PC13
  * @param Delay 延时ms
  * @retval None
  */
void flesh_LED(int Delay)
{  //闪烁一个LED PC13 自定义函数
    PCout(13) =0;

    delay_ms(Delay);
    PCout(13) =1;
    delay_ms(Delay);

}

void flesh_LEDB8(int Delay)
{  //闪烁一个LED PC13 自定义函数
    PBout(8) =0;
    delay_ms(Delay);
    PBout(8) =1;
    delay_ms(Delay);
}

  运行程序后可以发现PC13 和PB8 通过位带操作以不同的频率进行闪烁。

参考链接:https://blog.csdn.net/qq_42660303/article/details/107931915

     https://blog.csdn.net/chuancey_cc/article/details/84844740

  

  

   

  

原文地址:https://www.cnblogs.com/siyun/p/14529658.html