文章目录
- 程序设计
- 伺服电机的速度控制模式代码讲解
- main.c
- timer.c
- 伺服电机的位置控制模式代码讲解
- main.c
- timer.c
- 编译仿真
- 伺服电机的速度控制模式
- 伺服电机的位置控制模式
- 遇到的错误
- 总结
程序设计
伺服电机的速度控制模式代码讲解
main.c
#include "delay.h"
#include "key.h"
#include "timer.h" extern u8 dir; int main(void)
{ u8 Key_Value=0;gpio_init(); //有一个定时器通道3 delay_init(); //延时函数初始化 KEY_Init(); //按键初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); TIM2_PWM_Init(72000000/2000-1,0); TIM3_Int_Init(359,1000); TIM_Cmd(TIM2,DISABLE); //定时器2和定时器3默认不开启 TIM_Cmd(TIM3,DISABLE); while(1) { . . . . . . }
}
1、TIM2_PWM_Init
TIM2_PWM_Init(72000000/2000-1,0);
//72000000/2000=36000
//不分频,PWM启动频率=72000000/36000=2000Hz
TIM2_PWM_Init(72000000/2000-1,0)
参数1:72000000/2000-1,溢出值(从0开始)
参数2:0,分频值(从0开始)
通过该段代码使TIM2产生一个PWM方波。
2、TIM3_Int_Init
TIM3_Int_Init(359,1000);
//(72000000/1000)/360=200Hz
//5ms改变一次频率
//定时器3的溢出中断去调节定时器2产生的方波的频率
TIM3_Int_Init(359,1000)
参数1:4999,溢出值(从0开始)
参数2:7199,分频值(从0开始)
72MHz÷1000=72KHz,计数到360为5ms,即每5ms进一次中断。
通过该段代码使TIM3每5ms进入一次中断判断是加速减速还是匀速。
3、while
while(1)
{ Key_Value|=KEY_Scan(); if((Key_Value&0x01) ==1) { if(Key_Value>>7==0) //按下独立按键,开始发脉冲,电机加速至最高转速 { dir=1;//每次溢出中断,另脉冲频率开始升高 Key_Value =1<<7;//Key_Value最高位 0代表电机未开启 1代表电机已开启 TIM_Cmd(TIM3,ENABLE); //开启定时器2和定时器3,PA.2管脚开始输出脉冲 TIM_Cmd(TIM2,ENABLE); } else if(Key_Value>>7==1)//第二次按下独立按键,电机减速至停止 //最高位如果等于1 { Key_Value =0; //按键值清零 dir=0; //每次溢出中断,另脉冲频率开始降低 TIM_Cmd(TIM3,ENABLE); //重新打开定时器3,开始改变频率 } }
}
第一个段代码Key_Value|=KEY_Scan(),用于改变Key_Value的值,我们对KEY_Scan go to definition。
//按键处理函数
//返回按键值
//0,KEY0松开
//1,KEY0按下
u8 KEY_Scan(void)
{ //按一下,从0到高速 //再按一下,从高速变为0 static u8 key_up=1;//按键按松开标志 if(key_up && KEY0==0)//按键松开并且KEY0被按下 { delay_ms(10);//去抖动 key_up=0; if(KEY0==0) return 1; } else if(KEY0==1)key_up=1; return 0;// 无按键按下
}
代码解释:
key_up作为子程序KEY_Scan的局部静态变量,当没有键按下时,图中第10行的if条件不成立,key_up仍然为1,KEY_Scan直接return 0,KEY_Scan结束执行;当有按键按下时,第10行的if成立,执行if语句(由于程序执行周期远远小于人按键松开时间,所以认为执行1个周期期间key_up一直为1),延迟消抖后,key_up变为0,同时执行嵌套的if语句来再次判断是哪个键被按下,并且return对应的键值。尽管main高速调用KEY_Scan,但由于key_up是static类型的变量,会继承上一次调用的值,也即是说key_up=0,不执行第10行if,KEY_Scan的return为0。直到按键完全松开,执行第16行程序,key_up重新为1。做到了按下按键只返回一次对应值。
回到while,当第一次按下按键,则执行语句Key_Value | = KEY_Scan(),Key_Value = 1。此时Key_Value的最高位为0,所以Key_Value >> 7 = = 0成立,加速标志dir = 1,表示加速,同时另Key_Value的为高位为1,最后开启定时器2和定时器3来产生PWM方波和控制加减速。
if(Key_Value>>7==0) //按下独立按键,开始发脉冲,电机加速至最高转速
{ dir=1;//每次溢出中断,另脉冲频率开始升高 Key_Value =1<<7;//Key_Value最高位 0代表电机未开启 1代表电机已开启 //把最高位至1 TIM_Cmd(TIM3,ENABLE); //开启定时器2和定时器3,PA.2管脚开始输出脉冲 TIM_Cmd(TIM2,ENABLE);
}
第二次按下按键,由于Key_Value的为高位为1,所以Key_Value>>7 = = 1成立,另Key_Value = 0,则加速标志dir = 0,表示减速,重新打开定时器3,开始改变速度。
else if(Key_Value>>7==1)//第二次按下独立按键,电机减速至停止
//最高位如果等于1
{ Key_Value = 0; //按键值清零 dir = 0; //每次溢出中断,另脉冲频率开始降低 TIM_Cmd(TIM3,ENABLE);//重新打开定时器3
}
timer.c
TIM3_IRQHandler
void TIM3_IRQHandler(void) //TIM3中断
{ if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM3, TIM_IT_Update); if(dir==1) //加速标志 if(freq1<62000) //最高频率62KMz { freq1+=100; PWM_Change(freq1); } if(dir==0) //减速标志 if(freq1>2000) //最低频率2KMz { freq1 -=100; PWM_Change(freq1); } if(dir==1&&freq1>=62000) //如果加速达到最高频率,则关闭定时器3,定时器2输出最高频率的脉冲,电机匀速运行 TIM_Cmd(TIM3,DISABLE); if(dir==0&&freq1<=2000) //如果减速至2000Hz以下,则关闭定时器2和定时器3,停止输出脉冲,电机停止运行 { TIM_Cmd(TIM2,DISABLE); TIM_Cmd(TIM3,DISABLE); } }
}
由于main.c中初始化了TIM3_Int_Init(359,1000),所以每5ms发生一次溢出中断,判断一次加速标志dir,再修改或保持一次频率。
通过定时器3溢出中断发现,函数PWM_Change修改了频率,所以对PWM_Change go to definition
//改变频率
void PWM_Change(u32 freq)
{ u16 arr,psc; arr=72000000/freq-1; psc=0;//不分频 TIM2_PWM_Init(arr,psc); //使用新的参数配置定时器,改变定时器的周期 TIM_Cmd(TIM2,ENABLE); //开启定时器2
}
由函数可知,最终是调整了定时器2输出PWM的溢出周期arr的值来改变转速。
void TIM2_PWM_Init(u16 arr,u16 psc)
{ . . . . . . TIM_SetCompare3(TIM2,arr/2);
}
TIM2_PWM_Init多了这一句话,在初始化里面改变了比较点。
伺服电机的位置控制模式代码讲解
main.c
while(1)
{ num_plus_setting=100; //脉冲个数设定值 if(KEY_Scan()) running_motor=1; //电机启动 if(running_motor) TIM_Cmd(TIM2,ENABLE);//定时器2使能 else num_plus_now=0;//当前脉冲个数清零
}
如果有按键按下,则第5行的if判断成立,另running_motor=1;同时第7行的if判断也成立,则开启定时器2。如果没有按键按下,则running_motor=0,当前脉冲个数清0。
timer.c
TIM2_IRQHandler
定义了三个变量:
按键按下时的标志位,u8 running_motor;
当前的脉冲个数:u32 num_plus_now;
设定的脉冲个数:num_plus_setting。
当有按键按下时, running_motor=1,第2行的if判断成立,则定时器2每溢出一次,当前的脉冲个数num_plus_now自加1。
接着根据当前的脉冲个数num_plus_now的大小,判断伺服电机是应该加速还是应该减速,生成相应的加速标志dir=1或者减速标志dir=0。
最后根据标志来进行加速或减速。
编译仿真
伺服电机的速度控制模式
打开仿真
点击示波器:
弹出如下示波器页面:
点击set up增加变量
点击左边的方框,添加PORTA.2,同时把Display Type改为改为Bit。
点击运行
第一次点击PE.3,伺服电机加速,看到频率由低到高,后达到稳定。
第二次点击PE.3,伺服电机减速,看到频率由高变低,最后变为低电平。
伺服电机的位置控制模式
打开仿真
点击示波器:
弹出如下示波器页面:
点击set up增加变量
点击左边的方框,添加PORTA.2,同时把Display Type改为改为Bit。
点击运行
点击PE.3,伺服电机先加速后减速,看到频率由低到高在变低。
遇到的错误
遇到的错误:把TIM_SetCompare3注释,仿真还是会出现波形。
TIM_SetCompare3(TIM2,arr/2)注释后,比较点就不会再变化了;由于每次溢出中断都会调用PWM_Change函数来改变arr的值,导致溢出周期却还在一直变化,所以波形频率才会变化。
解决错误:
取消对TIM_SetCompare3(TIM2,arr/2)的注释。
成功运行