调整占空比,脉宽调制作用:
①直流电机的调速
②灯光的控制:亮度
③声音大小
④舵机角度调整
利用PWM脉宽信号实现独立按键S7(J5跳帽2、3)对L1指示灯亮度变化的控制。
①PWM脉宽信号的频率为100Hz
②系统上电后L1指示灯处在熄灭状态
③L1指示灯有4种亮度模式,分别是完全熄灭、10%亮度、50%亮度、90%亮度
④按下S7按键,循环切换L1指示灯的4种亮度模式
分析:
①100Hz = 0.01s = 10ms = 10000us (周期为10ms)
将周期分为100等份 = 100 * 100us(每100us产生一次中断 65535 - 100)
怎样产生60%占空比:60次高电平,40次低电平(设count计数)
②系统上电后L1指示灯处在熄灭状态:先产生低电平
1、自己写的代码(按键读取部分有点问题,为什么容易误判?)
#include "reg52.h"
sbit S7 = P3^0;
sbit L1 = P0^0;
sbit HC138_A = P2^5;
sbit HC138_B = P2^6;
sbit HC138_C = P2^7;
void InitHC138()//选LED
{
HC138_C = 1;
HC138_B = 0;
HC138_A = 0;
}
//************定时器相关函数****************************************
unsigned char count = 0;
unsigned char PWM_duty = 0;//PWM占空比
void InitTimer0() //中断函数
{
TMOD = 0x01;
TH0 = (65535 - 100) / 256; //100Hz = 0.01s = 10ms = 100*100us
TL0 = (65535 - 100) % 256; //将周期分为100份 = 100us产生一次中断
ET0 = 1;//打开定时器中断
EA = 1;//打开总中断
//TR0 = 1; (启动定时器)先不打开,等需要产生脉宽调制的时候再打开
}
void ServiceTimer0() interrupt 1 //中断服务函数
{
TH0 = (65535 - 100) / 256;
TL0 = (65535 - 100) % 256;//自动重装
count++;
if (count <= PWM_duty)//计数<=PWM占空比 L1亮
{
L1 = 0;
}
else if (count < 100)//PWM占空比<计数<100(周期) L1灭
{
L1 = 1;
}
else if (count == 100)//计数达到一个周期,L1灭,count清零,继续循环
{
L1 = 0;
count = 0;
}
//方法二
//count++;
//if (count == PWM_duty)
//{
// L1 = 1;
//}
//else if (count == 100)
//{
// L1 = 0;
// count = 0;
//}
}
//*****************************************************************
//************按键操作************************************************
void DelayKey(unsigned int t) //按键消抖函数
{
while(t--);
}
unsigned char flat = 0;//标志位(0时灯灭)
void ScanKeys() //按下S7按键,循环切换L1指示灯的4种亮度模式
{
if (S7 == 0)
{
DelayKey(100);//按键消抖
if (S7 == 0)
{
if (flat == 0)//10%亮度
{
L1 = 0;
TR0 = 1;//启动定时器
PWM_duty = 10;
flat = 1;
}
else if (flat == 1)//50%亮度
{
PWM_duty = 50;
flat = 2;
}
else if (flat == 2)//90%亮度
{
PWM_duty = 90;
flat = 3;
}
else if (flat == 3)//灭灯,进入下一次循环
{
L1 = 1;
TR0 = 0;//关闭定时器
flat = 0;//循环
}
while(!S7);//松开后,再进行读取(防止误判)
}
}
}
//*******************************************************************
void main()
{
InitHC138();
L1 = 1; //系统上电后L1指示灯处在熄灭状态
InitTimer0();
while(1)
{
ScanKeys();
}
}
2、标准代码(也有相同情况)
#include "reg52.h"
sbit S7 = P3^0;
sbit L1 = P0^0;
sbit HC138_A = P2^5;
sbit HC138_B = P2^6;
sbit HC138_C = P2^7;
void InitHC138()//选LED
{
HC138_C = 1;
HC138_B = 0;
HC138_A = 0;
}
//************定时器相关函数****************************************
unsigned char count = 0;
unsigned char PWM_duty = 0;//PWM占空比
void InitTimer0() //中断函数
{
TMOD = 0x01;
TH0 = (65535 - 100) / 256; //100Hz = 0.01s = 10ms = 100*100us
TL0 = (65535 - 100) % 256; //将周期分为100份 = 100us产生一次中断
ET0 = 1;//打开定时器中断
EA = 1;//打开总中断
//TR0 = 1; (启动定时器)先不打开,等需要产生脉宽调制的时候再打开
}
void ServiceTimer0() interrupt 1 //中断服务函数
{
TH0 = (65535 - 100) / 256;
TL0 = (65535 - 100) % 256;//自动重装
count++;
if (count <= PWM_duty)//计数<=PWM占空比 L1亮
{
L1 = 0;
}
else if (count < 100)//PWM占空比<计数<100(周期) L1灭
{
L1 = 1;
}
else if (count == 100)//计数达到一个周期,L1灭,count清零,继续循环
{
L1 = 0;
count = 0;
}
//方法二
//count++;
//if (count == PWM_duty)
//{
// L1 = 1;
//}
//else if (count == 100)
//{
// L1 = 0;
// count = 0;
//}
}
//*****************************************************************
//************按键操作************************************************
void DelayKey(unsigned int t) //按键消抖函数
{
while(t--);
}
unsigned char flat = 0;//标志位(0时灯灭)
void ScanKeys() //按下S7按键,循环切换L1指示灯的4种亮度模式
{
if (S7 == 0)
{
DelayKey(100);//按键消抖
if (S7 == 0)
{
switch(flat)
{
case 0: //10%亮度
L1 = 0;
TR0 = 1;//启动定时器
PWM_duty = 10;
flat = 1;
break;
case 1: //50%亮度
PWM_duty = 50;
flat = 2;
break;
case 2: //90%亮度
PWM_duty = 90;
flat = 3;
break;
case 3: //灯灭,进入下一次循环
L1 = 1;
TR0 = 0;//关闭定时器
flat = 0;
break;
}
while(!S7);//松开后,再进行读取(防止误判)
}
}
}
//*******************************************************************
void main()
{
InitHC138();
L1 = 1; //系统上电后L1指示灯处在熄灭状态
InitTimer0();
while(1)
{
ScanKeys();
}
}