(一)项目任务

ü 任务1:点亮LED

n 子任务1.1 LED电路认识

n 子任务1.2 C语言编程框架认识

n 子任务1.3 实现点亮LED功能

ü 任务2:LED流水灯功能实现

n 子任务2.1 C语言---for等基本语句认识

n 子任务2.2 实现流水灯功能

(二)相关知识点

2.1、位的概念

51单片机为8位单片机,一次性能处理一个字节(Byte),一个字节由8个bit位组成,例如P0.0,P0.1...P0.6,P0.7这8个位组成P0口,单片机可以分别处理P0.0,P0.1...P0.6,P0.7口引脚数据,也可以同时处理P0口8个位数据。

2.2、进制的概念

常用的进制有二进制、十进制和十六进制。十进制,逢十进位,一个位有十个值:0~9。二进制就是逢二进位,它的一个位只有两个值:0和1,但它却是实现计算机系统的最基本的理论基础,计算机(包括单片机)芯片是基于成万上亿个的开关管组合而成,他们每一个都只能有开和关两种状态,理解二进制对于理解计算机的本质很有帮助。书写二进制数据时需加前缀0b,每一位的值只能是0或1。十六进制就是把4个二进制位组合为一位来表示,它的每一位有0b0000~0b1111共16个值,用0~9再加上A~F(或a~f)表示,本质上同二进制一样,是程序编写中常用的形式。书写十六进制数据时需加前缀0x,表1是三种进制之间的对应关系。

对于二进制来说,8位二进制称之为一个字节,二进制的表达范围值是从0b00000000~0b11111111,而在程序中用十六进制表示的时候就是从0x00到0xFF,这里教大家一个二进制转换十进制和十六进制的方法,二进制4位一组,遵循8/4/2/1的规律比如0b1010,那么从最高位开始算,数字大小是8*1+4*0+2*1+1*0 = 10,那么十进制就是10,十六进制就是0xA。尤其二进制转十六进制的时候,十六进制一位和二进制的4位相对应。

对于进制来说,只是数据的表现形式,而数据的大小不会因为进制表现形式不同而不同,比如二进制的0b1、十进制的1、十六进制的0x01,他们本质上是数值大小相等的同一个数据。在进行C语言编程的时候,只写十进制和十六进制,那么不带0x的就是十进制,带了0x符号的就是十六进制。

2.3、发光二极管LED简介

发光二极管,是一种固态的半导体器件,它可以直接把电转化为光。LED的心脏是一个半导体的晶片,晶片的一端附在一个支架上,一端是负极,另一端连接电源的正极,整个晶片被环氧树脂封装起来。半导体晶片由两部分组成,一部分是P型半导体,在它里面空穴占主导地位,另一端是N型半导体,电子占主导地位。两种半导体连接起来的时候,它们之间形成一个“PN结”。当电流通过导线作用于这个晶片的时候,电子就会被推向P区,在P区里电子跟空穴复合,然后就会以光子的形式发出能量,这就是LED发光的原理。光的波长也就是光的颜色,是由形成P结的材料决定。

LED二极管通常的正向导通电压是1.8V到2.2V之间,工作电流一般在1mA~20mA之间。其中,当电流在1mA~5mA之间变化时,随着通过LED的电流越来越大,会明显感觉到这个小灯越来越亮,而当电流从5mA~20mA 之间变化时,发光二极管的亮度变化不是太明显了。当电流超过20mA时,LED就会有烧坏的危险,电流越大,烧坏的也就越快。所以在使用过程中应该特别注意它在电流参数上的设计要求,设计LED电路中要添加适当大小的电阻。VCC电压是5V,发光二极管自身压降大概是2V,那么在电阻上承受的电压就是3V。那么现在要求电流范围是1~20mA,可以根据欧姆定律R=U/I,把这个电阻的上限和下限值求出来。U=3V,当电流是1mA的时候,电阻值是3K;当电流是20mA的时候,电阻值是150欧,即R的取值范围是150~3K欧姆。这个电阻值大小的变化,直接可以限制整条通路的电流的大小,因此这个电阻通常称之为“限流电阻”。

2.4、LED点亮的两种方式

点亮LED有两种方式,以P0.0为例,图1(a)表示当P0.0为高电平时LED亮,图1(b)表示当P0.0为低电平时LED亮,常用的方式为图1(b),这是因为:

①51单片机上电复位时I/O的初始值为高电平,此时若采用(a)方式在默认上电情况下LED会点亮;

②单片机I/O驱动能力弱,一般用作灌电流。

灌电流是指单片机输出低电平时,将允许外部器件向单片机引脚内灌入的电流;拉电流是指单片机输出高电平时,则允许外部器件,从单片机的引脚拉出的电流。51单片机的灌电流最大电流为10mA,P1、P2以及P3允许总电流最大为15mA;P0灌入的最大总电流为26mA。全部的四个接口所允许的灌电流之和最大为71mA,而单片机的“拉电流”不到1mA,因此采用图1(b)方式点亮LED更为方便。

(a)高电平点亮
(b)低电平点亮

图1 LED点亮的两种方式

2.5、LED电路部分

配合本教材配套的开发板,如图2以点亮LED3为例,LED阳极连接+5V,负极连接P0.7,因此点亮该LED需要负极为低电平,即P0.7输出低电平,在开发板上从右到左依次为P0.4、P0.5、P0.6、P0.7,如图2(b)所示。

(a)LED原理图
(b)LED硬件连接图

图2 LED连接图

2.6、程序框架

常用的框架如图3所示,为了便于理解,采用伪代码的形式,一般来说,最小代码结构包括头文件和主函数,随着学习的深入还会发现程序中包含声明区和子函数,程序中有且只有一个主函数,子函数可有可无,甚至可以有无数个。

图3 程序最小框架图

2.7、C语言知识点---头文件、函数等概念和语句

2.7.1 头文件作用

头文件的作用相当于在该行位置键入文件“reg52.h”的全部内容。打开任意程序,编译后将鼠标放置“<reg52.h>”的任意位置,如图4所示,选择“Open document<reg52.h>”,即可打开“reg52.h”的文档,部分内容如图5所示,可以看到一系列的定义,主要是“sfr”和“sbit”这两个关键字来进行定义。以“sfr P0 =0x80”为例,意思是将单片机硬件的0x80这个地址赋给P0这两个字母。在项目1提到过,学习单片机的实质是通过寄存器实现对引脚的控制,在头文件中通过关键字“sfr”实现变量P0和地址的联系,每个寄存器都有唯一地址,操作地址的过程其实是控制寄存器的过程。通俗的讲,通过这样定义之后对P0的操作就会执行到0x80地址的寄存器中。因为程序最终是要由硬件来执行,所以本质上是对单片机的硬件地址进行操作。51单片机具有P0、P1、P2、P3,四个统称IO口,每个统称IO口有8个IO口。sfr P0 =0x80就是将P0的8个IO口定义为P0口,就是说sfr一次定义了8位,这时不难发现sfr和sbit的区别:sfr能一次定义8位,sbit一次只能定义一位。

图4 打开头文件操作界面图
图5 头文件部分内容

了解了这两个语句后,看一下单片机的特殊功能寄存器。请注意,每个型号的单片机都会配有生产厂商所编写的数据手册(Datasheet),看一下STC89C52的数据手册,从21页到24页,全部是对特殊功能寄存器的介绍以及地址映射列表,如图6所示。在使用这个寄存器之前,必须对这个寄存器的地址进行说明。

图6 IO口特殊功能寄存器

其中P4口STC89C52对标准51的扩展,先忽略它,只看前边的P0、P1、P2、P3这4个,每个P口本身又有8个控制端口。可以结合开发板原理图看,这样就确定了单片机一共有32个IO口(IO,Input和Output,分别是输入和输出)。

其中P0口所在的地址是0x80,一共有从7到0这8个IO口控制位,后边有个Reset Value(复位值),这个很重要,是看寄存器必看的一个参数,8个控制位复位值全部都是1。即每当单片机上电复位的时候,所有的引脚的值默认是都是1,即高电平,在设计电路的时候也要充分的考虑这个问题。

那么上边那2条语句,写sfr的时候,必须要根据手册里的这个地址(Add)去写,写sbit的时候,就可以直接将一个字节其中某一位取出来。编程的时候,也有现成的写好寄存器地址的头文件,直接包含该头文件就可以了,不需要逐一去写,头文件的作用也在于此!

2.7.2 变量

在编写C语句中,会用到各类数字,在使用这些数字前首先需要在内存开辟一块空间来存放数字,因为内存空间是以地址命名,不容易记,因此常用一个变量名来代替这块空间,例如“int num =1;”,“num”就是一个变量名,“=”表示赋值,不同于我们之前了解的“等于”,在C语句中的等于用“==”来表示。

在给变量“num”开辟空间时需要指定空间的大小,即变量的类型,“int”常用的类型,表示整型,常用的如表2所示。

常用的类型有unsigned char,unsigned int,例如定义一个变量“unsigned char i”,则i的取值范围为0~255,再如i的值大概在10000左右,要选择unsigned int类型。

2.7.3 声明

声明的作用是告诉编译器一个变量或者函数将在接下去的程序中用到,使编译器提前“认识”该变量或者函数,在图3中“sbit LED = P0^7;”即为一条声明语句,变量“LED”表示地址P0口的第8位(注意:第一位为P0^0),类型为位类型,通过该语句将P0的第8位和LED建立了联系。

2.7.4 函数定义

函数定义的一般形式如下:

函数值类型 函数名 (形式参数列表)

{

函数体

}

1、函数值类型,就是函数返回值的类型。在后边的程序中,会有很多函数中有return x语句,这个返回值也就是函数本身的类型。还有一种情况,就是这个函数只执行操作,不需要返回任何值,那么这个时候它的类型就是空类型 void,这个void按道理来说是可以省略的,但是一旦省略,Keil软件会报一个警告,所以通常也不省。

2、函数名,可以由任意的字母、数字和下划线组成,但数字不能作为开头。函数名不能与其他函数或者变量重名,也不能是关键字。关键字是程序中具备特殊功能的标志符,不可以命名函数,比如char。

3、形式参数列表,也叫做形参列表,这个是函数调用的时候,相互传递数据用的。有的函数不需要传递参数给它,那么可以用void来替代,void同样可以省略,但是那个括号是不能省略。

4、函数体,包含了声明语句部分和执行语句部分。声明语句部分主要用于声明函数内部所使用的变量,执行语句部分主要是一些函数需要执行的语句。特别注意,所有的声明语句部分必须放在执行语句之前,否则编译的时候会报错。

5、一个工程文件必须有且仅有一个main函数,程序执行的时候,都是从main函数开始的。

2.7.4.1 主函数

一个C程序从main()开始执行,执行的内容在“{ }”中,“{}”总是成对出现,一对“{}”上下对齐,便于阅读和理解。一般称main()为主函数,一个程序里有且只有一个主函数。框架为:

void main()
{
//c程序内容
}

图7 主函数框架

2.7.4.2 子函数

一个函数中可以有一个或者多个子函数,也可以没有。子函数可以理解为具有一定功能的语句集合,方便于主函数调用实现特定的功能。在3.2小节while语句中“LED = 1;delay();LED = 1;delay();”,按照C语言从上到下的执行规则,先执行“LED = 1;”,再执行“delay();”,delay()函数的作用是延时1s,再执行“LED = 1;delay();”,执行完最后一句后重新再从头执行。delay()函数的内容即为delay(){…}中括号里的内容,在下面的“for”语句中会详细讲解。

2.7.5 while语句

在C语言里,通常表达式符合条件叫做真,不符合条件叫做假。比如前边i<30000,当i等于0的时候,那这个条件成立,就是真;如果i大于30000的时候,条件不成立,就叫做假。

while(表达式)这个括号里的表达式,为真的时候,就会执行循环体语句,当为假的时候,就不执行。

while(表达式)

{

语句体;

}

还有另外一种情况,除了表达式外,还有常数,习惯上,把非0的常数都认为是真,只有0认为是假,所以程序中使用了while(1),这个数字1,可以改成2、3、4......等等都可以,都是一个死循环,不停的执行循环体的语句,但是如果把这个数字改成0,那么就不会执行循环体的语句。

2.7.6 for语句

for语句使用较多,常用的方式如图8所示,for语句有三个判断条件,执行过程:首先判断执行表达式1,一般情况下在整个for语句中执行一次,再执行表达式2,判断是否满足条件,在满足表达式2的情况下执行语句体,执行完成后再执行表达式3,表达式3一般自增或者自减,再跟表达式2比较判断,如继续满足则执行语句体,不满足表达式2则跳出for语句循环。

以图9“for”循环为例,执行过程:①将0赋值给变量i;②判断i<183是否成立,0<183成立;③执行“for(j=0;j<1000;j++);”语句;④:执行 “i++”,表示i自增1,原来i为0,自增1后为1;⑤判断i<183是否成立,1<183成立;⑥执行“for(j=0;j<1000;j++);”语句;⑦执行“i++”,表示i自增1,原来i为1,自增1后为2;…….直至条件不满足i<183,跳出整个for循环。

注意for(j=0;j<1000;j++);是for(j=0;j<1000;j++) { };缩写,它的语句体为空,即执行1000次空语句,图8整个for语句执行的次数为183*1000=183000次,即执行183000次空语句,通过执行空语句来达到延时的目的,至于为何是183000次,1s时间是否准确的问题将在仿真项目中详细讲解。

2.7.7 #define的使用方法

#define 标识符 替换列表

标识符的几点说明:

标识符由字母(A-Z,a-z)、数字(0-9)、下划线“_”组成,并且首字符不能是数字,但可以是字母或者下划线。不能把C语言关键字作为用户标识符,关键字例如if ,for,while等,在Keil界面中会显示粗黑体。标识符对大小写敏感,严格区分大小写。一般对变量名用小写,符号常量命名用大写,例如LED和led是两个不同的标识符。标识符命名应做到“顾名思义”,例如,LED代表有关LED的内容,替换列表可以是数字、字符、标点符号、标识符,关键字、字符常量等。

#define是预处理命令,在编译处理时进行简单的替换,例如“#define LED P0”,在编译处理时会用P0代替标识符LED。特别是在程序移植过程中作用更加明显,因为一个变量会出现在程序的很多地方,这样在这个变量改变后需要在每处都改变。如果在一开始用这种宏定义的方法,只需改变宏定义的数值即可。

(三)设计实施

3.1、点亮第一位LED灯

#include <reg52.h>   //头文件
sbit  LED= P0^4;  //定义使用的引脚
/*主函数有且只有一个*/
void  main()
{
while(1)   //循环函数
{
LED = 0; //0赋值给变量LED
}}

本小结展示了最小的程序框架,包括头文件、主函数和循环函数,一个函数有且只有一个主函数同时还需要注意几点:

① “//”表示注释, Keil软件在编译过程中不能识别“//”后面的文字;

②/* */表示另一种注释方式,文字放于“/*”“*/”之间,一般用于文字较多的情况;

③注意大小写,LED和led表示不同的变量;

④程序中的字母和符号都需要在英文输入法状态下输入;

⑤分号在C语言中表示一句话的结束,一定要在英文状态下输入。

将该程序输入到单片机中,观察实验现象。

3.2、实现一个LED闪烁功能

#include <reg52.h>   //头文件
sbit  LED  = P0^4;  //定义使用的引脚
/*主函数有且只有一个*/
void delay();//函数声明
void  main()
{while(1)   //循环函数{LED = 0;   //0赋值给变量LED, LED点亮delay();    //延时1sLED = 1;   // 1赋值给变量LED, LED熄灭delay();    //延时1s}
}
void delay()
{unsigned int i , j; //变量i , j的范围均为0~65535for(i=0;i<183;i++){for(j=0;j<1000;j++);}
}

①C程序执行过程:循环执行while语句内容,①LED = 0;②delay();③LED = 1;④delay();①②③④①②….注意执行到②时,会跳转到下面的delay子函数,执行完成后返回③继续执行,即主函数在执行过程中会调用子函数。

②本程序有两个函数,main主函数和delay子函数,如果在主函数之前定义了子函数,那么就不需要再次声明这个函数,如果在主函数之后定义了子函数,那么在主函数之前必须对其进行声明。

③void delay()这个函数中的“void”表示该函数执行完成后无返回值,在以后程序中会出现需要返回一个函数值的情况。

3.3、实现LED流水灯功能

本小结以两种方式实现LED流水灯功能,即第一盏LED亮其余都灭,延时1s,第二盏亮其余都灭,延时1s….. 第四盏LED亮其余都灭,延时1s,再从第一盏开始,第一盏亮其余都灭…..

之前实例中均采用位控制,在接下来的实例中采用4位同时控制的方式,读者亦可以根据要求写出用位控制流水灯的程序,与“方法一”做比较。

方法一:

#include <reg52.h>
#define LED P0
void delay();
void main()
{   while(1)
{
LED = 0xEF;  //二进制:11101111 delay();     LED = 0xDF;  //二进制:110111111delay();     LED = 0xBF;  //二进制:10111111 delay();     LED = 0x7F;  //二进制:01111111 delay();     }
}
void delay()
{unsigned  int  i , j; //变量i , j 的范围为0~65535for(i=0;i<183;i++)
{for(j=0;j<1000;j++);
}
}

① “LED = 0xEF;” 本质是将0xEF赋值给了P0口;

② 注意“for(j=0;j<1000;j++);”中的分号,其实是“for(j=0;j<1000;j++) {};”的缩写。

③ 据硬件原理图可知,4个LED相应连接的是P0.4、P0.5、P0.6、P0.7。

方法二:

#include <reg52.h>
#define LED P0
void delay();
void main()
{//P0 = 0XFF;while(1){unsigned char k;for(k=0;k<4;k++){LED =~(0x10<<k);delay();}}
}
void delay()
{unsigned int i , j;for(i=0;i<183;i++){for(j=0;j<1000;j++);}
}

① “P0 = 0XFF;”语句可写可不写,这是因为P0在上电时初始化为高电平;

② “<<”符号表示左移的意思,例如“0x01<<3”表示0x01左移3位,0x01化为二进制“0000 0001”,左移三位后为“00001000”,遵循“高位移出,低位移入补0”原则。

③ “>>”符号表示右移的意思,例如“0xFF<<3”表示0xFF左移3位,0xFF化为二进制“1111 1111”,右移三位后为“0001 1111”,遵循“高位移入补0,低位移出”原则。

④ “~”表示取反,例如:“0x01”取反后为“0xFE”。

⑤ 根据LED原理图,思考下如果有8个LED怎么用此方法编程。

(四)小结

掌握C语言中涉及到的相关概念语句,实现多种点亮LED的方法。

在B站观看相关视频!!

哔哩哔哩 ( ゜- ゜)つロ 乾杯~ Bilibili

单片机led灯闪烁实验总结_项目二 LED灯闪烁设计实现相关推荐

  1. 单片机led灯闪烁实验总结_单片机很好玩3,花三分钟,使用普通LED小灯,制作手机“呼吸灯”...

    上一节为了解决单片机 IO 电流驱动能力不足,导致 LED 小灯亮度不高的问题,借助了三极管.单片机的 IO 通过三极管开关 LED 小灯的电流,最后的确明显让小灯的亮度更高了. 使用电路模拟软件 还 ...

  2. 两地控制的项目要求_项目两地控制灯照明线路的安装.ppt

    项目两地控制灯照明线路的安装 两地控制灯照明线路的安装 一.能力目标 二.主要使用材料和工具 主要使用材料和工具见表18-1. 表18-1 主要使用材料和工具 两地控制灯照明线路的安装 三.项目及工艺 ...

  3. led灯光衰怎么解决_什么是LED光衰,光衰怎么解决?

    光衰这个LED行业老生常谈的问题,笔者一直在想怎么能很直观的告诉你们光衰和LED灯珠寿命的的关系呢?最后找到了一个比较好的方法,就是看图说话.提前说下减少光衰的方法就是散热,散热,散热......重要 ...

  4. 单片机led灯闪烁实验总结_新款LED型便携式实验室高强度紫外线灯对比说明

    实验室高强度紫外线灯有传统100W的高压汞灯和新款LED便携紫外灯,主要都用在科研院所.高校生命科学的转基因荧光蛋白筛选和分子材料的光催化反应的应用.另外还有UV固化,食品污染检测,齿科动物污染检查, ...

  5. arm嵌入式led灯闪烁实验报告_嵌入式led灯亮灭实验报告

    实验名称 Led 灯的亮灭 姓名 XXX 学号 XXX 一. 实验目的 通过在 ARM7TDI 实验机上,使 D7~D8 两个灯如下进行亮灭:开始时 D7 灯亮, D8 灯灭:而后 D7 灯灭, D8 ...

  6. led计数电路实验报告_「正点原子FPGA连载」第八章 按键控制LED灯实验

    1)实验平台:正点原子开拓者FPGA开发板 2)本实例源码下载:请移步正点原子官网 第八章 按键控制LED灯实验 按键是常用的一种控制器件.生活中我们可以见到各种形式的按键,由于其结构简单,成本低廉等 ...

  7. led计数电路实验报告_至简设计系列_状态机实现LED交通灯2

    --作者:肖肖肖 本文为明德扬原创及录用文章,转载请注明出处! 1.1 总体设计 1.1.1 概述 发光二极管简称为LED,是一种常用的发光器件,通过电子与空穴复合释放能量发光,可以高效的将电能转化为 ...

  8. 数电实验报告实验一_大二下学期的两三事之数电实验amp;课设

    数电实验&课设 叮 写在前面 这学期的数电实验老师是陈W老师.上学期的模电,选过一次他的课,线下教学,老师讲课游刃自如,点到为止,但又醍醐灌顶:这学期线上教学,可能是软件运用不熟练,他多少有些 ...

  9. led透明屏生产厂家_如何实现LED双面透明显示屏,双面LED透明屏

    市面上我们所常见的LED透明屏一般来说都是单面的,只能单面显示画面,而LED双面透明屏可能相对较少.其实LED双面透明屏显示屏无非就是两块LED透明屏的叠加,前后显示画面,可以向LED透明屏一样,拥有 ...

  10. led灯光衰怎么解决_如何解决LED灯具照明光衰问题

    如何解决 LED 灯具照明光衰问题 ? 作者:亮多美照明科技有限公司 LED 路灯光衰的关键问题在于温度,偏偏 LED 路灯通常又败在这个环节. LED 路灯由于 发光功率大于家用灯具,因此厂商在散热 ...

最新文章

  1. js在post后台接口的时候,一行代码完成删除对象中所有值为null、undefined或为空字符串““的属性
  2. java控制器删除数据_javaWeb删除一条及多条数据
  3. 【Python】matplotlib基础:数据可视化
  4. 数据中心人员短缺,行业仍然充满挑战
  5. arch检验python_Python实现端口检测
  6. RelationTrack解读
  7. restTemplate踩过的坑-spring clound--cloud内部服务调用重试次数
  8. java进阶 2018_Java Web基础入门2018版
  9. java合并单元格同时导出excel
  10. python nonetype报错_python 查询数据库数据 NoneType报错
  11. js定位div坐标存入mysql_JavaScript与Div 对层定位和移动获得坐标
  12. ALEIS,啊,累死
  13. 溯源:通过qq电话获取对方位置
  14. 塞班S60v3版平台手机证书权限内容大解析
  15. Linux 虚拟内存
  16. cahrt框架 ios_iOS-Charts介绍
  17. 创业反鸡汤--3.谈待遇
  18. 电脑耳机拔出后,再插入没声音
  19. Ubuntu 16.04+CUDA8.0+Caffe+OpenCV3.1
  20. 1核2g1m服务器能支持多少人在线访问?

热门文章

  1. 【win10升级】我们无法更新系统保留的分区
  2. c语言表达式判断语法错误题,C语言数据类型与表达式习题及答案.doc
  3. 计算机光驱启动设置,光驱启动怎么设置
  4. php使用加密狗,加密狗使用方法
  5. spring-task
  6. 用html设计logo,终于知道网页logo设计要点
  7. 史上最全的前端资源汇总(上)
  8. Python基础实战之文字游戏——模拟武侠类场景中的两派战斗场面
  9. could not get batchedbridge, make sure your bundle is packaged correctly
  10. 陀螺仪传感器的简单了解