嵌入式开发学习笔记9-做一个好玩的LED闪烁

嵌入式开发学习笔记9-做一个好玩的LED闪烁

  • 前言
  • 实际操作
    • 程序功能
    • 实现思路
    • 程序源码
    • 实现效果展示

前言

LED小灯闪烁实质是控制单片机上的I/O口,通过向I/O口循环输入高低电平,从而控制LED小灯的亮灭。但由于单片机的机器周期一般为12/11059200 s,而人眼一般不能识别这种快速转换,因此我们还需要利用定时器实现延时,降低到人眼可识别的闪烁效果,从而实现LED灯闪烁,这就是LED小灯闪烁的基本原理。

实际操作

程序功能

我们需要实现的功能的就是让LED小灯1 s闪烁一次,并且数码管依次显示数字,闪烁10次后打开蜂鸣器报警
在这里面我们主要要用到P1口、定时器0和外部中断1,整体的实现架构如下

实现思路

单片机开发板上的小灯接入了C51上的P1口,因此需要对P1口进行控制,可利用16进制数实现8个LED小灯的控制,此处为了简便,直接实现全亮和全灭,全亮对应16进制为0xFF,对其进行取反即为全灭,循环该过程则实现LED小灯的闪烁。

由于人眼的暂留效果,我们还需要采用定时器对其进行延迟,定时器能定时的最大机器周期为65536,约为71ms,虽然可能能够让我们看到LED闪烁,但是LED闪烁太快,因此我们需要使用多次循环进行扩展。此处为便于计算,选取定时器定时事件为50ms,对应机器周期为46080,因此定时器初值应为19456,对应十六进制为0x4BFD。

基于上述数据,采用函数来封装定时器初始化过程,定时器初始化主要分为三个步骤:
1、定时器工作模式的设置,设置其工作模式为第二种方式,即TMOD=0x01;
2、定时器初始值的设置,设置TH0=0x4B,TL0=0xFD
3、打开定时器,设定TR0=1
由此完成定时器0的设定,在对其进行循环20次,然后再实现对P1口取反,即可实现LED小灯1s闪烁一次,此处需要注意,由于没有使用内部中断T0,因此在定时器溢出后用软件将TF0置0,然后重新设定初值

实现上述功能后,本来任务应该完成了,但是我想着使用一下中断来熟悉一下,因此采用了外部中断1来实现另一个功能:10次闪烁后实现蜂鸣器报警。
实现外部中断的套路和实现定时器的套路差不多:
1、打开中断总开关EA
2、打开外部中断开关EX1
3、设定触发方式,此处设为下降沿触发方式,即IT1=1
由此完成外部中断1的设置,然后在设定外部中断1的服务程序,即满足触发条件后需进入中断执行服务程序,即打开蜂鸣器,循环一次后再关闭(或者可以实现延时一段时间后关闭),此处需要注意的是,在单片机开发板上需要连接P37口与P33口,然后在P3^7口产生一个下降沿来触发中断。
我在里面还加上了一个数码管显示函数,实现方式基本差不多,但是需要你去了解一下数码管的显示原理,此处不再详细说了,之后有时间再开一篇博客来谈谈电路问题

程序源码

#include

sbit DU = P2^6;//段选锁存器
sbit WE = P2^7;//位选锁存器
sbit beep = P2^3;//蜂鸣器
sbit flag = P3^7;//产生下降沿控制进入中断


//数码管位置地址	 加code存放在R0M区,在执行过程中不会被更改
code unsigned char location[]={
0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F};
//数码管显示内容
code unsigned char nums[]={
//0     1     2     3     4    5     6      7     8    9    
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 
//A     b     C     d     E    F     G      H     L     N    -
0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71 ,0x76, 0x38, 0x37, 0x3E, 0x40 };

//外部中断1初始化
void INIT1()
{
   EA = 1; //开总中断
   EX1 = 1; //开外部中断1
   IT1 = 1;	//外部中断1下降沿触发
}

//外部中断1服务程序
//如果进入中断,蜂鸣器交替工作
void int1() interrupt 2
{
	beep = ~beep;
}

//定时器初始化
void TimerInit()
{
	TMOD = 0x01; // 设置定时器工作模式
	TH0 = 0x4B;	//(65536-46082) / 256;
	TL0 = 0xFD; //(65536-46082) % 256; 定时50ms
	TR0 = 1; //打开定时器
}

//数码管显示定时器计数时间
//locationInfo--选择显示的数码管位置,从1开始
//numInfo--选择显示的数字,默认显示为0
void Display(unsigned char locationInfo,unsigned char numInfo)
{
	P0 = 0xFF;//清除断码,单片机处理效果较快,肉眼可能还会混合在上一个P口的值
	 
	WE = 1; //打开位选锁存器
	P0 = location[locationInfo-1]; //打开数码管 1111 1110
	WE = 0; //锁存数据,不受IO口影响
	
	DU = 1; //打开段选锁存器
	P0 = nums[numInfo]; //显示数据 0000 0110
	DU = 0;	
}

void main()
{
	unsigned char msec,sec = 0;//毫秒和秒存储变量
	TimerInit();
	P1 = 0x00; //LED亮
	while(1)//10s一个循环
	{
	    if(TF0 == 1)//定时器溢出标志
		{
		 	TF0 = 0;//定时器溢出标志位清零
			TH0 = 0x4B;	//
	        TL0 = 0xFD;
		 	msec++; //50ms到
			if(msec == 20)//1s到
			{
			 	msec = 0;
				P1 = ~P1;//实现LED灯闪烁
				Display(2,sec);//默认第二个数码管显示
				sec++;//1s时间到		
			}
		}
		if(sec == 10) 
		{
		 	sec = 0;
			INIT1();//外部中断1初始化
			flag = 1;//进入中断
			flag = 0;//通过P3^7下降沿变化传送到P3^3口--单片机上需要有线连接
		}
	}	
}

实现效果展示

嵌入式开发学习笔记9-做一个好玩的LED闪烁_第1张图片
嵌入式开发学习笔记9-做一个好玩的LED闪烁_第2张图片

------------------------以上内容由作者原创,欢迎转载,有疑问下方留言----------------------------------

你可能感兴趣的:(嵌入式开发学习)