jsi
依然是先列框架。
- 看题要用到的东西,定义头文件,HC138相关代码,定义S7L1端口,以及main函数。
#include <REGX52.H> sbit L1 = P0^0; sbit S7 = P3^0; void SELECT_HC138(unsigned char n) { switch(n) { case 4: P2=(P2&0x1f)|0x80; break; case 5: P2=(P2&0x1f)|0xa0; break; case 6: P2=(P2&0x1f)|0xc0; break; case 7: P2=(P2&0x1f)|0xe0; break; } } void main() { SELECT_HC138(4); L1=1; InitTimer0(); while(1) { ScanKey(); } }
- 要用到S7按键,所以需要一个按键扫描ScanKey函数以及用于消抖的延时函数。在ScanKey函数中,由于整个题有四个不同的状态,我们设置一个变量state记录。当state为0时,开始计时,且亮度即占空比为10%,执行完后,state变为1;当state为1时,占空比改为20%,执行完后同样改变state值,使其进行下一个循环;当state为2时,占空比为90%,同样改变state值;当state为3时,此时灯光完全熄灭,这里有两种方法,一是将占空比定义为0,同样会进行系统定时器的计数,count会计数到100后自动清零,然后改变state值为0,从而再进入到下一个循环。另一种方法是在state为3时,关闭定时器的计数,改变state值为0,这个时候就不会进行定时器计数,只需要等到下一次按下S7进入下一个循环即可。两种方法在实践中都可以完成任务,都没有问题。
void ScanKey() { if(S7 == 0) { Delay(100); if(S7==0) { switch(state) { case 0: L1 = 0; TR0=1; pwm_duty = 10; state=1; break; case 1: pwm_duty=50; state=2; break; case 2: pwm_duty =90; state=3; break; case 3: L1=1; TR0=0; state=0; break; } while(S7 == 0); } } }
- 利用脉宽信号实现对灯光的控制,这个地方需要用到中断函数InitTimer0,一般分为初始化函数和中断服务函数ServiceTimer0()。题目上说pwm脉宽信号的频率为100Hz,即周期为10ms,以第一种情况为例,10%的亮度,即低电平在整个周期中占比为10%。假如将这个周期分为一百份,其中十份为低电平,剩下的九十份为高电平,这样完成一个周期就完成了第一种情况,等到下个周期的时候,改变低电平的占比为50%就可以完成第二种情况,依次改变占空比就可以完成所有情况。
- 我们将系统定时器的周期设置成一百份中的其中一份,每完成一次周期记一次数,这个数在小于占空比值时,设置为低电平使灯亮,大于占空比时,设置为高电平使灯灭,等到这个数为100时,就可以清空,然后开启下一个占空比值不同的周期。这里定义两个变量pwm_duty以及count分别用于改变占空比值和记录周期。
void InitTimer0() { TMOD=0x01; TH0=(65535-100)/256; TL0=(65535-100)%256; ET0=1; EA=1; } void ServiceTimer0() interrupt 1 { TH0=(65535-100)/256; TL0=(65535-100)%256; count++; if(count <= pwm_duty) { L1=0; } else if(count > pwm_duty) { L1=1; if(count == 100) { count = 0; } } }