ucos移植起来不算简单,所以官方很贴心的提供了移植好的工程,包括keil和IAR工程。去官网https://www.micrium.com/downloadcenter/,然后找到自己使用的MCU下载即可,下载需要账号,如果你懒得注册,并且你使用的是STM32F4xx系列芯片的话,可以从网盘下载https://pan.baidu.com/s/1DCr059UvCrW4o5ZiIMj1Fg密码:b7ci。
此坑不仅在ucos官方例程中出现,在其他开发过程中也应当注意,那就是RCC的配置问题。官方例程中的RCC初始化给出了中规中矩的STM32F4xx时钟配置,即配置SYSCLK为168MHz、PCLK1为42MHz、PCLK2为84MHz等等。但需要注意的是官方例程中默认使用了外部晶振,并且是25MHz的外部晶振,而大多数情况下,无论是开发板还是产品中,使用最多的是8MHz晶振,所以要将程序中定义的外部晶振改为8000000,且修改RCC初始化中M分频为8.
如果你是使用的keil,那么你在Options for Target中选中Target选项卡,修改Xtal为8MHz。另一个更加通用的办法为直接修改程序,在stm32f4xx_hal_conf.h中修改HSE_VALUE的值为8000000。
在平时开发中若发现程序无误,串口、IIC、SPI等等各种东西都莫名通讯失败,首先考虑是否时钟树配置有误,可以通过HAL_RCC_getPCLK等函数看看是否和预期的时钟树一致。
跟裸机中不同的是,ucos中对中断向量的函数接口做了修改。打个比方,比如串口2中断,从裸机的启动文件中可以看出,其接口函数为USART2_IRQHandler,也就是说当发生串口2中断后会根据中断向量表进而跳到USART2_IRQHandler中断处理函数。而ucos中将接口函数写为了BSP_IntHandlerUSART2,并且从bsp_int.c中可以看出,ucos中所有中断接口函数都被统一的管理到了BSP_IntHandler中,如以下代码所示:
void BSP_IntHandlerWWDG (void) { BSP_IntHandler(BSP_INT_ID_WWDG); }
void BSP_IntHandlerPVD (void) { BSP_IntHandler(BSP_INT_ID_PVD); }
void BSP_IntHandlerTAMP_STAMP (void) { BSP_IntHandler(BSP_INT_ID_TAMP_STAMP); }
void BSP_IntHandlerRTC_WKUP (void) { BSP_IntHandler(BSP_INT_ID_RTC_WKUP); }
void BSP_IntHandlerFLASH (void) { BSP_IntHandler(BSP_INT_ID_FLASH); }
void BSP_IntHandlerRCC (void) { BSP_IntHandler(BSP_INT_ID_RCC); }
void BSP_IntHandlerEXTI0 (void) { BSP_IntHandler(BSP_INT_ID_EXTI0); }
void BSP_IntHandlerEXTI1 (void) { BSP_IntHandler(BSP_INT_ID_EXTI1); }
void BSP_IntHandlerEXTI2 (void) { BSP_IntHandler(BSP_INT_ID_EXTI2); }
void BSP_IntHandlerEXTI3 (void) { BSP_IntHandler(BSP_INT_ID_EXTI3); }
void BSP_IntHandlerEXTI4 (void) { BSP_IntHandler(BSP_INT_ID_EXTI4); }
void BSP_IntHandlerDMA1_CH0 (void) { BSP_IntHandler(BSP_INT_ID_DMA1_CH0); }
void BSP_IntHandlerDMA1_CH1 (void) { BSP_IntHandler(BSP_INT_ID_DMA1_CH1); }
void BSP_IntHandlerDMA1_CH2 (void) { BSP_IntHandler(BSP_INT_ID_DMA1_CH2); }
void BSP_IntHandlerDMA1_CH3 (void) { BSP_IntHandler(BSP_INT_ID_DMA1_CH3); }
void BSP_IntHandlerDMA1_CH4 (void) { BSP_IntHandler(BSP_INT_ID_DMA1_CH4); }
void BSP_IntHandlerDMA1_CH5 (void) { BSP_IntHandler(BSP_INT_ID_DMA1_CH5); }
void BSP_IntHandlerDMA1_CH6 (void) { BSP_IntHandler(BSP_INT_ID_DMA1_CH6); }
void BSP_IntHandlerADC (void) { BSP_IntHandler(BSP_INT_ID_ADC); }
void BSP_IntHandlerCAN1_TX (void) { BSP_IntHandler(BSP_INT_ID_CAN1_TX); }
void BSP_IntHandlerCAN1_RX0 (void) { BSP_IntHandler(BSP_INT_ID_CAN1_RX0); }
void BSP_IntHandlerCAN1_RX1 (void) { BSP_IntHandler(BSP_INT_ID_CAN1_RX1); }
void BSP_IntHandlerCAN1_SCE (void) { BSP_IntHandler(BSP_INT_ID_CAN1_SCE); }
void BSP_IntHandlerEXTI9_5 (void) { BSP_IntHandler(BSP_INT_ID_EXTI9_5); }
void BSP_IntHandlerTIM1_BRK_TIM9 (void) { BSP_IntHandler(BSP_INT_ID_TIM1_BRK_TIM9); }
void BSP_IntHandlerTIM1_UP_TIM10 (void) { BSP_IntHandler(BSP_INT_ID_TIM1_UP_TIM10); }
void BSP_IntHandlerTIM1_TRG_COM_TIM11 (void) { BSP_IntHandler(BSP_INT_ID_TIM1_TRG_COM_TIM11); }
void BSP_IntHandlerTIM1_CC (void) { BSP_IntHandler(BSP_INT_ID_TIM1_CC); }
void BSP_IntHandlerTIM2 (void) { BSP_IntHandler(BSP_INT_ID_TIM2); }
void BSP_IntHandlerTIM3 (void) { BSP_IntHandler(BSP_INT_ID_TIM3); }
void BSP_IntHandlerTIM4 (void) { BSP_IntHandler(BSP_INT_ID_TIM4); }
void BSP_IntHandlerI2C1_EV (void) { BSP_IntHandler(BSP_INT_ID_I2C1_EV); }
void BSP_IntHandlerI2C1_ER (void) { BSP_IntHandler(BSP_INT_ID_I2C1_ER); }
void BSP_IntHandlerI2C2_EV (void) { BSP_IntHandler(BSP_INT_ID_I2C2_EV); }
void BSP_IntHandlerI2C2_ER (void) { BSP_IntHandler(BSP_INT_ID_I2C2_ER); }
void BSP_IntHandlerSPI1 (void) { BSP_IntHandler(BSP_INT_ID_SPI1); }
void BSP_IntHandlerSPI2 (void) { BSP_IntHandler(BSP_INT_ID_SPI2); }
void BSP_IntHandlerUSART1 (void) { BSP_IntHandler(BSP_INT_ID_USART1); }
void BSP_IntHandlerUSART2 (void) { BSP_IntHandler(BSP_INT_ID_USART2); }
void BSP_IntHandlerUSART3 (void) { BSP_IntHandler(BSP_INT_ID_USART3); }
void BSP_IntHandlerEXTI15_10 (void) { BSP_IntHandler(BSP_INT_ID_EXTI15_10); }
void BSP_IntHandlerRTCAlarm (void) { BSP_IntHandler(BSP_INT_ID_RTC_ALARM); }
void BSP_IntHandlerOTG_FS_WKUP (void) { BSP_IntHandler(BSP_INT_ID_OTG_FS_WKUP); }
void BSP_IntHandlerTIM8_BRK_TIM12 (void) { BSP_IntHandler(BSP_INT_ID_TIM8_BRK_TIM12); }
void BSP_IntHandlerTIM8_UP_TIM13 (void) { BSP_IntHandler(BSP_INT_ID_TIM8_UP_TIM13); }
void BSP_IntHandlerTIM8_TRG_COM_TIM14 (void) { BSP_IntHandler(BSP_INT_ID_TIM8_TRG_COM_TIM14); }
void BSP_IntHandlerTIM8_CC (void) { BSP_IntHandler(BSP_INT_ID_TIM8_CC); }
void BSP_IntHandlerDMA1_STREAM7 (void) { BSP_IntHandler(BSP_INT_ID_DMA1_STREAM7); }
void BSP_IntHandlerFSMC (void) { BSP_IntHandler(BSP_INT_ID_FSMC); }
void BSP_IntHandlerSDIO (void) { BSP_IntHandler(BSP_INT_ID_SDIO); }
void BSP_IntHandlerTIM5 (void) { BSP_IntHandler(BSP_INT_ID_TIM5); }
void BSP_IntHandlerSPI3 (void) { BSP_IntHandler(BSP_INT_ID_SPI3); }
void BSP_IntHandlerUSART4 (void) { BSP_IntHandler(BSP_INT_ID_USART4); }
void BSP_IntHandlerUSART5 (void) { BSP_IntHandler(BSP_INT_ID_USART5); }
void BSP_IntHandlerTIM6_DAC (void) { BSP_IntHandler(BSP_INT_ID_TIM6_DAC); }
void BSP_IntHandlerTIM7 (void) { BSP_IntHandler(BSP_INT_ID_TIM7); }
void BSP_IntHandlerDMA2_CH0 (void) { BSP_IntHandler(BSP_INT_ID_DMA2_CH0); }
void BSP_IntHandlerDMA2_CH1 (void) { BSP_IntHandler(BSP_INT_ID_DMA2_CH1); }
void BSP_IntHandlerDMA2_CH2 (void) { BSP_IntHandler(BSP_INT_ID_DMA2_CH2); }
void BSP_IntHandlerDMA2_CH3 (void) { BSP_IntHandler(BSP_INT_ID_DMA2_CH3); }
void BSP_IntHandlerDMA2_CH4 (void) { BSP_IntHandler(BSP_INT_ID_DMA2_CH4); }
void BSP_IntHandlerETH (void) { BSP_IntHandler(BSP_INT_ID_ETH); }
void BSP_IntHandlerETHWakeup (void) { BSP_IntHandler(BSP_INT_ID_ETH_WKUP); }
void BSP_IntHandlerCAN2_TX (void) { BSP_IntHandler(BSP_INT_ID_CAN2_TX); }
void BSP_IntHandlerCAN2_RX0 (void) { BSP_IntHandler(BSP_INT_ID_CAN2_RX0); }
void BSP_IntHandlerCAN2_RX1 (void) { BSP_IntHandler(BSP_INT_ID_CAN2_RX1); }
void BSP_IntHandlerCAN2_SCE (void) { BSP_IntHandler(BSP_INT_ID_CAN2_SCE); }
void BSP_IntHandlerOTG_FS (void) { BSP_IntHandler(BSP_INT_ID_OTG_FS); }
void BSP_IntHandlerDMA2_CH5 (void) { BSP_IntHandler(BSP_INT_ID_DMA2_CH5); }
void BSP_IntHandlerDMA2_CH6 (void) { BSP_IntHandler(BSP_INT_ID_DMA2_CH6); }
void BSP_IntHandlerDMA2_CH7 (void) { BSP_IntHandler(BSP_INT_ID_DMA2_CH7); }
void BSP_IntHandlerUSART6 (void) { BSP_IntHandler(BSP_INT_ID_USART6); }
void BSP_IntHandlerI2C3_EV (void) { BSP_IntHandler(BSP_INT_ID_I2C3_EV); }
void BSP_IntHandlerI2C3_ER (void) { BSP_IntHandler(BSP_INT_ID_I2C3_ER); }
void BSP_IntHandlerOTG_HS_EP1_OUT (void) { BSP_IntHandler(BSP_INT_ID_OTG_HS_EP1_OUT); }
void BSP_IntHandlerOTG_HS_EP1_IN (void) { BSP_IntHandler(BSP_INT_ID_OTG_HS_EP1_IN); }
void BSP_IntHandlerOTG_HS_WKUP (void) { BSP_IntHandler(BSP_INT_ID_OTG_HS_WKUP); }
void BSP_IntHandlerOTG_HS (void) { BSP_IntHandler(BSP_INT_ID_OTG_HS); }
void BSP_IntHandlerDCMI (void) { BSP_IntHandler(BSP_INT_ID_DCMI); }
void BSP_IntHandlerCRYP (void) { BSP_IntHandler(BSP_INT_ID_CRYP); }
void BSP_IntHandlerHASH_RNG (void) { BSP_IntHandler(BSP_INT_ID_HASH_RNG); }
void BSP_IntHandlerFPU (void) { BSP_IntHandler(BSP_INT_ID_FPU); }
BSP_IntHandler函数如下所示:
static void BSP_IntHandler (CPU_DATA int_id)
{
CPU_FNCT_VOID isr;
CPU_SR_ALLOC();
CPU_CRITICAL_ENTER(); /* Tell the OS that we are starting an ISR */
OSIntEnter();
CPU_CRITICAL_EXIT();
if (int_id < BSP_INT_SRC_NBR) {
isr = BSP_IntVectTbl[int_id];
if (isr != (CPU_FNCT_VOID)0u) {
isr();
}
}
OSIntExit(); /* Tell the OS that we are leaving the ISR */
}
也就是说当发生中断时,BSP_IntHandler根据所传进来的参数将id放入中断待处理队列中,然后系统调度去执行中断。比如USART2中断发生时,就向BSP_IntHandler中传入BSP_INT_ID_USART2,这个是个宏定义,为一个整数。那么BSP_IntHandler就会根据这个id去执行相应的中断处理函数。那么问题来了,这个id绑定的处理函数是什么呢?这就是ucos中断配置和裸机不同的地方。在打开中断使能后,一定要记得加上以下代码:
BSP_IntVectSet(BSP_INT_ID_USART2, MY_BSP_IntHandlerUSART2);
BSP_IntEn(BSP_INT_ID_USART2);
这就是ucos的中断id和中断处理函数绑定的语句。也就是说BSP_INT_ID_USART2这个中断id和MY_BSP_IntHandlerUSART2函数绑定起来,发生中断后就跳到MY_BSP_IntHandlerUSART2中去执行了。MY_BSP_IntHandlerUSART2里的内容就是常规的请标志位、读数据等操作,和裸机无异。