STM32入门学习笔记之uCOS-II系统移植3

发布者:alpha12最新更新时间:2024-05-17 来源: elecfans关键字:STM32  uCOS-II  系统移植 手机看文章 扫描二维码
随时随地手机看文章

⑤这两个函数都用于任务切换,它们的本质都是触发PendSV中断,具体切换过程在PendSV的中断函数中进行,其中OSCtxSw是任务级切换,OSIntCtxSw是中断级切换,是从中断退出时切换到一个任务中,从中断切换到任务的过程中,CPU的寄存器入栈工作已经完成。


OSCtxSw

  PUSH    {R4, R5}

  LDR     R4, =NVIC_INT_CTRL        ;触发PendSV异常

  LDR     R5, =NVIC_PENDSVSET

  STR     R5, [R4]              ;向NVIC_INT_CTRL写入NVIC_PENDSVSET触发PendSV中断

  POP     {R4, R5}

  BX      LR

OSIntCtxSw

  PUSH    {R4, R5}

  LDR     R4, =NVIC_INT_CTRL        ;触发PendSV异常

  LDR     R5, =NVIC_PENDSVSET

  STR     R5, [R4]              ;向NVIC_INT_CTRL写入NVIC_PENDSVSET触发PendSV中断

  POP     {R4, R5}

  BX      LR

  NOP

⑥这部分代码才是真正的任务切换函数,通过触发PendSV中断来进入该函数内进行任务切换



PendSV_Handler

  CPSID  I                                ;任务切换过程中必须关闭所有中断

  MRS    R0, PSP                          ;如果在用PSP堆栈,则可以忽略保存寄存器

  CBZ    R0, PendSV_Handler_Nosave    ;如果PSP为0就转移到PendSV_Handler_Nosave



  SUBS    R0, R0, #0x20                                        ;R0-=20H

  STM     R0, {R4-R11}



  LDR     R1, =OSTCBCur

  LDR     R1, [R1]

  STR     R0, [R1]



PendSV_Handler_Nosave

    PUSH    {R14}              ;保存R14的值

    LDR     R0, =OSTaskSwHook        ;调用OSTaskSwHook()

    BLX     R0

    POP     {R14}



    LDR     R0, =OSPrioCur

    LDR     R1, =OSPrioHighRdy

    LDRB    R2, [R1]

    STRB    R2, [R0]



    LDR     R0, =OSTCBCur

    LDR     R1, =OSTCBHighRdy

    LDR     R2, [R1]

    STR     R2, [R0]



    LDR     R0, [R2]              ;R0作为新任务的SP

    LDM     R0, {R4-R11}            ;从堆栈中恢复R4-R11

    ADDS    R0, R0, #0x20

    MSR     PSP, R0              ;用新任务的SP加载PSP

    ORR     LR, LR, #0x04          ;确保LR的bit2为1,返回后使用进程堆栈

    CPSIE   I                ;开启所有中断

    BX      LR                ;中断返回



  end

(2)os_cpu.h文件详解


①这部分主要用于定义一些数据类型,其中重点关注OS_STK这个数据类型,我们在定义任务堆栈的时候就是该类型数据,这是一个32位的数据类型,按字节算的话实际堆栈大小是我们定义的4倍。


typedef unsigned char  BOOLEAN;

typedef unsigned char  INT8U;

typedef signed   char  INT8S;

typedef unsigned short INT16U;

typedef signed   short INT16S;

typedef unsigned int   INT32U;

typedef signed   int   INT32S;

typedef float          FP32;

typedef double         FP64;



typedef unsigned int   OS_STK;

typedef unsigned int   OS_CPU_SR;

②这部分代码定义了堆栈的增长方向,任务机切换的宏定义OS_TASK_SW,如果OS_CRITICAL_METHOD被定义为3的话那么进出临界段的宏定义分别为OS_ENTER_CRITICAL和OS_EXIT_CRITICAL,这两个函数都是用汇编语言编写的


//OS_CRITICAL_METHOD = 1 :直接使用处理器的开关中断指令来实现宏 

//OS_CRITICAL_METHOD = 2 :利用堆栈保存和恢复CPU的状态 

//OS_CRITICAL_METHOD = 3 :利用编译器扩展功能获得程序状态字,保存在局部变量cpu_sr



#define  OS_CRITICAL_METHOD   3     //进入临界段的方法



#if OS_CRITICAL_METHOD == 3

#define  OS_ENTER_CRITICAL()  {cpu_sr = OS_CPU_SR_Save();}

#define  OS_EXIT_CRITICAL()   {OS_CPU_SR_Restore(cpu_sr);}

#endif



void       OSCtxSw(void);

void       OSIntCtxSw(void);

void       OSStartHighRdy(void);

void       OSPendSV(void);



#if OS_CRITICAL_METHOD == 3u

OS_CPU_SR  OS_CPU_SR_Save(void);

void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);

#endif

OS_CPU_EXT INT32U OSInterrputSum;

(3)sys.h文件修改


添加关于条件编译的定义,在文件中添加以下代码即可。


#define SYSTEM_SUPPORT_OS 1


当宏定义为1的时候,编译器在编译的时候会只编译满足条件的代码,当为0时,这部分代码不会被编译。


(4)delay.c文件修改


①添加Sys_Tick中断服务函数与函数定义


#include 'includes.h'

//支持UCOSII

#ifdef  OS_CRITICAL_METHOD

#define delay_osrunning    OSRunning              //OS是否运行标记,0,不运行;1,在运行

#define delay_ostickspersec  OS_TICKS_PER_SEC            //OS时钟节拍,即每秒调度次数

#define delay_osintnesting  OSIntNesting                //中断嵌套级别,即中断嵌套次数

#endif

//systick中断服务函数,使用OS时用到

void SysTick_Handler()

{

  //OS开始跑了,才执行正常的调度处理

  if( delay_osrunning==1 )

  {

    OSIntEnter() ;                        //进入中断

    OSTimeTick() ;                      //调用ucos的时钟服务程序

    OSIntExit() ;                        //触发任务切换软中断

  }

}

②时钟初始化函数修改


复制

void SysTick_Init( u8 SYSCLK )

{

#if SYSTEM_SUPPORT_OS

  u32 reload;

#endif

   SysTick->CTRL &= ~( 1<<2 ) ;                  //SYSTICK使用外部时钟源

  fac_us = SYSCLK/8 ;                      //fac_us都需要使用

#if SYSTEM_SUPPORT_OS

  reload = SYSCLK/8 ;                      //每秒钟的计数次数,单位为K     

  reload *= 1000000/delay_ostickspersec ;              //根据delay_ostickspersec设定溢出时间

  fac_ms = 1000/delay_ostickspersec ;                //代表OS可以延时的最少单位

  SysTick->CTRL |= 1<<1 ;                    //开启SYSTICK中断

  SysTick->LOAD = reload ;                    //每1/delay_ostickspersec秒中断一次

  SysTick->CTRL |= 1<<0 ;                    //开启SYSTICK

#else

  fac_ms = ( u16 )fac_us*1000 ;                  //代表每个ms需要的systick时钟数

#endif

}


关键字:STM32  uCOS-II  系统移植 引用地址:STM32入门学习笔记之uCOS-II系统移植3

上一篇:基于STM32的空气处理机组DDC控制器设计
下一篇:STM32入门学习笔记之uCOS-II系统移植2

推荐阅读最新更新时间:2024-11-06 16:33

STM32基础知识1-stm32PWM输入捕获模式详解
一、概念理解 PWM输入捕获模式是输入捕获模式的特例,自己理解如下 1. 每个定时器有四个输入捕获通道IC1、IC2、IC3、IC4。且IC1 IC2一组,IC3 IC4一组。并且可是设置管脚和寄存器的对应关系。 2. 同一个TIx输入映射了两个ICx信号。 3. 这两个ICx信号分别在相反的极性边沿有效。 4. 两个边沿信号中的一个被选为触发信号,并且从模式控制器被设置成复位模式。 5. 当触发信号来临时,被设置成触发输入信号的捕获寄存器,捕获“一个PWM周期(即连续的两个上升沿或下降沿)”,它等于包含TIM 时钟周期的个数(即捕获寄存器中捕获的为TIM的计数个数n)。 6. 同样另一个捕获通道捕获触发信号和下一个相反极性的边
[单片机]
如何将ADC与带有LCD的stm32 Discovery板一起使用
步骤1:ADC 使用HAL Cube,ADC的实现非常简单(在第1部分中提到)。 我正在使用 12位ADC模块 ADC预分频器= 8 转换数= 1 ADC分辨率= 128 采样时间为112个周期。 我们还可以将ADC与DMA一起使用。用于它的IRQ处理程序是 HAL_DMA_IRQHandler(AdcHandle.DMA_Handle) ,其中AdcHandle是ADC_HandleTypeDef类型。 要显示ADC值,我们必须使用uint32t uhADCxConvertedValue的外部值。它将值从0转换为4096(2 ^ 12),因此如果要显示从0开始的电压-3V,我们必须做简单的计算 uhADCxConverted
[单片机]
如何将ADC与带有LCD的<font color='red'>stm32</font> Discovery板一起使用
详解STM32的时钟系统
STM32的时钟树 时钟信号推动单片机内各个部分执行相应的指令,时钟就像人的心跳一样。 STM32本身十分复杂,外设非常多,任何外设都需要时钟才能启动,但并不是所有的外设都需要系统时钟那么高的频率,如果都用高速时钟势必造成浪费。同一个电路,时钟越快功耗越大、抗电磁干扰能力越弱。复杂的MCU采用多时钟源的方法来解决这些问题。如下图,是STM32的时钟系统框图。 如上图左边的部分,看到STM32有4个独立时钟源,HSI、HSE、LSI、LSE。 HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高。 HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。 LSI是低速内部时钟,RC
[单片机]
ST全新软件包可支持开发Azure RTOS,加快智能产品研发
半导体供应商意法半导体(STMicroelectronics,简称ST;纽约证券交易所代码:STM) 加大对基于Microsoft®Azure RTOS平台的下一代智能物联网设备的开发支持,发布面向产品研发团队的功能丰富的STM32Cube扩展包系列的首个软件包。 意法半导体和微软于2020年宣布,开发者可以从意法半导体的STM32Cube *生态系统直接使用Azure RTOS套件。基于这项合作计划,新软件包提供更多的应用代码示例,帮助工程师克服常见的开发挑战,缩短产品上市时间。 软件包免版税,开发人员可以立即使用和自定义代码示例。 意法半导体副总裁、微控制器事业部总经理Ricardo de Sa Earp表示: “
[单片机]
ST全新软件包可支持开发Azure RTOS,加快智能产品研发
STM32开发板学习日记-[5]TIM的PMW模式
脉冲宽度调制模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。 在TIMx_CCMRx寄存器中的OCxM位写入 110 (PWM模式1)或 111 (PWM模式2),能够独立地设置每个OCx输出通道产生一路PWM。必须设置TIMx_CCMRx寄存器OCxPE位以使能相应的预装载寄存器,最后还要设置TIMx_CR1寄存器的ARPE位使能自动重装载的预装载寄存器(在向上计数或中心对称模式中)。 因为仅当发生一个更新事件的时候,预装载寄存器才能被传送到影子寄存器,因此在计数器开始计数之前,必须通过设置TIMx_EGR寄存器中的UG位来初始化所有的寄存器。 OCx的极性可以通过软件在TIMx_C
[单片机]
STM32存储器 — <3> STM32实现IAP
在对STM32存储器结构及相关知识了解后,我们就可以进行IAP的设计了。 在上一篇笔记中,进行了一个简单的IAP程序结构,以及和User App程序的相互联系的系统设计。 本篇对IAP实现的细节进行了较为详细的论述,包括源码结构的设计;我们从上位机(PC C#)和下位机(MCU C)共同描述IAP功能的实现过程。 1 STM32的IAP实现平台 IAP功能的实现需要两个方面(上位机和STM32上的IAP程序)的密切合作。因此,我们除了需要知道STM32芯片上的IAP程序结构,我们还需要了解上位机的程序结构,这样才能使上位机和STM32很好的相互工作。 下位机(指的是STM32构成的单片机系统): 本下位机系统使用C语言进行
[单片机]
RT-Thread学习笔记【stm32】(二):线程的创建中的一些问题
本文作者在实现对RTT的线程创建的过程中,发现了一些问题。 首先,我初始化了三个线程a,b,c。 但是在start 的过程中,我发现了一个神奇的现象,那就是,我只能初始化前两个线程, 第三个线程总是初始化失败。 而后我想到可能是,优先级的设置出现问题,于是我更换各种优先级之后发现,问题并没有得到解决。 再后来,我想到了一个重要的问题,那就是我用的是最小板STM,那么会不会是32的ram不够大,而 我的任务堆栈设置的过大,到导致任务无法初始化。 而后,我降低了任务的堆栈,发现,成功开始了线程。
[单片机]
三种串口接收不定长数据方法详解
方法1:串口接受数据,定时器来判断超时是否接受数据完成。 方法2:DMA接受+IDLE中断 实现思路:采用STM32F103的串口1,并配置成空闲中断IDLE模式且使能DMA接收,并同时设置接收缓冲区和初始化DMA。那么初始化完成之后,当外部给单片机发送数据的时候,假设这帧数据长度是200个字节,那么在单片机接收到一个字节的时候并不会产生串口中断,而是DMA在后台把数据默默地搬运到你指定的缓冲区里面。当整帧数据发送完毕之后串口才会产生一次中断,此时可以利用DMA_GetCurrDataCounter();函数计算出本次的数据接受长度,从而进行数据处理。 应用对象:适用于各种串口相关的通信协议,如:MODBUS,PPI ;还有
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved