基于51单片机通过GPIO口点亮LED灯

控制/MCU

1815人已加入

描述

前言

在之前的教程中,我们成功搭建了开发环境,初步对开发板的GPIO口有了一定的了解,在本教程中,我们将带领大家制作第一个工程,就是通过GPIO口来点亮一盏LED小灯!

一、LED简介

LED 即发光二极管。它具有单向导电性,通过5mA 左右电流即可发光,电流越大,其亮度越强,但若电流过大,会烧毁二极管,一般我们控制在3 mA-20mA之间,通常我们会在LED 管脚上串联一个电阻,目的就是为了限制通过发光二极管的电流不要太大,因此这些电阻又可以称为“限流电阻”。当发光二极管发光时,测量它两端电压约为1.7V,这个电压又叫做发光二极管的“导通压降”。

下图左右分别为直插式发光二极管和贴片式发光二极管实物图。发光二极管正极又称阳极,负极又称阴极,电流只能从阳极流向阴极。直插式发光二极管长脚为阳极,短脚为阴极( 长正短负、大负小正 )。仔细观察贴片式发光二极管正面的一端有彩色标记通常有标记的一端为阴极。

二、硬件设计

开发板上LED 模块电路如下图所示:

发光二极管

在前面我们介绍过如何查看原理图,相同网络标号表示它们是连接在一起的,该模块独立,可自由连接单片机IO 口,因此D1-D8 可连接到单片机的P20-P27口。图中LED 采用 共阳接法 ,即所有LED 阳极管脚接电源VCC,阴极管脚通过一个470 欧的限流电阻接到P2 口上。根据前面LED 的介绍我们知道,要让LED 发光即对应的阴极管脚应该为低电平,若为高电平则熄灭。

如果要想51 单片机控制LED,就必须通过单片机管脚在P2 口上输出低电平。本教程所要实现的功能是:点亮D1 指示灯。

三、程序设计

#include< reg52.h > //头文件
sbit LED1=P2^0;  //将P2.0管脚定义为LED1


void main()
{  
  while(1)
  {  
   LED1=0;   //LED端口设置为低电平 即点亮LED灯
  }
}

main.c 文件内代码非常少也很简单,首先将51 单片机的头文件包含进来,然后使用sbit 关键字来定义P2.0 管脚,定义好后即可使用LED1 来替代P2.0口的操作。主函数功能非常简单,首先让LED1 为低电平,即P2.0 口输出为低电平,D1 指示灯即点亮,然后进入while 循环,单片机此时一直在while 内循环操作。当然该条语句也可以放在while 循环语句内,同样会点亮D1 指示灯。在51 单片机程序开发中,main 函数内通常都会有一个while 循环,在循环体内不断执行我们所要实现的功能。对于仅点亮LED,可以把控制语句放在while 之前来执行。

至此,整个程序就编写完成,我们编译一下,如下图所示:

发光二极管

可以看到没有错误,也没有警告。

从编译信息可以看出,我们的代码占用FLASH 大小为:19 字节,所用的SRAM 大小为:9 个字节(9+0)。这里我们解释一下,编译结果里面的几个数据的意义:

code:表示程序所占用FLASH 的大小。

data:数据储存器内部RAM 占用大小。

xdata:数据储存器外部RAM 占用大小。

有了这个就可以知道你当前使用的flash 和sram 大小了。一定要注意的是程序的大小不是.hex 文件的大小,而是编译后的code 和data 之和。

四、LED 闪烁实验

如果要实现LED 闪烁,只需循环让D1 指示灯先亮一会后熄灭。这里就有一个延时问题,如何来产生延时呢?我们知道单片机执行每条代码指令都是需要时间的,在前面介绍C 语言时讲解过循环语句,因此只需编写一个循环函数,让CPU 不干其它事,专门在那循环运行即可实现延时功能。依据人的肉眼余晖效应,延时时间不能太短,否则就无法观察到LED 闪烁。

void delay_10us(u16 time_us)
{
  while(time_us--);
}

上述代码即为延时函数,通过while 循环来实现。函数入口有一个形式参数ten_us,如果ten_us 等于1,则while 循环执行一次,调用该函数延时时间大约10us,当然使用循环来实现延时,这种延时是不精确的,目前我们先得到个大概的时间即可。

细心的朋友可能会看到函数形参ten_us 是u16 类型的,这个似乎不是C 语言数据类型关键字,这是我们重定义的数据类型,如下:

typedef unsigned int u16;
typedef unsigned char u8;

使用关键字typedef 对系统默认数据类型unsigned int 和unsigned char重新命名,主要是方便我们代码的书写和变量类型的查看。u16 即代表该变量是16 位的无符号整型数据,u8 代表该变量是8 位的无符号字符型数据。有了这个就知道参数的传送范围,不能超过形参定义的范围。

下面看下main 函数代码,如下:

void main()
{  
  while(1)
  {
    LED1=0;            //点亮
    delay_10us(50000);  //延时大概450ms
    LED1=1;            //熄灭
    delay_10us(50000); 
  }
}

main 函数内实现功能很简单,在while 循环内不断间隔一定时间点亮LED1和熄灭LED1,这样即可实现D1 指示灯闪烁。细心的朋友可能会问,前面delay_10us 函数形参为1 时大约是10us,那现在实参传输50000,不应该是500ms吗,为什么注释写的是450ms 呢?这里还得回到刚才话题,使用循环来延时只是获得一个大概的时间,并不能精确,如需精确延时,后期我们会学习定时器。此处就不用纠结这个问题。

#include< reg52.h > 
typedef unsigned int u16;
typedef unsigned char u8;


sbit LED1=P2^0;  


void delay_10us(u16 time_us)
{
  while(time_us--);
}


void main()
{  
  while(1)
  {
    LED1=0;            //点亮
    delay_10us(50000);  //延时大概450ms
    LED1=1;            //熄灭
    delay_10us(50000); 
  }
}
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分