直流电机控制(PWM)+普中51单片机+江科大自化协
1 实验现象
2 实验原理
通过按键来控制PWM占空比实现对直流电机的调速,数码管则显示当前速度挡位信息。
(1)直流电机的控制是通过设置PWM波的占空比来控制直流电机的转速,占空比越大,转速越快,越小转速越低;
(2)单片机的I/O口是不能直接驱动电机的,所以还需要用一个驱动芯片。如 LG9110、CMO825、L298 等。驱动芯片可以将单片机I/O输出信号放大,这样电机中流过的电流足够大,电机才能转起来。
(3)直流电机只有两根电源线,直流电机的两根电源线是不分正负极的。假设两根电源线代号分别为A、B。 当A线接正极,B线接负极时,电机正转(反转);那么当B线接正极,A线接负极时,电机反转(正转)。
3 参考程序
3.1 主程序
#include <REGX52.H> #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<Compare) //计数值小于比较值 { Motor=1; //高电平驱动,电机转动 } else { Motor=0; //电机停止 } }
3.2 延时函数
#include <intrins.h> 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 <reg52.h> #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 <REGX52.H> #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 <REGX52.H> /** * @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
4 参考资料