51单片机PWM控制电机

发布于:2021-10-23 19:53:40

??? 小时候玩的四驱车,给直流马达接通电源就嗤嗤的跑出去了。电机种类众多,就属控制直流电机最简单,只要对调正负极就能改变电机的转向。另外,直流电机负载能力强,适合做越野车的驱动电机。为了做可调速的越野车,就有了这篇文章。


??? 电源电压输出是固定的,电机的转速也因此是固定的,为了调节电机的转速,就得改变电源电压的输出(为嘛要改变电机转速?举个简单的列子,双电机驱动小车-一边一个电机-如何实现转向?让两边轮胎上的速度不同即可)。how?用PWM调制的方法,把恒定的直流电源电压调制成频率一定宽度可变的脉冲电压序列,从而可以改变*均输出电压的大小,以调节电机的转速。电源电压在此处就是51MCU的引脚输出,4.5-5V,只要在引脚上产生频率可调的波形即可。假设在一个周期内,就10ms吧,前5ms引脚输出高电*,后5ms引脚输出低电*,周而复始,引脚上输出50%占空比的稳定方波;再改改,前2ms输出高电*,后8ms输出低电*,引脚上输出20%占空比的稳定方波。


??? MCU产生周期性事件很简单,用定时器定时产生中断即可。一般差不多一下形式:



void Isr01() interrupt 1
{
static unsigned int cnt;
cnt++;
if(cnt==40)
{
cnt=0;
}
}
假设每250us产生一次中断,以上中断函数统计40次中断,即10ms。

为了完成"可改变占空比的方波"这个命题,来试试给这个函数增加一些统计事件,在一个统计事件中做一些事,另一个统计事件中做其他的事。



unsigned int condition=20;
void Isr01() interrupt 1
{
static unsigned int cnt;
cnt++;
//一个周期
if(cnt==40)
{
cnt=0;
}
//事件1
?if(cnt {
//do sth
}
//事件2
?else
{
//do other thing
}
}
condition就是新增加的统计事件,前半个周期为一个事件,后半个周期为另一个事件。这里,当cnt小于5ms,输出高电*,当cnt大于输出低电*,合在一起生成一个50%占空比的方波。



unsigned int condition=20;
void Isr01() interrupt 1
{
static unsigned int cnt;
cnt++;
//一个周期
if(cnt==40)
{
cnt=0;
}
if(cnt {
//前半个周期do sth
pin=0x00;
}
else
{
//后半个周期do other thing
pin=0x01;
}
}
为了改变占空比,只要在ISR外修改condition即可,贴出最终的代码:



#include
#include

sbit P2_0 = P2^0;
sbit P2_1 = P2^1;
#define MakeByte(target, Hi,Lo)
do{
target |= (((Hi)<<4)|(Lo));
}while(0);

#define SetTH(n,val)
do{
TH##n = val;
}while(0);

#define SetTL(n,val)
do{
TL##n = val;
}while(0);

#define EnableET(n)
do{
ET##n = 0x01;
IE |= 0x80;
}while(0);

enum KEYSTAT
{
KEYDOWN=0,KEYUP,
};

unsigned char iterator = 0x00;

void DelayMs(unsigned int ms)
{
int i=0,j=0;
for(;i {
for(j=0;j<1000;j++)
{
_nop_();
}
}
}

void OnKeyDown()
{
if(iterator == 0x28)
iterator = 0x00;
else
iterator += 0x04;
}

OnKeyUp()
{}

int main()
{
unsigned char curKeyStat = KEYUP;
unsigned char preKeyStat = KEYUP;

SetTH(0,0x06);
SetTL(0,0x06);
MakeByte(TMOD,0x02,0x02);
EnableET(0);
TR0 = 0x01;

while(1)
{
while(1)
{
curKeyStat = P2_1;
switch(curKeyStat)
{
case KEYDOWN:
if(curKeyStat == preKeyStat)
{
//确实按下键
OnKeyDown();
}
else
{
//两次按键不同 状态待定
}
preKeyStat = curKeyStat;
break;
case KEYUP:
if(curKeyStat == preKeyStat)
{
//确实松开键
OnKeyUp();
}
else
{
//两次按键不同 状态待定
}
preKeyStat = curKeyStat;
break;
}
DelayMs(200);
}
}

return 0;
}

void IsrT0() interrupt 1
{
static unsigned int enterIsr = 0;
TR0 = 0x00;
//每250us进入isr
enterIsr++;
//10ms一个周期
if(enterIsr == 0x28)
{
enterIsr = 0x00;
P2_0 = 0x0;
}
if(enterIsr<=iterator)
{
P2_0 = 0x00;
}
else
{
P2_0 = 0x01;
}
TR0 = 0x01;
}
在主函数中,通过判*聪录锤谋鋍ondition。



结尾部分,贴上仿真图和仿真结果:



1)占空比100%:



2)差不多55%占空比:




3)0%的占空比,电机休息了:



相关推荐

最新更新

猜你喜欢