⭐注意
由图片可知,要使用P3口
🍔同一个灯
🏳️🌈效果
led灯闪烁
#include <REGX52.H> void Delay(unsigned int xms) { unsigned char i, j; while(xms){ i = 2; j = 239; do { while (--j); } while (--i); xms--; } } void main() { while(1) { if(P3_1==0)//按下 { Delay(20); while(P3_1==0);//仍然按下 Delay(20); P2_0=~P2_0; } } }
着重分析下面的代码
while(1) { if(P3_1==0) { Delay(20); while(P3_1==0) ; Delay(20); P2_0=~P2_0; } }
🏳️🌈问题分析
⭐注意
1.在这个程序里面,最好用类似于P3_1=0的代码,不要用类似于P2=0xFE的代码,因为后者很容易迷糊
(如果是流水灯,可以用P2=0xFE)
2.Delay()函数里面用的是自动延时代码,可以由软件自动生成,如果不明白是怎么肥四,可以参考下面这篇文章
【51单片机】使用STC烧录软件自动生成延时代码_在下 小吉的博客-CSDN博客
⭐P3_1=0,表示按下按键
⭐为什么while(P3_1==0);后面要加上分号呢?
在观察现象的时候发现,按一次松手,灯亮了,再按一次松手,灯灭了
所以,这样子主要是为了一直按着按键的时候,防止灯亮
(而且不能改为P3_1=0,因为这里必须是循环语句或者判断语句)
⭐两个Delay(20)的作用
如图
第一个Delay(20)是作用于前面抖动的部分
第二个Delay(20)是作用于后面抖动的部分(防止松手时影响灯的亮度)
⭐P2_0=~P2_0;
就是控制LED的开关状态,使其可以闪烁
🍔不同灯(显示二进制移位)
🏳️🌈效果
多个led灯亮
🏳️🌈代码
#include <REGX52.H> void Delay(unsigned int xms) { unsigned char i, j; while(xms){ i = 2; j = 239; do { while (--j); } while (--i); xms--; } } void main() { unsigned char LEDNum=0; while(1) { if(P3_1==0) { Delay(20); while(P3_1==0); Delay(20); LEDNum++; P2=~LEDNum; } } }
🏳️🌈原因
请看下图
P2=~LEDNum;由于二进制数字的变化,所以会引起灯的变化
🍔流水灯(按一下按键,灯亮的位置才会变化)(移位)
🏳️🌈效果
WeChat_20230425133443
🏳️🌈代码
#include <REGX52.H> unsigned char LEDNum; void Delay(unsigned int xms) { unsigned char i, j; while(xms){ i = 2; j = 239; do { while (--j); } while (--i); xms--; } } void main() { while(1) { if(P3_1==0) { Delay(20); while(P3_1==0); Delay(20); if(LEDNum>=8) LEDNum=0; P2=~(0x01<<LEDNum); LEDNum++; } if(P3_0==0)//多个按键操作 { Delay(20); while(P3_0==0); Delay(20); if(LEDNum==0)//反方向的流水灯 LEDNum=7; else LEDNum--; P2=~(0x01<<LEDNum); } } }
🏳️🌈解释
首先 led=0x01,而且LEDNum=0,因为 LED 是低电平点亮 ,所以 (0x01<<LEDNum) 取反 后的结果是 0xFE, 对应二进制数为 1111 1110,即最低位为 0,因此最开始的 D1 指示灯会点亮 ,然后延时一段时间进入while循环, 由于要实现8个LED从D1->D8 循环点亮,因此可以使用 for 循环语句循环 8 次,每循环一次,点亮的小灯向右 移动一个即 P2 口输出的低电平要左移一位,因此可以使用 P2=~(0x01<<i);语句实现 。0x01<<LEDNum 表示每次 LEDNum 增加 1 次,0x01 中的 1 就移动多少位, 因为 1不会让 LED 点亮,需要取反后变为低电平 0 才能点亮,所以最后的结果需要
取反后给 P2 口
🍔流水灯(按一下,灯亮的位置自动改变)
🏳️🌈效果
按键流水灯
🏳️🌈代码例子&&解释
main.c
#include <REGX52.H> #include "Timer0.h" #include "Key.h" #include <INTRINS.H> unsigned char KeyNum,LEDMode; void main() { P2=0xFE; Timer0Init(); while(1) { KeyNum=Key(); //获取独立按键键码 if(KeyNum!=0) //如果按键按下 { //if(KeyNum==1) //如果K1按键按下 //{ LEDMode++; //模式切换 if(LEDMode>=2)LEDMode=0; //} } } } void Timer0_Routine() interrupt 1 { static unsigned int T0Count; TL0 = 0x18; //设置定时初值 TH0 = 0xFC; //设置定时初值 T0Count++; //T0Count计次,对中断频率进行分频 if(T0Count>=500)//分频500次,500ms { T0Count=0; if(LEDMode==0) //模式判断 P2=_crol_(P2,1); //LED输出 //_crol_循环左移 if(LEDMode==1) P2=_cror_(P2,1); //_cror_循环右移 } }
⭐_crol_循环左移
⭐_cror_循环右移
⭐使用定时器中断的原因(请看图片)
Timer0.c
#include <REGX52.H> /** * @brief 定时器0初始化,1毫秒@12.000MHz * @param 无 * @retval 无 */ void Timer0Init(void) { TMOD &= 0xF0; //设置定时器模式 TMOD |= 0x01; //设置定时器模式 TL0 = 0x18; //设置定时初值 TH0 = 0xFC; //设置定时初值 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时 ET0=1; EA=1; PT0=0; } /*定时器中断函数模板 void Timer0_Routine() interrupt 1 { static unsigned int T0Count; TL0 = 0x18; //设置定时初值 TH0 = 0xFC; //设置定时初值 T0Count++; if(T0Count>=1000) { T0Count=0; } } */
🎆为什么主函数没有调用中断函数,但是中断函数为什么会执行呢
当调用Timer0Init()函数时,就会开启定时器0中断,并将中断服务函数的入口地址设置为Timer0_Routine()函数的地址(这个过程涉及到中断向量表的设置,一般由编译器完成)。而每当定时器0中断被触发时,就会跳转到Timer0_Routine()函数执行其中的代码。因此,即使主函数没有显式调用中断函数,中断函数也会被执行。
上面一段代码不明白的同学可以参考一下这一篇博客
【51单片机】使用STC烧录软件生成定时器的代码以及注意事项_在下小吉.的博客-CSDN博客
Timer0.h
#ifndef __TIMER0_H__ #define __TIMER0_H__ void Timer0Init(void); #endif
Key.c
#include <REGX52.H> #include "Delay.h" /** * @brief 获取独立按键键码 * @param 无 * @retval 按下按键的键码,范围:0~4,无按键按下时返回值为0 */ unsigned char Key() { unsigned char KeyNumber=0; if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;} if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;} if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;} if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;} return KeyNumber; }
因为图片中的就是P3口
所以最好使用P3口的4个引脚(P3_0~P3_3)
Key.h
#ifndef __KEY_H__ #define __KEY_H__ unsigned char Key(); #endif
Delay.c
void Delay(unsigned int xms) { unsigned char i, j; while(xms--) { i = 2; j = 239; do { while (--j); } while (--i); } }
上面一段代码不明白的同学可以参考一下这篇博客
【51单片机】使用STC烧录软件自动生成延时代码_在下小吉.的博客-CSDN博客
Delay.h
#ifndef __DELAY_H__ #define __DELAY_H__ void Delay(unsigned int xms); #endif