在STM32F103C8T6用FreeRTOS实现一些小项目时刚好要用到SG90舵机,刚开始以为比较简单,结果把舵机代码移植过去,创建任务等操作后,发现它报如下错误
Error : ..\FreeRTOS\portable\RVDS\ARM_CM3\port.c,371
Error : .. \FreeRTOS\tasks.c,3074
舵机转了一个小角度后,就不转了,于是想到是不是跟另外一个任务起了冲突,于是把另外一个任务注释掉,结果还是报同样的错误,看来不是跟另外一个任务有冲突。
排除这个问题后,想到舵机转动代码里有delay_ms()函数,于是加入了中断临界段代码保护,并且设置的NVIC优先级低于宏configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY的值, 结果还是报了同样的错误。把另外一个任务打开还是报同样的错误,重新设置了优先级亦是如此。
使用定时器中断实现舵机转动时,需要用到延时函数delay_ms,而delay_ms()其实就是对 FreeRTOS 中的延时函数 vTaskDelay()的 简单封装,所以在使用 delay_ms()的时候就会导致任务切换,导致使用外部中断时报错。
使用定时器(这里使用的是TIM4,PWM引脚PB9)实现舵机转动时,不使用中断,在任务中调用实现舵机转动的函数。如下所示:
定时器代码:
void Timer_Init(u16 Period,u16 Prescaler){
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_InitStructure;
TIM_OCInitTypeDef PWM_InitStructure;
// NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
GPIO_InitStructure.GPIO_Pin = PWM0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIO_PWM,&GPIO_InitStructure);
TIM_InitStructure.TIM_Period = Period;
TIM_InitStructure.TIM_Prescaler = Prescaler;
TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_InitStructure.TIM_RepetitionCounter = DISABLE;
TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4,&TIM_InitStructure);
TIM_ClearFlag(TIM4,TIM_FLAG_Update|TIM_FLAG_Trigger);
// TIM_ITConfig(TIM4,TIM_IT_Update|TIM_IT_Trigger,ENABLE);
TIM_Cmd(TIM4,ENABLE);
PWM_InitStructure.TIM_OCMode = TIM_OCMode_PWM1;
PWM_InitStructure.TIM_OutputState = TIM_OutputState_Enable;
PWM_InitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC4Init(TIM4,&PWM_InitStructure);
TIM_OC4PreloadConfig(TIM4,TIM_OCPreload_Enable);
// NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
// NVIC_Init(&NVIC_InitStructure);
}
舵机转动代码:
void SG90_Turn(void)
{
// status1 = taskENTER_CRITICAL_FROM_ISR();
for(u16 i=500;i<=2500;i+=500){
TIM_SetCompare4(TIM4,i);
delay_ms(1000);
}
for(u16 i=2500;i>=500;i-=500){
TIM_SetCompare4(TIM4,i);
delay_ms(1000);
}
// taskEXIT_CRITICAL_FROM_ISR(status1);
}
使用定时器中断(这里使用的是TIM4,PWM引脚PB9)实现舵机转动时,用延时函数delay_xms(),此函数是对 delay_us()的简单封装,delay_xms()会用来 模拟关闭中断一段时间,此函数不会引起任务调度。代码如下:
void Timer_Init(u16 Period,u16 Prescaler){
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_InitStructure;
TIM_OCInitTypeDef PWM_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
GPIO_InitStructure.GPIO_Pin = PWM0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIO_PWM,&GPIO_InitStructure);
TIM_InitStructure.TIM_Period = Period;
TIM_InitStructure.TIM_Prescaler = Prescaler;
TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_InitStructure.TIM_RepetitionCounter = DISABLE;
TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4,&TIM_InitStructure);
TIM_ClearFlag(TIM4,TIM_FLAG_Update|TIM_FLAG_Trigger);
TIM_ITConfig(TIM4,TIM_IT_Update|TIM_IT_Trigger,ENABLE);
TIM_Cmd(TIM4,ENABLE);
PWM_InitStructure.TIM_OCMode = TIM_OCMode_PWM1;
PWM_InitStructure.TIM_OutputState = TIM_OutputState_Enable;
PWM_InitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC4Init(TIM4,&PWM_InitStructure);
TIM_OC4PreloadConfig(TIM4,TIM_OCPreload_Enable);
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void TIM4_IRQHandler(void){
if(TIM_GetITStatus(TIM4,TIM_IT_Update) != RESET){
for(u16 i=500;i<=2500;i+=500){
TIM_SetCompare4(TIM4,i);
delay_xms(1000);
}
for(u16 i=2500;i>=500;i-=500){
TIM_SetCompare4(TIM4,i);
delay_xms(1000);
}
TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
}
}