1 实验现象
2 实验原理
通过按键来控制PWM占空比实现对直流电机的调速,数码管则显示当前速度挡位信息。
(1)直流电机的控制是通过设置PWM波的占空比来控制直流电机的转速,占空比越大,转速越快,越小转速越低;
(2)单片机的I/O口是不能直接驱动电机的,所以还需要用一个驱动芯片。如 LG9110、CMO825、L298 等。驱动芯片可以将单片机I/O输出信号放大,这样电机中流过的电流足够大,电机才能转起来。
(3)直流电机只有两根电源线,直流电机的两根电源线是不分正负极的。假设两根电源线代号分别为A、B。 当A线接正极,B线接负极时,电机正转(反转);那么当B线接正极,A线接负极时,电机反转(正转)。
3 参考程序
3.1 主程序
#include
#include "delayms.h"
#include "key.h"
#include "Nixie.h"
#include "timer0.h"
sbit Motor=P1^3; //直流电机,高电平驱动
unsigned char Counter,Compare; //计数值和比较值,用于输出PWM
unsigned char KeyNum,Speed;
void main()
{
timer0_init();
while(1)
{
KeyNum=key();
if(KeyNum==1)
{
Speed++;
Speed%=4; //计数值计算范围为0-3
if(Speed==0) {Compare=0;}
if(Speed==1) {Compare=50;}
if(Speed==2) {Compare=75;}
if(Speed==3) {Compare=100;}
}
Nixie(1,Speed);
}
}
void Timer0_Routine() interrupt 1
{
TL0 = 0xAE; //设置定时初始值,100us,@11.0592MHz
TH0 = 0xFB; //设置定时初始值,100us,@11.0592MHz
Counter++;
Counter%=100; //计数值计算范围为0-99
if(Counter
Motor=1; //高电平驱动,电机转动
}
else
{
Motor=0; //电机停止
}
}
3.2 延时函数
#include
void delayms(unsigned int xms) //@11.0592MHz
{
unsigned char i, j;
while(xms--)
{
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
}
#ifndef _delayms_h_
#define _delayms_h_
delayms(unsigned int xms);
#endif
3.3 按键扫描函数
#include
#include "delayms.h"
sbit key1 = P3^1;
sbit key2 = P3^0;
sbit key3 = P3^2;
sbit key4 = P3^3;
/**
* @brief 获取独立按键键码
* @param 无
* @retval 按下按键的键码,范围:0~4,无按键按下时返回值为0
*/
unsigned char key()
{
unsigned char KeyNumber = 0;
if(key1==0){delayms(20);while(key1==0);delayms(20);KeyNumber=1;}
if(key2==0){delayms(20);while(key2==0);delayms(20);KeyNumber=2;}
if(key3==0){delayms(20);while(key3==0);delayms(20);KeyNumber=3;}
if(key4==0){delayms(20);while(key4==0);delayms(20);KeyNumber=4;}
return KeyNumber;
}
#ifndef _key_h_
#define _key_h_
unsigned char key();
#endif
3.4 数码管扫描函数
#include
#include "delayms.h"
sbit HC138_A=P2^2;
sbit HC138_B=P2^3;
sbit HC138_C=P2^4;
//数码管段码表,0-9
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
/**
* @brief 数码管显示
* @param Location 要显示的位置,范围:1~8
* @param Number 要显示的数字,范围:段码表索引范围
* @retval 无
*/
void Nixie(unsigned char Location,Number)
{
switch(Location) //位码输出
{
case 1:HC138_C=1;HC138_B=1;HC138_A=1;break;
case 2:HC138_C=1;HC138_B=1;HC138_A=0;break;
case 3:HC138_C=1;HC138_B=0;HC138_A=1;break;
case 4:HC138_C=1;HC138_B=0;HC138_A=0;break;
case 5:HC138_C=0;HC138_B=1;HC138_A=1;break;
case 6:HC138_C=0;HC138_B=1;HC138_A=0;break;
case 7:HC138_C=0;HC138_B=0;HC138_A=1;break;
case 8:HC138_C=0;HC138_B=0;HC138_A=0;break;
}
P0=NixieTable[Number]; //段码输出
delayms(1); //显示一段时间
P0=0x00; //段码清0,消影
}
#ifndef __NIXIE_H__
#define __NIXIE_H__
void Nixie(unsigned char Location,Number);
#endif
3.5 定时器函数
#include
/**
* @brief 定时器0初始化,100微秒@11.0592MHz
* @param 无
* @retval 无
*/
void timer0_init(void) //100微秒@11.0592MHz
{
TMOD &= 0xF0; //设置定时器模式,1111_0000,&,高四位保留,低四位清零
TMOD |= 0x01; //设置定时器模式,0000_0001,|,高四位保留,设置模式为T0
TL0 = 0xAE; //设置定时初始值,100us,@11.0592MHz
TH0 = 0xFB; //设置定时初始值,100us,@11.0592MHz
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1; //打开定时器T0中断开关
EA=1; //打开中断系统总开关
PT0=0; //设置T0中断优先级,低
}
/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x66; //设置定时初值,1毫秒@11.0592MHz
TH0 = 0xFC; //设置定时初值,1毫秒@11.0592MHz
T0Count++;
if(T0Count>=1000)
{
T0Count=0;
}
}
*/
#ifndef _timer0_h_
#define _timer0_h_
void timer0_init(void);
#endif