【51单片机学习】LED、独立按键

一、点亮一个LED

(一)LED介绍

VCC经过限流电阻连接到LED的正极,通过控制引脚的高低电平来控制LED的亮灭,单片机的TTL电平,高电平是5V低电平时0V,单片机输出高电平LED不点亮,输出低电平LED点亮。

贴片电阻的读数方式

单片机称为MCU,其内部集成了一个CPU,寄存器是一种特殊的存储器,八个分为一组,相当于按钮,每个寄存器都有一根线经过驱动器连接到I/O口,CPU可以通过程序直接访问寄存器,写1对应高电平,写0对应低电平,此时高低电平的问题就转化为了配置P2口的寄存器问题。单片机的操作方式都是CPU通过配置相应的寄存器控制硬件电路,使其能够满足需要的功能。

(二)进制转换

(三)代码示例

cs 复制代码
#include <REGX52.H>

void main()
{
	//P2 = 0xFE;//1111 1110
	P2 = 0x55;//0101 0101
	while(1)//非0即真
	{
		
	}
}

二、LED闪烁

(一)产生延时函数

利用STC-ISP生成延时。

如果直接复制代码的话会报错,为了避免该问题,需要添加头文件 #include <INTRINS.H> 。如果_nop_();大概是1微秒,对精度要求不是很高可以直接删掉_nop_();这行代码。

(二)代码示例

cs 复制代码
#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 1110
	P2 = 0xFF;//1111 1111
	while(1)
	{
		P2 = 0xFE;//1111 1110
		Delay500ms();
		P2 = 0xFF;//1111 1111
		Delay500ms();
	}
}

三、LED流水灯

(一)C51数据类型

在单片机中int类型是16位的,而在计算机中int类型是32位的。

int默认是有符号数,如果要表示无符号数应写为 unsigned int。

(二)代码示例

cs 复制代码
#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 1110
		Delay500ms();
		P2 = 0xFD;//1111 1101
		Delay500ms();
		P2 = 0xFB;//1111 1011
		Delay500ms();
		P2 = 0xF7;//1111 0111
		Delay500ms();
		P2 = 0xEF;//1110 1111
		Delay500ms();
		P2 = 0xDE;//1101 1111
		Delay500ms();
		P2 = 0xBE;//1011 1111
		Delay500ms();
		P2 = 0x7E;//0111 1111
		Delay500ms();
	}
}

(三)代码优化

上述代码的延时过于死板,为了使其变得更加灵活,可以先生成一个1毫秒延时函数,在子函数的括号中写入参数并指定变量类型,再写入一个while循环。

cs 复制代码
#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 1110
		Delay1ms(500);
		P2 = 0xFD;//1111 1101
		Delay1ms(500);
		P2 = 0xFB;//1111 1011
		Delay1ms(500);
		P2 = 0xF7;//1111 0111
		Delay1ms(500);
		P2 = 0xEF;//1110 1111
		Delay1ms(500);
		P2 = 0xDE;//1101 1111
		Delay1ms(500);
		P2 = 0xBE;//1011 1111
		Delay1ms(500);
		P2 = 0x7E;//0111 1111
		Delay1ms(500);
	}
}

四、独立按键控制LED亮灭

(一)独立按键

按键的一端接到单片机的IO口,另一端接地,单片机上电时,所有IO口默认为高电平,所以当按键未按下时保持高电平,当按键按下时则为低电平,寄存器还可以检测IO口的电平状态,读取高低电平,检测按键是否被按下。

sfr是对八位寄存器进行定义的。

sbit是位寄存器,是对每一位进行控制。

当头文件是REGX时,有对位的声明。

当头文件是REG时,没有对位的声明,需要自己定义声明。

(二)C51数据运算

(三)C51基本语句

if、switch表示选择,for、while表示循环,任何复杂的程序都可以由顺序、选择、循环这三个基本功能实现。

for循环主要用于指定次数的循环。

(四)代码示例

cs 复制代码
#include <REGX52.H>

void main()
{
//	P2 = 0xFE;  控制八位寄存器
	while(1)
	{
		if(P3_1 == 0)
		{
			P2_0 = 0;
		}
		else
		{
			P2_0 = 1;
		}
	}
}

五、独立按键控制LED状态

(一)按键的抖动

不同的按键抖动时间不同,消除抖动可以通过硬件解决(较麻烦),也可以通过软件解决(简单 延时即可)。

(二)代码示例

cs 复制代码
#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位的二进制的数据,与寄存器恰好对应。

cs 复制代码
#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~255
	while(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移位

cs 复制代码
#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<<1
	0000 0100		0x01<<2
	0000 1000		0x01<<3
	0001 0000		0x01<<4
	0010 0000		0x01<<5
	0100 0000		0x01<<6
	1000 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;
			else
				LEDNum--;
			P2 = ~(0x01<<LEDNum);//P2口是共阳极 所以给0亮 给1灭			
		}
	}
}