目录
1.独立按键介绍
2.独立按键控制LED亮灭
1.1按下时LED亮,松手LED灭(按一次执行亮灭)
1.2首先按下时无操作,松手时LED亮(再按下无操作,所以LED亮),松手LED灭(松手时执行取反操作)(按两次执行亮灭)
1.3.独立按键控制LED按二进制递增亮
1.4.两个独立按键控制LED移位,左移,右移
1.5:一个独立按键控制流水灯方向
方法一:一个代码编程所有:
方法2:模块化编程,
1.独立按键介绍
独立按键的原理图:
所有单片机I/O口上电时都是默认高电平,独立按键没有按下,就是高电平,按下时,外部接地时强下拉,与地相接,I/O就会变为低电平,这里讲一下什么是I/O口,I/O口也叫input/output口,输入输出口,cpu可以给寄存器写值,比如上一节LED灯,CPU写值给寄存器,,由于单片机内部是弱上拉,所以要加驱动器加强电流,最后连接到I/O口,寄存器通过数据总线把值给I/O口此时I/O口就是output,input刚好就是相反的操作,比如I/O口读取外部信息,把值给寄存器,CPU再识别寄存器的值,
讲一下编程的命名问题,前面我们讲了sbit,对单个I/O口命名,就像一个人一样,要有名字,不过称呼一个人是不是也可以取外号啊,C51编程就给了这样的命名规则,
#include <REGX52.H>这个函数就相当于父母一样,里面对I/O口八位或单个I/O都命名了,
我们用单个I/O口就直接用P0_0,P0_0就像父母给的名字一样,但是也可以外号称呼,sbit LED=P2^0,此时LED就是外号,LED和P2_0都可以指向P2^0口(看成一个人)
记住:sbit LED=P2_0;是错的,把名字给外号显然不是喊你,P2^1=0;也是错的,赋值就像别人要称呼你,称呼你喊你的名字,肯定不是叫哎,这个人吧
延时消抖
主要原因还是单片机运算速度太快了,us级别,这些抖动他是可以识别出来的, 比如上面这个图,你按一下,由于有抖动,出现高-低--高--低--高--低...这样的话单片机会误以为你按了5/6下,
实际上你就按了一下,所以这样的操作就会与人们期望的不符,所以我们延时一段时间来消除抖动,按下与松手都加个延时,当然也可以加一个电路消抖动,(有点麻烦)
2.独立按键控制LED亮灭
1.1按下时LED亮,松手LED灭(按一次执行亮灭)
最终代码如下:
#include <REGX52.H>
sbit LED=P2^0;
void Delay1ms(unsigned int xms) //@12.000MHz
{unsigned char i, j;while(xms){i = 2;j = 239;do{while (--j);} while (--i);xms--;}
}void main()
{while(1){if(P3_1==0)//按下{Delay1ms(20);//消抖,真正的按下P2_0=0;}else//松手{Delay1ms(20);LED=0;}}
}
1.2首先按下时无操作,松手时LED亮(再按下无操作,所以LED亮),松手LED灭(松手时执行取反操作)(按两次执行亮灭)
代码如下:
#include <REGX52.H>
sbit LED=P2^0;
void Delay1ms(unsigned int xms) //@12.000MHz
{unsigned char i, j;while(xms){i = 2;j = 239;do{while (--j);} while (--i);xms--;}
}void main()
{while(1){if(P3_1==0){Delay1ms(20);//消抖,确定按下}else{Delay1ms(20);//消抖,确定松手LED=~LED;while(P3_1==1);}}
}
这段代码的现象是没有按之前,LED从1变为0;LED亮, 如果没有按独立按键,LED就一直亮,按下独立按键,没有任何反应,松手LED从0变为1,LED灭,一直是灭的状态,假如没有while(P3_1==1);这句,现象是LED一直在闪烁,无论按不按,都是闪烁,为什么呢,P3_1默认为高电平,一上电,我们没有按开关,执行else语句,LED=~LED,10101010.......延迟20ms的闪烁,按了就是多了延迟,只是增加了闪烁时间不同而已,有了这句话之后,松手的话,死循环,一直不执行,保持着了LED的状态,而不要让他一直变,
最后按一下松手执行下面操作,
亮----灭-----亮------灭.....
当然下面代码可以执行下面现象.
灭-----亮------灭.....亮........
void main()
{while(1){if(P3_1==0){Delay1ms(20);while(P3_1==0);Delay1ms(20);LED=~LED;}}
}
没有按下,不执行任何操作,保持原有状态 ,按下时,一直按着的话,就什么都不操作,执行while语句,一旦松手,跳出while语句,LED取反,再跳出if语句
1.3.独立按键控制LED按二进制递增亮
引入中间变量LEDNum,为什么呢,因为P2 ++,上电默认是不是1111 1111,加1变为0000 0000,全部亮,加一0000 0001,刚好与我们的预想的相反,而P2取反,就会1111 1111,变为0000 0000,取反you变为1111 1111,无法达到我们的效果,而引入中间变量LEDNum,LEDNum把值存起来,再给P2赋值就完美的解决了这一点,比如char类型刚好一个字节,存8位,
按下一次按键后LEDNum从0000 0000加加后变为0000 0001,取反1111 1110,给P2口,刚好第一个灯亮,而且LEDNum的值不会因为赋给P2而变成P2的值,还是 0000 0001,加一0000 0010 取反 1111 1101 给P2,刚好点亮第二个灯,依次循环,实现了用灯表示二进制,
#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;}}
}
1.4.两个独立按键控制LED移位,左移,右移
方法一:
0000 0001 0x01<<0
0000 0010 0x01<<1
0000 0100 0x01<<2
0000 1000 0x01<<3
..............
0 1 2 3 4定义为LEDNum,每按一下加一,加到7,LEDNum回到0,加个if语句。if(LEDNum>=8),LEDNum=0,因为LEDNum=7时,继续执行i++,
P2口应该与上面写的是反的,再取反操作。
代码如下
#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;elseLEDNum--;P2=~(0x01<<LEDNum);}}
}
注意:LEDNum是无符号型,最大值 255,LEDNum--的话,减到0,再减一的话,变成255,这就是越界。所以减到0我们重新让他变为7,
方法二:
每按一次独立按键,P2的数值变化如下
P2: 1111 1111 上电时, 我们用左移操作时,最低位是不是补0,我们在或上0x01,补成1
1111 1110 按一次按键 P2左移1位 ,此时P2=1111 1110
1111 1101 按两次按键 P2左移1位后或上0000 0001,
1111 1011 按三次按键 P2左移1位后或上0000 0001
...............
#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()
{ P2=0xFE;while(1){if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);P2=P2<<1|0x01;if(P2==0xFF){P2=0xFE;}}if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);P2=P2>>1|0x80;if(P2==0xFF){P2=0x7F;}}}
}
1.5:一个独立按键控制流水灯方向
代码如下:
方法一:一个代码编程所有:
#include <REGX52.H>
#include <INTRINS.H> //导入头文件
unsigned char LEDNum;
unsigned int count;
void Delay1ms(unsigned int xms) //@11.0592MHz //延时函数
{unsigned char i, j;while (xms--){i = 2;j = 199;do{while (--j);} while (--i);}
}void main()
{while(1){if(P3_1==0){Delay1ms(20);while(P3_1==0);Delay1ms(20); //软件消抖P2=0xFE;Delay1ms(500);LEDNum = 0xFE;while(1){while(count == 0) //当count为0时进入此循环{LEDNum =_crol_(LEDNum,1);P2 = LEDNum;Delay1ms(500);//1if(P3_1==0){Delay1ms(20);while(P3_1==0);Delay1ms(20);count = 1; //再次按下K1改变count值使进入逻辑右移}}while(count == 1) //当count为1时进入此循环{LEDNum =_cror_(LEDNum,1);P2 = LEDNum;Delay1ms(500);if(P3_1==0){Delay1ms(20);while(P3_1==0);Delay1ms(20);count = 0; //再次按下K1改变count值使进入逻辑左移}}} }}
}
方法2:模块化编程,
后面我们专门写一期怎么模块化编程,下面针对这个题进行一次模块化编程,涉及内容有中断,定时器,后面所以讲到了会一一再解释这里的所有代码的具体含义。
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_循环右移}
}
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;}
}
*/
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;
}
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);}
}
Delay.h :
#ifndef __DELAY_H__
#define __DELAY_H__void Delay(unsigned int xms);#endif