【51单片机零基础-chapter3:按键:独立按键|||附带常见C语句.逻辑运算符】
将unsigned char var=0;看作沟通二进制和十进制的桥梁
var是8位,初始为0000 0000;
同时可以进行十进制的运算
逻辑运算
位运算
& 按位与(有0则0)
| 按位或(有1则1)
~ 按位非
^ 按位异或(相同则1,不同为0)
<<按位左移 >>按位右移位运算符解释: 0011 1100 <<1 则变为 0111 1000 本质就是去掉最高K个位,最低K个位补充为0 右移同理,最低位k个全舍弃,最高位补充k个0 0011 1100 >>2 0000 1111 0011 1100 & 0010 0110 0010 0100
但是有符号数中负数的右移相当于填个1
单片机管脚指IO口
前面的LED灯有高低电平才会亮
单片机上电,所有IO口默认高电平
所以独立按键如果按下则低电平,没有按下默认高电平
寄存器写值会送到IO口
寄存器检测IO口电平,又会读回寄存器中
松开按键读寄存器则是高电平1,按下则读的是0
所以检测管脚电平高低,可以知道是否按下了按键.
#include <REGX52.H>
void main(){
P2=0xfe; //MIN bit=0;other bit =1;
while(1){
;
}
}
不难看出,这个点亮单个灯是通过控制寄存器实现的
但是需要给其它位赋值(8位为一组),即通过P2赋值
但我们只想操作最低位,不干涉别的位数强行赋值.
如何制定一位来控制?
打开头文件不难看到有指定位的方法
原来P2寄存器有指定的变量!
P2-0to7有八个引脚的赋值变量
所以有:
不使用0x十六进制全位赋值,指定控制某个位
#include <REGX52.H>
void main(){
//P2=0xfe; //MIN bit=0;other bit =1;
P2_0=0;//1-7 bit is unknown,but maybe default 1
while(1){
;
}
}
0是低电平,默认有高电平,此时存在一高一低,所以第一个灯会点亮,而其他的因为没有赋值默认为1不会点亮因为这些灯全是高电平.
此时你写了寄存器,那么就会被送到IO口
IO口产生的电平也会被送到寄存器从而得知0与1
独立按键
翻看手册,看到K1按键的口是RXD
所以K1-RXD-P3_1(P3_1,0,2,3)这个设计有点老了,本应该是0123对应K1234
#include <REGX52.H>
void main(){
//p2是灯,p3是按键,pk_num的num指的是第几个,一般从0开始,但是p3是1023顺序,p2是正常的0123
while(1){
if(P3_1==0){//如果按键是低电平,那么说明按下了
P2_7=0;//点亮
}else{
P2_7=1;//高电平,说明是默认值高电平没有按下,那么不点亮
}
}
}
按键抖动
对于独立按键,由于单片机检测频率不同于家用电器,单片机是可以监测到抖动的,因为按键的小铁片有弹性,不会马上变成稳定状态从而低电平,按下或松开都会发生5-10ms的抖动,这个抖动会导致频繁的被单片机监测到,从而造成按一下相当于按多次的情况,需要避免.
消抖方法:
1.硬件(不会)
2.软件,首次监测到执行,然后接下来5-10ms的抖动用延时单片机检测(delay啥也不干)来处理(首次按下瞬间,松开瞬间后都要消抖)
#include <REGX52.H>
void Delay(unsigned int x) //@12.000MHz
{
while(x--){
unsigned char i, j;
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
void main(){
while(1){
if(P3_1==0){//检测到按键的第一瞬间,马上执行按键消抖
Delay(15);
while(P3_1==0);//如果没放手则一直等待
//松手对应从while出来的一瞬间,马上执行松手消抖
Delay(15);
//消抖完毕,此时执行点亮操作
//P2_7=0;
P2_7=~P2_7;//按位取反也可点亮,特别适合开关逻辑,p2_7原来是1则变为0,若再按则0变为1熄灭
}
}
}
按一下,灯光移动一下
8个位置避免溢出,取余解决
灯光移动,以0000 0001逻辑左移解决
这是第k次按,则0000 0001<<k赋给灯光P2
#include <REGX52.H>
void Delay(unsigned int x);
void main(){
unsigned char ledvar=0;//because un char is 8bits data , and compatible with register data(8 bits)
while(1){
//default all bits is 1: just as 1111 1111
if(P3_1==0){
Delay(5);while(P3_1==0);Delay(5);
++ledvar;
ledvar%=8;
P2=~(0x01<<ledvar);
}
}
}
void Delay(unsigned int x) //@12.000MHz
{
while(x--){
unsigned char i, j;
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
稍作更改得到
按键1得到右移,按键2得到左移
主要还是在代码的逻辑
因为最终的显示取决于P2每位的值,以便赋予各管脚高低电平
而P2由0x01即0000 0001的每轮左右得到,这是0x01是不变的
关键在于移的位数
如果本轮左移动了7位,那么下一轮左移就左移6位即可(通过右移的位数偏差,实现当轮左移的逻辑)
void main(){
unsigned char ledvar=0;//because un char is 8bits data , and compatible with register data(8 bits)
while(1){
//default all bits is 1: just as 1111 1111
if(P3_1==0){
Delay(5);while(P3_1==0);Delay(5);
++ledvar;
ledvar%=8;
P2=~(0x01<<ledvar);
}
else if(P3_0==0){
Delay(5);while(P3_0==0);Delay(5);
--ledvar;
ledvar%=8;
P2=~(0x01<<ledvar);
}
}
}
按键实现二进制灯光模拟:
按k次,二进制是多少,则亮对应的灯
逻辑上,初始全0,恰好无符号字符var就是8位,刚好适合,那么初始置为0,既有0000 0000的数据
此时++,有:
0000 0001第一次
0000 0010第二次
0000 0011第三次按下
…
1111 1111
0000 0000
…
核心代码
void main(){
unsigned char ledvar=0//because un char is 8bits data , and compatible with register data(8 bits)
while(1){
//default all bits is 1: just as 1111 1111
if(P3_1==0){
Delay(5);while(P3_1==0);Delay(5);
++ledvar;
p2=~ledvar;
}
}
}
今天晚上单片机刚到,先结束一个章节.
收工,刷抖音去了