【51单片机学习】LED、独立按键
一、点亮一个LED
(一)LED介绍
VCC经过限流电阻连接到LED的正极,通过控制引脚的高低电平来控制LED的亮灭,单片机的TTL电平,高电平是5V低电平时0V,单片机输出高电平LED不点亮,输出低电平LED点亮。
贴片电阻的读数方式
单片机称为MCU,其内部集成了一个CPU,寄存器是一种特殊的存储器,八个分为一组,相当于按钮,每个寄存器都有一根线经过驱动器连接到I/O口,CPU可以通过程序直接访问寄存器,写1对应高电平,写0对应低电平,此时高低电平的问题就转化为了配置P2口的寄存器问题。单片机的操作方式都是CPU通过配置相应的寄存器控制硬件电路,使其能够满足需要的功能。
(二)进制转换
(三)代码示例
#include <REGX52.H>void main()
{//P2 = 0xFE;//1111 1110P2 = 0x55;//0101 0101while(1)//非0即真{}
}
二、LED闪烁
(一)产生延时函数
利用STC-ISP生成延时。
如果直接复制代码的话会报错,为了避免该问题,需要添加头文件 #include <INTRINS.H> 。如果_nop_();大概是1微秒,对精度要求不是很高可以直接删掉_nop_();这行代码。
(二)代码示例
#include <REGX52.H>
#include <INTRINS.H>void Delay500ms(void) //@11.0592MHz 括号内的void可省略
{unsigned char data i, j, k;_nop_();//需加定义 是空语句的意思i = 4;j = 129;k = 119;do{do{while (--k);} while (--j);} while (--i);
}void main()
{P2 = 0xFE;//1111 1110P2 = 0xFF;//1111 1111while(1){P2 = 0xFE;//1111 1110Delay500ms();P2 = 0xFF;//1111 1111Delay500ms();}
}
三、LED流水灯
(一)C51数据类型
在单片机中int类型是16位的,而在计算机中int类型是32位的。
int默认是有符号数,如果要表示无符号数应写为 unsigned int。
(二)代码示例
#include <REGX52.H>
#include <INTRINS.H>void Delay500ms(void) //@11.0592MHz
{unsigned char data i, j, k;_nop_();//约1us可删去 影响不大 若不删需加头文件i = 4;j = 129;k = 119;do{do{while (--k);} while (--j);} while (--i);
}void main()
{while(1){P2 = 0xFE;//1111 1110Delay500ms();P2 = 0xFD;//1111 1101Delay500ms();P2 = 0xFB;//1111 1011Delay500ms();P2 = 0xF7;//1111 0111Delay500ms();P2 = 0xEF;//1110 1111Delay500ms();P2 = 0xDE;//1101 1111Delay500ms();P2 = 0xBE;//1011 1111Delay500ms();P2 = 0x7E;//0111 1111Delay500ms();}
}
(三)代码优化
上述代码的延时过于死板,为了使其变得更加灵活,可以先生成一个1毫秒延时函数,在子函数的括号中写入参数并指定变量类型,再写入一个while循环。
#include <REGX52.H>void Delay1ms(unsigned int xms) //@11.0592MHz 括号内为子函数的形参
{unsigned char data i, j;while(xms){//_nop_();i = 2;j = 199;do{while (--j);} while (--i);//xms = xms-1;xms--;//每执行一次 减少1ms 从而达到输入多少ms就延时多少ms}
}void main()
{while(1){P2 = 0xFE;//1111 1110Delay1ms(500);P2 = 0xFD;//1111 1101Delay1ms(500);P2 = 0xFB;//1111 1011Delay1ms(500);P2 = 0xF7;//1111 0111Delay1ms(500);P2 = 0xEF;//1110 1111Delay1ms(500);P2 = 0xDE;//1101 1111Delay1ms(500);P2 = 0xBE;//1011 1111Delay1ms(500);P2 = 0x7E;//0111 1111Delay1ms(500);}
}
四、独立按键控制LED亮灭
(一)独立按键
按键的一端接到单片机的IO口,另一端接地,单片机上电时,所有IO口默认为高电平,所以当按键未按下时保持高电平,当按键按下时则为低电平,寄存器还可以检测IO口的电平状态,读取高低电平,检测按键是否被按下。
sfr是对八位寄存器进行定义的。
sbit是位寄存器,是对每一位进行控制。
当头文件是REGX时,有对位的声明。
当头文件是REG时,没有对位的声明,需要自己定义声明。
(二)C51数据运算
(三)C51基本语句
if、switch表示选择,for、while表示循环,任何复杂的程序都可以由顺序、选择、循环这三个基本功能实现。
for循环主要用于指定次数的循环。
(四)代码示例
#include <REGX52.H>void main()
{
// P2 = 0xFE; 控制八位寄存器while(1){if(P3_1 == 0){P2_0 = 0;}else{P2_0 = 1;}}
}
五、独立按键控制LED状态
(一)按键的抖动
不同的按键抖动时间不同,消除抖动可以通过硬件解决(较麻烦),也可以通过软件解决(简单 延时即可)。
(二)代码示例
#include <REGX52.H>void Delay(unsigned int xms) //@11.0592MHz 0~65535
{unsigned char data i, j;// _nop_();while(xms){i = 2;j = 199;do{while (--j);} while (--i); xms--;}}void main()
{while(1){if(P3_1 == 0)//按下一直循环,放开跳出循环,松手后led出现操作{Delay(20);while(P3_1 == 0);//若循环体为空,可直接加分号Delay(20);//消除松手抖动P2_0 = ~P2_0;//按下时执行whlie空语句,松开就跳出循环,执行取反操作,亮灯}}
}
六、独立按键控制LED显示二进制
(一)错误代码
IO口上电默认为高电平 1111 1111,再加1就会产生溢出,变为 0000 0000,此时P2再取反,又会变成 1111 1111。
(二)代码示例
为了避免上述代码中出现的错误,可以定义一个变量,对变量进行操作,最后再将变量送给P2口。无符号字符型unsigned char是8位的二进制的数据,与寄存器恰好对应。
#include <REGX52.H>
void Delay(unsigned int xms) //@11.0592MHz
{unsigned char data i, j;// _nop_();while(xms--)//与在程序末尾加xms--是一样的效果{i = 2;j = 199;do{while (--j);} while (--i);}
}void main()
{unsigned char LEDNum = 0;//自定义变量 0~255while(1){if(P3_1 == 0){Delay(20);//注意下这个按键结构,按下通电松开断电,所以要做松手检测while(P3_1 == 0);//这边的while,当你没松手时一直按着按键会就进入while循环,防止一直执行下去,去掉的话你会发现灯会一直闪Delay(20);// P2++; 1111 1111 -> 0000 0000 -> 1111 1111使得灯一直不亮
// P2 = ~P2;LEDNum++;P2 = ~LEDNum;}}
}
七、独立按键控制LED移位
#include <REGX52.H>void Delay(unsigned int xms) //@11.0592MHz
{unsigned char data i, j;// _nop_();while(xms--)//与在程序末尾加xms--是一样的效果{i = 2;j = 199;do{while (--j);} while (--i);}
}unsigned char LEDNum; //全局变量若不赋初值则默认为零void main()
{P2 = ~0x01;//上电时进行初始化
// unsigned char//局部变量定义时需要附初始值while(1){if(P3_1 == 0){Delay(20);while(P3_1 == 0);Delay(20);
/* 0000 0001 0x01<<0 按位左移0000 0010 0x01<<10000 0100 0x01<<20000 1000 0x01<<30001 0000 0x01<<40010 0000 0x01<<50100 0000 0x01<<61000 0000 0x01<<7 */LEDNum++;if(LEDNum>=8)//越界判断{LEDNum = 0;}P2 = ~(0x01<<LEDNum);//P2口是共阳极 所以给0亮 给1灭}if(P3_0 == 0){Delay(20);while(P3_0 == 0);Delay(20);if(LEDNum == 0)//对于无符号字符型减到0后再减会变成255,为了避免这一现象需要提前进行处理LEDNum = 7;elseLEDNum--;P2 = ~(0x01<<LEDNum);//P2口是共阳极 所以给0亮 给1灭 }}
}