单片机
返回首页

stm32——ucos的中断使用

2024-10-08 来源:cnblogs

uCosII移植到stm32上的文章和demo已经很多了,细节上建议大家可以看官方的移植文档(难过当 然是E文的)。网上流传的各种移植版本基本都是基于官方的移植版本做了小改进。这些改进基本都限制在更适合自己的项目或自己的使用习惯上。当然我也一样, 我的改进是为了搭建一个平台,只要stm32+ucos平台都使用这个版本,无论是我使用或是一起开发者,能更快上手。

  uCosII V2.86版本在cortex-m3的移植上面有bug,具体可以自己google一下。我目前使用的是V2.91版本,建立在stm32 V3.40的库基本上。我是强烈要求(或是强制要求)协同开发者使用库函数,除非在速度要求高的情况下或中断里需要直接操作寄存器,也必须使用库的地址定 义,并要求在后面注明对应的库函数。因为程序不是你一个人看的……例如:


/* Clear the selected DMA interrupt pending bits */  

DMA1->IFCR = DMA1_IT_TC4;  //DMA_ClearITPendingBit(DMA1_IT_TC4);  

/* Disable the selected DMAy Channelx */  

DMA1_Channel4->CCR &= (u16)(~DMA_CCR1_EN);//DMA_Cmd(DMA1_Channel4, DISABLE);  


好了,进入正题。uCos在stm32上的移植官方的版本是默认不支持中断嵌套的(个人理解),因为其没有调用 NVIC_PriorityGroupConfig这一函数或使用相同的功能语句。stm32在复位的状态下默认进去 NVIC_PriorityGroup_0,即只要子优先级没有主优先级,即先到先处理,同时到达再按优先级处理。 官方在这上面也是留有空间,因为NVIC_PriorityGroupConfig只能调用一次,采用默认状态,开发者可以加入并完善使用中断嵌套。 


官方的移植把所有的应用中断入口都指向了 BSP_IntHandler这个函数,并定义了一个函数数组static  CPU_FNCT_VOID  BSP_IntVectTbl[BSP_INT_SRC_NBR];因此,如果要加入自己的中断函数的话,只需把自己写的中断函数的指针存入这个数组就 OK了,在初始化中断前调用这函数BSP_IntVectSet。官方的中断优先级设置方式,我全删除了,使用库函数来设置将更直接,但这种中断方式保存 下来,这样中断函数更自由,写中断函数时也不用考虑太多东西,只负责自己要做的东西。


/* 

********************************************************************************************************* 

*                                             INCLUDE FILES 

********************************************************************************************************* 

*/  

  

#define  BSP_INTERRUPT_MODULE  

  

#include   

#include  //STM32芯片内部寄存器定议  

  

#include   

  

#include   

  

/* 

********************************************************************************************************* 

*                                            LOCAL DEFINES 

********************************************************************************************************* 

*/  

#define  BSP_INT_SRC_NBR                                 60  

  

  

/* 

********************************************************************************************************* 

*                                            LOCAL TABLES 

********************************************************************************************************* 

*/  

  

static  CPU_FNCT_VOID  BSP_IntVectTbl[BSP_INT_SRC_NBR];  

  

  

/* 

********************************************************************************************************* 

*                                      LOCAL FUNCTION PROTOTYPES 

********************************************************************************************************* 

*/  

  

static  void  BSP_IntHandler(u16  int_id);  

static  void  BSP_IntHandlerDummy(void);  

  

  

/* 

********************************************************************************************************* 

*                                            BSP_IntVectSet() 

* Description : Assign ISR handler. 

* Argument(s) : int_id      Interrupt for which vector will be set. 

*               isr         Handler to assign 

* Return(s)   : none. 

* Caller(s)   : Application. 

* Note(s)     : none. 

********************************************************************************************************* 

*/  

  

void  BSP_IntVectSet (u16       int_id,  

                      CPU_FNCT_VOID  isr)  

{  

  

#if OS_CRITICAL_METHOD == 3u                            /* Allocate storage for CPU status register    */  

    OS_CPU_SR     cpu_sr = 0u;  

#endif  

      

  

    if(int_id < BSP_INT_SRC_NBR){  

        OS_ENTER_CRITICAL();  

        BSP_IntVectTbl[int_id] = isr;  

        OS_EXIT_CRITICAL();  

    }  

}  


  

/* 

********************************************************************************************************* 

********************************************************************************************************* 

*                                           INTERNAL FUNCTIONS 

********************************************************************************************************* 

********************************************************************************************************* 

*/  

  

/* 

********************************************************************************************************* 

*                                              BSP_IntInit() 

* Description : Initialize interrupts: 

* Argument(s) : none. 

* Return(s)   : none. 

* Caller(s)   : BSP_Init(). 

* Note(s)     : none. 

********************************************************************************************************* 

*/  

  

void  BSP_IntInit (void)  

{  

    u16  int_id;  

    OS_CPU_SR  cpu_sr;  

  

  

    OS_ENTER_CRITICAL();                         /* Tell uC/OS-II that we are starting an ISR          */  

    OSIntNeedSW = OSIntSW_Disable;               // 需退出中断时进行任务调度切换  

    OS_EXIT_CRITICAL();  

  

    for (int_id = 0; int_id < BSP_INT_SRC_NBR; int_id++) {  

        BSP_IntVectSet(int_id, BSP_IntHandlerDummy);  

    }  

}  

  

  

/* 

********************************************************************************************************* 

*                                        BSP_IntHandler####() 

* Description : Handle an interrupt. 

* Argument(s) : none. 

* Return(s)   : none. 

* Caller(s)   : This is an ISR. 

* Note(s)     : none. 

********************************************************************************************************* 

*/  

void  BSP_IntHandlerWWDG          (void)  { BSP_IntHandler(WWDG_IRQn);            }  

void  BSP_IntHandlerPVD           (void)  { BSP_IntHandler(PVD_IRQn);             }  

void  BSP_IntHandlerTAMPER        (void)  { BSP_IntHandler(TAMPER_IRQn);          }  

void  BSP_IntHandlerRTC           (void)  { BSP_IntHandler(RTC_IRQn);             }  

void  BSP_IntHandlerFLASH         (void)  { BSP_IntHandler(FLASH_IRQn);           }  

void  BSP_IntHandlerRCC           (void)  { BSP_IntHandler(RCC_IRQn);             }  

void  BSP_IntHandlerEXTI0         (void)  { BSP_IntHandler(EXTI0_IRQn);           }  

void  BSP_IntHandlerEXTI1         (void)  { BSP_IntHandler(EXTI1_IRQn);           }  

void  BSP_IntHandlerEXTI2         (void)  { BSP_IntHandler(EXTI2_IRQn);           }  

void  BSP_IntHandlerEXTI3         (void)  { BSP_IntHandler(EXTI3_IRQn);           }  

void  BSP_IntHandlerEXTI4         (void)  { BSP_IntHandler(EXTI4_IRQn);           }  

void  BSP_IntHandlerDMA1_CH1      (void)  { BSP_IntHandler(DMA1_Channel1_IRQn);        }  

void  BSP_IntHandlerDMA1_CH2      (void)  { BSP_IntHandler(DMA1_Channel2_IRQn);        }  

void  BSP_IntHandlerDMA1_CH3      (void)  { BSP_IntHandler(DMA1_Channel3_IRQn);        }  

void  BSP_IntHandlerDMA1_CH4      (void)  { BSP_IntHandler(DMA1_Channel4_IRQn);        }  

void  BSP_IntHandlerDMA1_CH5      (void)  { BSP_IntHandler(DMA1_Channel5_IRQn);        }  

void  BSP_IntHandlerDMA1_CH6      (void)  { BSP_IntHandler(DMA1_Channel6_IRQn);        }  

void  BSP_IntHandlerDMA1_CH7      (void)  { BSP_IntHandler(DMA1_Channel7_IRQn);        }  

void  BSP_IntHandlerADC1_2        (void)  { BSP_IntHandler(ADC1_2_IRQn);          }  

void  BSP_IntHandlerUSB_HP_CAN_TX (void)  { BSP_IntHandler(USB_HP_CAN1_TX_IRQn);   }  

void  BSP_IntHandlerUSB_LP_CAN_RX0(void)  { BSP_IntHandler(USB_LP_CAN1_RX0_IRQn);  }  

void  BSP_IntHandlerCAN_RX1       (void)  { BSP_IntHandler(CAN1_RX1_IRQn);         }  

void  BSP_IntHandlerCAN_SCE       (void)  { BSP_IntHandler(CAN1_SCE_IRQn);         }  

void  BSP_IntHandlerEXTI9_5       (void)  { BSP_IntHandler(EXTI9_5_IRQn);         }  

void  BSP_IntHandlerTIM1_BRK      (void)  { BSP_IntHandler(TIM1_BRK_IRQn);        }  

void  BSP_IntHandlerTIM1_UP       (void)  { BSP_IntHandler(TIM1_UP_IRQn);         }  

void  BSP_IntHandlerTIM1_TRG_COM  (void)  { BSP_IntHandler(TIM1_TRG_COM_IRQn);    }  

void  BSP_IntHandlerTIM1_CC       (void)  { BSP_IntHandler(TIM1_CC_IRQn);         }  

void  BSP_IntHandlerTIM2          (void)  { BSP_IntHandler(TIM2_IRQn);            }  

void  BSP_IntHandlerTIM3          (void)  { BSP_IntHandler(TIM3_IRQn);            }  

void  BSP_IntHandlerTIM4          (void)  { BSP_IntHandler(TIM4_IRQn);            }  

void  BSP_IntHandlerI2C1_EV       (void)  { BSP_IntHandler(I2C1_EV_IRQn);         }  

void  BSP_IntHandlerI2C1_ER       (void)  { BSP_IntHandler(I2C1_ER_IRQn);         }  

void  BSP_IntHandlerI2C2_EV       (void)  { BSP_IntHandler(I2C2_EV_IRQn);         }  

void  BSP_IntHandlerI2C2_ER       (void)  { BSP_IntHandler(I2C2_ER_IRQn);         }  

void  BSP_IntHandlerSPI1          (void)  { BSP_IntHandler(SPI1_IRQn);            }  

void  BSP_IntHandlerSPI2          (void)  { BSP_IntHandler(SPI2_IRQn);            }  

void  BSP_IntHandlerUSART1        (void)  { BSP_IntHandler(USART1_IRQn);          }  

void  BSP_IntHandlerUSART2        (void)  { BSP_IntHandler(USART2_IRQn);          }  

void  BSP_IntHandlerUSART3        (void)  { BSP_IntHandler(USART3_IRQn);          }  

void  BSP_IntHandlerEXTI15_10     (void)  { BSP_IntHandler(EXTI15_10_IRQn);       }  

void  BSP_IntHandlerRTCAlarm      (void)  { BSP_IntHandler(RTCAlarm_IRQn);        }  

void  BSP_IntHandlerUSBWakeUp     (void)  { BSP_IntHandler(USBWakeUp_IRQn);       }  

void  BSP_IntHandlerTIM8_BRK      (void)  { BSP_IntHandler(TIM8_BRK_IRQn);        }  

void  BSP_IntHandlerTIM8_UP       (void)  { BSP_IntHandler(TIM8_UP_IRQn);         }  

void  BSP_IntHandlerTIM8_TRG_COM  (void)  { BSP_IntHandler(TIM8_TRG_COM_IRQn);    }  

void  BSP_IntHandlerTIM8_CC       (void)  { BSP_IntHandler(TIM8_CC_IRQn);         }  

void  BSP_IntHandlerADC3          (void)  { BSP_IntHandler(ADC3_IRQn);            }  

void  BSP_IntHandlerFSMC          (void)  { BSP_IntHandler(FSMC_IRQn);            }  

void  BSP_IntHandlerSDIO          (void)  { BSP_IntHandler(SDIO_IRQn);            }  

void  BSP_IntHandlerTIM5          (void)  { BSP_IntHandler(TIM5_IRQn);            }  

void  BSP_IntHandlerSPI3          (void)  { BSP_IntHandler(SPI3_IRQn);            }  

void  BSP_IntHandlerUART4         (void)  { BSP_IntHandler(UART4_IRQn);           }  

void  BSP_IntHandlerUART5         (void)  { BSP_IntHandler(UART5_IRQn);           }  

void  BSP_IntHandlerTIM6          (void)  { BSP_IntHandler(TIM6_IRQn);            }  

void  BSP_IntHandlerTIM7          (void)  { BSP_IntHandler(TIM7_IRQn);            }  

void  BSP_IntHandlerDMA2_CH1      (void)  { BSP_IntHandler(DMA2_Channel1_IRQn);        }  

void  BSP_IntHandlerDMA2_CH2      (void)  { BSP_IntHandler(DMA2_Channel2_IRQn);        }  

void  BSP_IntHandlerDMA2_CH3      (void)  { BSP_IntHandler(DMA2_Channel3_IRQn);        }  

void  BSP_IntHandlerDMA2_CH4_5    (void)  { BSP_IntHandler(DMA2_Channel4_5_IRQn);      }  

  

  

/* 

********************************************************************************************************* 

********************************************************************************************************* 

*                                           LOCAL FUNCTIONS 

********************************************************************************************************* 

********************************************************************************************************* 

*/  

  

/* 

********************************************************************************************************* 

*                                          BSP_IntHandler() 

* Description : Central interrupt handler. 

* Argument(s) : int_id          Interrupt that will be handled. 

* Return(s)   : none. 

* Caller(s)   : ISR handlers. 

* Note(s)     : none. 

********************************************************************************************************* 

*/  

  

static  void  BSP_IntHandler (u16  int_id)  

{  

  

#if OS_CRITICAL_METHOD == 3u                            /* Allocate storage for CPU status register    */  

    OS_CPU_SR     cpu_sr = 0u;  

#endif  

  

    OS_ENTER_CRITICAL();                                      /* 不支持中断嵌套,无需关中断    */  

    OSIntNesting++;  

    OS_EXIT_CRITICAL();  

  

    if (int_id < BSP_INT_SRC_NBR) {  

        BSP_IntVectTbl[int_id]();  

    }  

    OSIntExit();  

}  

  

  

/* 

********************************************************************************************************* 

*                                        BSP_IntHandlerDummy() 

* Description : Dummy interrupt handler. 

* Argument(s) : none. 

* Return(s)   : none. 

* Caller(s)   : BSP_IntHandler(). 

* Note(s)     : none. 

********************************************************************************************************* 

*/  

  

static  void  BSP_IntHandlerDummy (void)  

{  

  

}  


从上代码可以看到,增加了一个全局变量OSIntNeedSW。这个变量的使用是判断退出中断的时候需不需要任务调度,因为你在中断里没有做改变任务优先 级的事,在退出的时候就无需重新调试,如需调度,只需加一个语句 OSIntNeedSW =OSIntSW_Enable;  当然这是临界代码,需关中断。


void  BSP_IntInit (void)  

这一函数必须在开中断前调用一次,初始化必要的变量。


还有两个系统函数必须改动,以实现这功能。在滴答时钟中断中,


void  OS_CPU_SysTickHandler (void)  


{  

    OS_CPU_SR  cpu_sr;  

  

  

    OS_ENTER_CRITICAL();                         /* Tell uC/OS-II that we are starting an ISR          */  

    OSIntNesting++;  

    OSIntNeedSW = OSIntSW_Enable;               // 需退出中断时进行任务调度切换  

    OS_EXIT_CRITICAL();  

  

    OSTimeTick();                                /* Call uC/OS-II's OSTimeTick()                       */  

  

    OSIntExit();                                 /* Tell uC/OS-II that we are leaving the ISR          */  

}  

最后需改动的一个函数是OSIntExit(),


void  OSIntExit (void)  

{  

#if OS_CRITICAL_METHOD == 3u                               /* Allocate storage for CPU status register */  

    OS_CPU_SR  cpu_sr = 0u;  

#endif  

  

    if (OSRunning == OS_TRUE) {  

        OS_ENTER_CRITICAL();  

        if (OSIntNesting > 0u) {                           /* Prevent OSIntNesting from wrapping       */  

            OSIntNesting--;  

        }  

        if (OSIntNesting == 0u) {                          /* Reschedule only if all ISRs complete ... */  

            if(OSIntNeedSW == OSIntSW_Enable){            // 在这判断是否需要任务切换调试  

                OSIntNeedSW = OSIntSW_Disable;  

                if (OSLockNesting == 0u) {                     /* ... and not locked.                      */  

                    OS_SchedNew();  

                    OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];  

                    if (OSPrioHighRdy != OSPrioCur) {          /* No Ctx Sw if current task is highest rdy */  

#if OS_TASK_PROFILE_EN > 0u  

                        OSTCBHighRdy->OSTCBCtxSwCtr++;         /* Inc. # of context switches to this task  */  

#endif  

                        OSCtxSwCtr++;                          /* Keep track of the number of ctx switches */  

                        OSIntCtxSw();                          /* Perform interrupt level ctx switch       */  

                    }                      

                }                  

            }  

        }  

        OS_EXIT_CRITICAL();  

    }  

}  


最终目的,通过增加一个OSIntNeedSW全局变量,来判断退出中断时是否需要进行任务调试切换。这样的话,在一般的中断处理函数处理的退出过程更快,缩短无改变任务优先级中断的处理时间。其实这功能在新的版本ucos III中已经实现了。


之前使用的版本我还按网上一些人的做法更改了ucos的移植文件,如下图,这是任务切换的时候,如果不使用OSTaskSwHook可以屏蔽下面四行汇编。大笑,省四条语句。


 ; At this point, entire context of process has been saved  

PU_PendSVHandler_nosave  

;PUSH    {R14}                                               ; Save LR exc_return value  

;LDR     R0, =OSTaskSwHook                                   ; OSTaskSwHook();  

;BLX     R0  

;POP     {R14}  

  

LDR     R0, =OSPrioCur                                      ; OSPrioCur = OSPrioHighRdy;  

LDR     R1, =OSPrioHighRdy  

LDRB    R2, [R1]  

STRB    R2, [R0]  

  

LDR     R0, =OSTCBCur                                       ; OSTCBCur  = OSTCBHighRdy;  

LDR     R1, =OSTCBHighRdy  

LDR     R2, [R1]  

STR     R2, [R0]  

  

LDR     R0, [R2]                                            ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;  

LDM     R0, {R4-R11}                                        ; Restore r4-11 from new process stack  

ADDS    R0, R0, #0x20  

MSR     PSP, R0                                             ; Load PSP with new process SP  

ORR     LR, LR, #0x04                                       ; Ensure exception return uses process stack  

CPSIE   I  

BX      LR                                                  ; Exception return will restore  


强烈推荐在调试阶段加入,并开启这宏定义


#ifdef USE_FULL_ASSERT  

/****************************************************************************** 

* Function Name  : assert_failed 

* Description    : Reports the name of the source file and the source line  

number 

*                  where the assert_param error has occurred. 

* Input          : - file: pointer to the source file name 

*                  - line: assert_param error line source number 

* Output         : None 

* Return         : None 

*******************************************************************************/  

void assert_failed(uint8_t* file, uint32_t line)  

{  

  /* User can add his own implementation to report the file name and line number, 

     ex: printf('Wrong parameters value: file %s on line %drn', file, line)  

*/  

  

  /* Infinite loop */  

    while (1)  

    {}  

}  

#endif 


进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 1瓦线性调频增强器

  • 家用电器遥控器

  • 12V 转 28V DC-DC 变换器(基于 LM2585)

  • 红外开关

  • DS1669数字电位器

  • HA1377 桥式放大器 BCL 电容 17W(汽车音频)

    相关电子头条文章