STM32F103C8T6搭载FreeRTOS时使用SG90舵机遇到的问题及解决办法

遇到的问题

  在STM32F103C8T6用FreeRTOS实现一些小项目时刚好要用到SG90舵机,刚开始以为比较简单,结果把舵机代码移植过去,创建任务等操作后,发现它报如下错误

Error : ..\FreeRTOS\portable\RVDS\ARM_CM3\port.c,371

Error : .. \FreeRTOS\tasks.c,3074
 

STM32F103C8T6搭载FreeRTOS时使用SG90舵机遇到的问题及解决办法_第1张图片

舵机转了一个小角度后,就不转了,于是想到是不是跟另外一个任务起了冲突,于是把另外一个任务注释掉,结果还是报同样的错误,看来不是跟另外一个任务有冲突。

排除这个问题后,想到舵机转动代码里有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);
	}
}

你可能感兴趣的:(FreeRTOS,单片机,stm32,嵌入式硬件)