点亮一个LED(51)+(独立按键控制LED亮灭)

目录

1.LED介绍

2.硬件电路

3.程序设计

3.1.点亮一颗LED

3.2.LED闪烁

3.3.LED流水灯实现

4.按键介绍

5.按键电路

6.代码实现


1.LED介绍

       发光二极管也具有二极管普遍的特性单向导电性,有阳极和阴极之分 ,上图左侧式插件式LED ,长的引脚是阳极;左侧是贴片式的带色的一端是阴极,箭头指向是阴极,也就是电流的流向。二极管阳极接电源,阴极接地。电流大小一般在3-20ma之间,若是电流再大容易烧坏二极管。二极管的亮度和电流的大小有关,电流越大,发光二极管就越亮,自身带有导通压降1.7V 。

2.硬件电路

        为防止发光二级管因为电流而烧毁,需要串联一个电阻来限制电流的大小,硬件连接电路如下

        图中的电阻是排阻内有四个电阻并,阳极接在电源处,阴极经过排阻和单片机的I/0相连接,这样只有单片机输出的是低电平的时候,电路导通,二极管才能发光。

3.程序设计
3.1.点亮一颗LED

        假设控制是D1发光二极管,那么P20引脚只有输出低电平的情况下,电路导通。我们直接将P20口置为0,这样端口就是低电平了。

sbit LED1 = P2^0;
void main()
{
	LED1 = 0;
	while(1)
	{
		
	}
}

如何编程 P2.0管脚输出低电平

         1.先定义管脚 :使用一个关键字 sbit 是特殊功能寄存器的某一个位的位定义 P2寄存器 ,语句加分号结束

        2.直接将定义的引脚置为0 。

        程序从main函数执行,单片机不断的循环执行程序 ,如果有while就会一直执行while循环。

        code 程序flash大小 data ram 数据占用的大小 xdata 外部的ram 没有的话就不用调用了

        编译之后才会出现的上述的单位是字节

3.2.LED闪烁

        使用循环语句让D1二极管一亮一灭,想要实现可以让P2.0GPIO口一会输出低电平,一会儿输出高电平,当然还要有延时,人肉眼的识别要大于20-50ms。这里的延时程序是不准确的,想要精确的定时是要有定时器的。u16的最大值是65535。这里的延时时长和单片机的晶振频率有关。

#include <REGX52.H>
sbit LED1 = P2^0;

void delay_10us(u16 ten_us)//当传输ten_us=1的时候,大约10us
{
	while(ten_us--);
}
void main()
{
	while(1)
	{
		LED1 = 0;
		delay_10us(500000);
		LED1 = 1;
		delay_10us(500000);
	}

}
3.3.LED流水灯实现

        D1-D8一次点亮,移位操作和循环(while)的结合 ,对8个I/O进行操作,

        宏定义可以定义一组寄存器 ,定义P2端口 PORT端口,在宏定义的时候不用加分号

        P2.7是高位 P2.0是低位 左移之后,低位补0可以使用0x01移动之后取反,这样就会有一个二极管是常量的,总共有8个二极管,循环体要循环八次才能让每一个二极管亮一遍。

#include <REGX52.H>

typedef unsigned char u8;
typedef unsigned int u16;

#define LED_PORT    P2 

void delay_10us(u16 ten_us)
{
    while(ten_us--);
}
void main()
{
    while(1)
    {
        u8 i = 0;
        for(i = 9; i < 8;i++)
        {
            LED_PORT = ~(0X01<<i);
            delay_10us(50000);
        }        
    }

}

一个来回从D1-D8,再从D8-D1;使用的是 <intrins.H>头文件中包含的函数

#include <REGX52.H>
#include <intrins.H>
typedef unsigned char u8;
typedef unsigned int u16;

#define LED_PORT    P2 //

void delay_10us(u16 ten_us)
{
    while(ten_us--);
}
void main()
{
    u8 i = 0;
        LED_PORT = ~(0x01);
        delay_10us(50000);
    while(1)
    {
        for(i = 0; i < 7;i++)//这里循环了7次,因为刚开始D1灯已经亮了
        {
            LED_PORT = _crol_ (LED_PORT,1);//向左移动
            delay_10us(50000);
        }        
        for(i = 0; i < 7;i++)
        {
            LED_PORT = _cror_(LED_PORT,1);//向右移动
            delay_10us(50000);
        }        
        
    }

}

_crol_和_cror_和C语言中的位移符号是不一样的。

        使用函数进行位移情况,二级制的补码是首位相接的,如下

_crol_(11111110,1);
1111 1110 比如每一次移动一次 左移为例
1111 1101
1111 1011  //首位相连 _crol_(11111110,1);

        使用位移操作符<< 左移为例 移动一位,空白的区域填上0。

1111 1110
1111 1100
1111 1000 //每一次移动一位 <<1
4.按键介绍

        图片来自开发板开源教程,上图就是轻触按键了,初始状态按键的长边是导通的,短边不导通;当按下按键的时候,四角均导通;可以控制外部设备和调节参数。当按下按键的时候会有抖动,我们采用的是软件消抖的方式,来精确的读出按键所接引脚的高低电平。

为什么要消抖呢?

        当按下按键的时候,按键会有抖动,这个时候的电压不稳定可能会读取到高电平或者低电平,因此我们直接不读取这段时间的数值,直接延时2ms-10ms(抖动时间)来完成消抖。

        一般我们不会考虑释放抖动之后再读取数值。

5.按键电路

        图片中 按键一脚接单片机I/O口,一端接地,当按下高低电平时候,可以实现高电平到低电平的转换。

6.代码实现

u8 key_scan(mode)按键函数思路,

1.根据创建的枚举变量作为返回值来确定按个按键的按下

2.当mode=0的时候单次扫描,mode=1的时候是多次扫描。例如音量的加加和减减;

#include <REGX52.H>
#include <stdio.h>
#define  SMG_A_DP_PORT  P1 
sbit KEY1=P0^0;
sbit KEY2=P0^1;
sbit KEY3=P0^2;
sbit KEY4=P0^3;
sbit LED1=P2^0;
sbit LED2=P2^1;
sbit LED3=P2^2;
sbit LED4=P2^3;

enum KEY
{
	KEY_UNPRESS=0,
	KEY1_PRESS=1,
	KEY2_PRESS=2,
	KEY3_PRESS=3,
	KEY4_PRESS=4,
};//枚举
typedef unsigned char u8;
typedef unsigned int u16;
//ÑÓʱº¯Êý µ±1=ten_us,ÑÓʱ10us
void delay_10us(u16 ten_us)
{
	while(ten_us--);
}

u8 key_scan(mode)
{
	static u8 key=1;
	if(mode)
	{
		key=1;
	}
	if(key==1&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0))
	{	
		key=0;
		delay_10us(1000);
		if(KEY1==0)
		return KEY1_PRESS;
		else if(KEY2==0)
		return KEY2_PRESS;
		else if(KEY3==0)
		return KEY3_PRESS;
		else if(KEY4==0)
		return KEY4_PRESS;
	}
	else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1)
		{
			key=1;
		}
	return KEY_UNPRESS;
}


void main()
{
	
	u8 ret=0;

	while(1)
	{
		ret=key_scan(0);
		switch(ret)
		{
			case KEY1_PRESS:
			{
				LED1=!LED1;
				break;
			}
		    case KEY2_PRESS:
			{
				LED2=!LED2;
				break;
			}
			case KEY3_PRESS:
			{
				LED3=!LED3;
				break;
			}
			case KEY4_PRESS:
			{
				LED4=!LED4;
				break;
			}
		
		}	
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值