13.增改源代码,实现LED的控制

13.增改源代码,实现LED的控制


  初学STM FOC或者需要尽快应用到工程项目中,在电机能大致驱动运转时,需要加入其它交互的接口方式,使得能更容易控制电机和判断电机状态。这时,可以加入LED灯的闪烁状态,加入通讯接口并拟定通讯协议实现控制和监控。
  本文主要介绍在workbench生成好的代码中,直接添加LED控制的代码,来表达电机当前的运行状态。我会用到一个PA8引脚控制LED,用TIM3来产生LED闪烁的时钟频率,根据电机的STM结构体来判断电机状态。


1.使能LED控制接口

//初始化PB1为输出.并使能时钟	    
//LED IO初始化
void LED_Init(void)
{
    GPIO_InitTypeDef GPIO_Initure;
    __HAL_RCC_GPIOA_CLK_ENABLE();           //开启GPIOA时钟
	
    GPIO_Initure.Pin=GPIO_PIN_8; //PA8
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;     //高速
    HAL_GPIO_Init(GPIOA,&GPIO_Initure);
	
    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,GPIO_PIN_RESET);	//PA8置0,默认初始化后灯灭
}

初始化LED灯的函数调用很简单

2.使能TIM3作为时基

使能TIM3时,我只用了一个函数来实现定时时间的设定,这样方便调用和修改。
定时器初始化函数在main中LED的初始化后面调用就行。
我设置的是100ms时基:TIM3_Init(1000-1,8400-1); //定时器3初始化,定时器时钟为84M,分频系数为8400-1,
其实,如果单是点亮LED的闪烁,完全可以加到电机控制的中频任务函数块中去。但我后续还会用到TIM时基,就使能TIM3来做LED的定时控制了。

//通用定时器3中断初始化
//arr:自动重装值。
//psc:时钟预分频数
//定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.
//Ft=定时器工作频率,单位:Mhz
//这里使用的是定时器3!(定时器3挂在APB1上,时钟为HCLK/2)
void TIM3_Init(u16 arr,u16 psc)
{  
    TIM3_Handler.Instance=TIM3;                          //通用定时器3
    TIM3_Handler.Init.Prescaler=psc;                     //分频系数
    TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;    //向上计数器
    TIM3_Handler.Init.Period=arr;                        //自动装载值
    TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;//时钟分频因子
    HAL_TIM_Base_Init(&TIM3_Handler);
    
    HAL_TIM_Base_Start_IT(&TIM3_Handler); //使能定时器3和定时器3更新中断:TIM_IT_UPDATE   
}

在stm32f3xx_hal_msp.c文件中的
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)函数里加入了这段代码来开启TIM3的中断

	if(htim_base->Instance==TIM3)
	{
		__HAL_RCC_TIM3_CLK_ENABLE();            //使能TIM3时钟
		HAL_NVIC_SetPriority(TIM3_IRQn,1,3);    //设置中断优先级,抢占优先级1,子优先级3
		HAL_NVIC_EnableIRQ(TIM3_IRQn);          //开启ITM3中断   
	}

3.TIM3中断服务完成指定闪烁

这段代码是,TIM3中断函数的回调、LED闪烁控制的结构体定义、TIM3实际的中断服务函数、设置LED闪烁规律的函数。

//定时器3中断服务函数
void TIM3_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&TIM3_Handler);
}



typedef struct
{
	u8 uDelay100ms;  //亮灭间隔时间
  u8 uLightOnNb;     //点亮次数
  u8 uLightOffNb;   //熄灭间隔
}LightCtr;


LightCtr LightCtruser={5,1,0};


//回调函数,定时器中断服务函数调用
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim==(&TIM3_Handler))
    {
			static u8 LedFlg=0;  //这里其实可以读PA8的寄存器来判断亮灭状态
			static LightCtr LightCtrCnt={0,0,0}; //一个静态变量 记录次数信息
			
			LightCtrCnt.uDelay100ms++;
			if(LightCtrCnt.uDelay100ms>=LightCtruser.uDelay100ms)  //这个判断来执行闪烁快慢
			{
				LightCtrCnt.uDelay100ms=0;
				if(LightCtruser.uLightOffNb==0)  //如果没有熄灭间隔时间,那就得一直闪烁下去
					LightCtrCnt.uLightOnNb=0;
				
			  if(LightCtrCnt.uLightOnNb<LightCtruser.uLightOnNb)  //判断闪烁次数是否达够指定的次数
				{
					if(LedFlg)
					{
						LightCtrCnt.uLightOnNb++;  //点亮一次 则闪烁次数增加一次
						LedFlg=0;
						HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,GPIO_PIN_RESET);
					}
					else
					{
						LedFlg=1;
						HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,GPIO_PIN_SET);
					}
				}
				else  //达够闪烁次数后 进行一定延时的熄灭
				{
						LightCtrCnt.uLightOffNb++;  //熄灭的延时计数
				    LedFlg=0;
						HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,GPIO_PIN_RESET);
					//达够熄灭的延时计数之后 清零LED闪烁控制的变量 开始下个回合
						if(LightCtrCnt.uLightOffNb>=LightCtruser.uLightOffNb)  
						{
							LightCtrCnt.uLightOffNb=0;
							LightCtrCnt.uLightOnNb=0;
						}
				}	
			}
    }
}

void SetFlashingSpeed(	u8 uDelay100ms,u8 uLightOnNb,u8 uLightOffNb)
{
	LightCtruser.uDelay100ms=uDelay100ms;
	LightCtruser.uLightOnNb=uLightOnNb;
	LightCtruser.uLightOffNb=uLightOffNb;
}

4.根据STM来判断LED闪烁频率

/*
指示灯闪烁判断 根据有无故障来解析闪烁次数和频率
*/
void LightTwinkle(void)
{
		uint16_t  hFaultOccurred;
		
		hFaultOccurred=STM[0].hFaultOccurred|STM[1].hFaultOccurred; //按位与  不论哪个电机有故障 都报告
		if(hFaultOccurred)
		{
			u8 Twinkle=0;
			while(hFaultOccurred)  //按照最高位的优先级来闪烁指示灯
			{
				Twinkle++;   //移位累加 获取到最高位的错误 值 ,闪烁次数 即哪个bit位的故障
				hFaultOccurred>>=1;
			}
			if((STM[0].hFaultNow|STM[1].hFaultNow)==0) //当前没有故障了,错误已经解除
				SetFlashingSpeed(2,Twinkle,5);  //故障解除 则熄灭状态延长节拍
			else 
				SetFlashingSpeed(2,Twinkle,2);  //故障保持 则熄灭节拍短促
		}
		else
			SetFlashingSpeed(5,1,0);

}

这个函数在主函数的while(1)里面被调用就可以了。

做如上的增改之后,LED正常情况下会0.5s的闪烁;如果有故障产生,且故障没有解除,则LED快速闪烁指定的次数后,短暂熄灭;如果故障已经消除,但没通过人为确认,则闪烁后是一段长时间的熄灭。这样,与ST FOC 代码中对故障的Now 和hFaultOccurred 思路一致。

ST的开源方案–空间矢量控制,驱动永磁同步电机的学习及分享计划CSDN链接

猜你喜欢

转载自blog.csdn.net/Soonjn/article/details/102985236
今日推荐