资讯详情

学习单片机开发——浅尝点灯的快乐

点灯

    • 前言
    • 开始点灯
      • 基本点灯
        • 查看原理图
        • 正常点灯
      • 花式点灯
        • 位选存器
        • 段选锁存器
      • 按键交互
    • 总结

前言

因为刚开始学51单片机,同学推荐后选择了清翔单片机,芯片;

视频链接如下

https://www.bilibili.com/video/BV1nt411f7To?p=35&spm_id_from=pageDriver&vd_source=352cf5eb0220bc4e9ed73c26dc3d8be1 

单片机的重点是**“点灯”**,其实高低电平是通过我们的程序(多用C语言)变化,拉高/拉低(1/0)。

开始点灯

基本点灯

点灯,我必须明白(一般情况,外设元件有一段连接单片机芯片,另一端的连接情况要查看电路原理图)

查看原理图

顾名思义,原理图是指电路板上各设备之间连接原理的图表。通过分析电路原理图,了解各种电子设备的功能和工作原理,学习单片机和硬件电路设计。

查看原理图最重要的是

在这里插入图片描述

网络标号的优点是

正常点灯

学习单片机点灯,首先是点亮第一个LED灯,很简单,(我用清翔原理图),参考原理图

因为LED灯是连接的,需要低电平(把P1^0 只有降低),电路才能导通。

sbit LED1 = P1^0; void main() //主函数 { 
          LED1 = 0;//点亮P1.0上的LED  } 

当然,点灯的方法不止一种。

sbit LED1 = P1^0; void main() //主函数 { 
          LED1 = ~LED1;;//点亮P1.0上的LED  } 

点亮LED灯后,我们可以试着让LED闪烁。

sbit LED1 = P1^0; void delay(int n)///延迟函数 { 
          unsigned int x,y;  for(x = n;x >= 0;x--)   for(y = 114;y >= 0; y--); } 
       
        void 
        main
        (
        ) 
        //主函数 
        { 
          LED1 
        = 
        0
        ;
        //点亮P1.0上的LED 
        delay
        (
        50
        )
        ;
        //软件延时  LED1 
        = 
        1
        ;
        //熄灭P1^0上的LED  
        ) 
       

清翔的单片机上有8个LED灯,我们可以通过运用尝试流水灯的设计了。

#include<reg52.h>
#include<intrins.h>
void delay(uint z)
{ 
        
	uint x,y;
	for(x = z; x > 0; x--)
		for(y = 114; y > 0 ; y--); 	//晶振11.0592us
} 

void main ()
{ 
        
    LED = 0xFE;//1111 1110 初值LED1亮
    P1 = LED;
	delay(100);//毫秒级延时 100毫秒
    while(1)
    { 
        
      LED = _crol_(LED,1);//循环左移,需要预定义intrins
      P1 = LED;//移位完成后赋值给P1 每个一个灯点亮
      delay(100);//毫秒级延时 100毫秒
    }
}

至此最基本的的点灯就是这样,其中注意,因为单片机上用了8个LED灯,8个LED灯分别连接在89c52芯片中P1口的P10~P17;所以我们可以直接通过8位2进制(或者0x_2位16进制)同时让LED灯直接点亮,这既是

明白了并行传输我们就可以搞一搞——点亮数码管

花式点灯

点亮数码管之前,我们需要了解一下数码管锁存器(我用的是清翔单片机外设锁存器)。

  • OE: Output Enable 输出使能端
  • LE: Latch Enable 锁存器使能端
  • D 0 ~ D 7:数据的输入引脚
  • Q 0~Q 7:数据的输出引脚
  • GND:地线接地端
  • VCC:供电电压

位选锁存器

位选,顾名思义,就是多位数码管的位置选择;通信方式是并行通信,并行通信就是8位一次性传输。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-itUikTcs-1655610173187)(C:/Users/ali126174/AppData/Roaming/Typora/typora-user-images/image-20220617173704194.png)]

而锁存器就是通过一个“开关”,将我们需要的数据传输给数码管,让数码管选择好他应该点亮的位置;这个“开关”就是,在位选中就是

sbit WE = P2^7;
void main()
{ 
        
    WE = 1;	 //打开U8锁存端
    P0 = 0xF4;	 //送入位选信号 0xfe为16进制表示方法,转换 为二进制为1111 0100
   WE = 0;	 //关闭U8锁存端
}

注意:WE位选锁存器打开后,一定要锁存就是给WE赋0,因为如果不锁存WE的话,位选锁存器在段选值赋入的时候就被更改了,这也是锁存器最大的功能——锁存。

段选锁存器

当我们找到我们点亮的位置后,我们开始点亮数码管,但是点亮数码管之前,我们应该先清楚数码管的原理和结构;

(左)8段数码管排布图 (右)数码管原理图

我们通过排布图可以看出有七个段和一个点,分别对应的8位2进制(2进制很重要!!),所以我只需要从A到G,dp,从低到高的点灯就可以了。点灯,我们就需要判断怎样让电路导通,

由此我们从原理图中可以看到有两种数码管,分别是。共阴极就是把八条二极管线路的阴极共同接地,共阳极就是把八条二极管线路的阳极共同接VCC,所以共阴极拉高(赋1)导通,共阳极拉低(赋0)导通,STC89C52开发板是共阴极的,所以

下面为共阴极数码码表:

0x3F 0
0x06 1
0x5b 2
0x4f 3
0x66 4
0x6d 5
0x7d 6
0x07 7
0x7f 8
0x6f 9
0x77 A
0x7c b
0x39 C
0x5e d
0x79 E
ox71 F
ox76 H
ox38 L
ox40 -
ox00 熄灭

STC89C52开发板上所用的是2个四位的数码管,在其内部公共端是独立的,独立的公共端可以用来控制哪一位数码管点亮,段线是连接在一起的,用来负责显示什么数字,我们常常把公共端叫做"位选线",连接在一起的线叫做"段选线"。

sbit WE = P2^7;//定义位选
sbit DU = P2^6;//定义段选
void main()
{ 
        
    WE = 1;	 //打开位选锁存端
    P0 = 0x80;	 //送入位选信号 0xfe为16进制表示方法,转换二进制为1000 0000
   WE = 0;	 //关闭位选锁存端
   
   DU = 1;//打开段选锁存器
   P0 = 0x06;//送入段选信号0x06, 0000 0110 显示一个“1” 
   DU = 0;//关闭段选锁存器
}

就此我们就点亮了第一个位置的第一个数码管,点亮为“1”。

后续我们可以拓展一些我们想要的变式:

  • 数码管动态显示
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int 

sbit  DU = P2^6;//数码管段选
sbit  WE = P2^7;//数码管位选

uchar temp;

//共阴极数码管段选表0~9
uchar code table[] = { 
        0X3F ,0X06 , 0X5B , 0X4F , 0X66 , 0X6D , 0X7D ,  0X07 , 0X7F , 0X6F };

void delay(uint z)//定义毫秒级的延时函数
{ 
        
		uint  x,y;
		for(x = z ; z > 0 ; z-- )
				for( y = 114 ; y > 0 ; y--);
}

void display(uint i)//定义一个千位的数码显示函数
{ 
        
	uint	thr ,hur ,ser ,num;
	thr = i / 1000;
	hur = i % 1000 /100;
	ser = i % 1000 % 100 / 10;
	num = i % 10;
	
	
		//第一位数码管
		P0 = 0xFF;//清除段码
		WE = 1;//打开位选锁存器
		P0 = 0xFE;//1111 1110
		WE = 0; //锁存位选数据
		
		DU = 1;//打开段选锁存器
		P0  =table[thr];
		DU = 0;//锁存段选数据
		delay(5);
	
		//第二位数码管
		P0 = 0xFF;//清除段码
		WE = 1;//打开位选锁存器
		P0 = 0xFD;//1111 1101
		WE = 0; //锁存位选数据
		
		DU = 1;//打开段选锁存器
		P0  =table[hur];
		DU = 0;//锁存段选数据
		delay(5);
		
		//第三位数码管
		P0 = 0xFF;//清除段码
		WE = 1;//打开位选锁存器
		P0 = 0xFB;//1111 1011
		WE = 0; //锁存位选数据
		
		DU = 1;//打开段选锁存器
		P0  =table[ser];
		DU = 0;//锁存段选数据
		delay(5);
		
		//第四位数码管
		P0 = 0xFF;//清除段码
		WE = 1;//打开位选锁存器
		P0 = 0xF7;//1111 0111
		WE = 0; //锁存位选数据
		
		DU = 1;//打开段选锁存器
		P0  =table[num];//0101 1011
		DU = 0;//锁存段选数据
		delay(5);
}

void main()
{ 
        
	
	while(1)
	{ 
        
		display(1261);
	}
}

点亮这个数码管后,有没有发现这些“点灯”,都是直接点灯,没有间接,也不交互,所以我们不让他与我们交互一下,这就有了——独立按键/矩阵按键

按键交互

独立按键/矩阵按是一种0/1式的"scanner",按键其实也是一个“开关”,但不是直接将电源拉低,让电路停止的“电源开关”,他像一个“阀门”,控制“0”/“1”(电路的拉高和拉低),但是注意

按键产生的不是理想的所以存在**“按键抖动”延时函数delay**解决,让上一个动作再延长一点,再执行下一个动作。

自此我们就可以通过在按键闭合为高时,其他的外设功能应该输出一个什么情况;按键松开为低时,其他的外设功能应该输出一个什么情况。

独立按键

要弄清楚独立按键按下去的时候,按键被拉低的,因为有一端共同接地所以,当)为0时(按下拉低时),电路导通,功能实现。

#include<intris.h>
#define uchar unsigned char
#define uint unsigned int 

sbit  DU = P2^6;//数码管段选
sbit  WE = P2^7;//数码管位选
sbit  key_s2 = P3^0;//定义独立按键S2
sbit  key_s3 = P3^1;//定义独立按键S3
sbit  beep = P2^3; //定义蜂鸣器

uchar led;
uchar temp;
uchar  sum;

//共阴极数码管段选表0~9
uchar code table[] = { 
        0X3F ,0X06 , 0X5B , 0X4F , 0X66 , 0X6D , 0X7D ,  0X07 , 0X7F , 0X6F };

void delay(uint z)//定义毫秒级的延时函数
{ 
        
		uint  x,y;
		for(x = z ; z > 0 ; z-- )
				for( y = 114 ; y > 0 ; y--);
} 
void main()
{ 
         

	sum = 0;
	WE = 1;//打开位选锁存器
	P0 = 0XFE;//1111 1110
	WE  =0;//锁存位选数据
	
    led = 0xFE;
	P1 = led;
 delay(150);

	while(1)
{ 
        	
		led = _crol_(led ,1);//循环左移函数
		P1 = led ;
		delay(150);
	
	if(key_s2 == 0){ 
        
			delay(40);//按键抖动
			if(key_s2 == 0)
				{ 
        
					
					if(sum != 9)
							 sum++;
							DU = 1;//打开段选锁存器
							P0 = table[sum];
							DU = 0;//锁存段选数据 
			
						while(!key_s2);//松手检测
				}
				beep = 0;//外加蜂鸣器
				delay(100);
				beep = 1;
	}
	if(key_s3 == 0 ){ 
        
		delay(40);//按键抖动
		if(key_s3 == 0)
				{ 
        
					if(sum > 0)
						sum--; 
					DU = 1;//打开段选锁存器
					P0 = table[sum];
					DU = 0;//锁存段选数据 
			
					while(!key_s3);//松手检测
				}
				beep = 0;
				delay(100);
				beep = 1;
	}
	
	
	DU = 1;//打开段选锁存器
	P0 = table[sum];
	DU = 0;//锁存段选数据 
			
}

矩阵按键

矩阵键盘一共有4行和4列,共16个键;我们可以采用。列扫描时先把接在列上面的所有IO口拉高,接在行上的所有IO置低。当其中有一列内任何一个按键按下那么整条列线都会被拉低。

当我们采用列扫描时,我们先将P34P37拉高,P30P33拉低,即是P3 = 0xf0(1111 0000);如果这时候有按键按下,那么P3^4~ P3^7 就有一个会变成低电平。因此P3的值就不等于0xf0,按下按键所在的列就会变成低电平,这是就可以判断有按键按下。

然后我们进行行扫描,将P34P37拉低,P3033拉高,P3 = 0x0f,按下按键,P30~P33其中一行就会被拉低;最后我们将行扫描和列扫描的值相加就得出我们需要得某行某列的数值。

S1 S2 S3 S4
0xEE 0xDE 0xBE 0x7E
S5 S6 S7 S8
0XED 0xDD 0xBD 0x7D
S9 S10 S11 S12
0XEB 0xDB 0xBB 0x7B
S13 S14 S15 S16
0XE7 0xD7 0xB7 0x77

void scan()
{ 
        //4x4矩阵按键扫描
	//列扫描
	P3 = 0xF0;
	if(P3 != 0xF0){ 
        
		
	
			delay(10);//防抖动
			if(P3 != 0xF0){ 
        
					switch(P3){ 
        
						case 0xE0: num = 0; break;
						case 0xD0: num = 1; break;
						case 0xB0: num = 2; break;
						case 0x70: num = 3; break;
					}
			}
	P3 = 0X0F;//行扫描
			if(P3 != 0x0F){ 
        
					switch(P3){ 
        
						case 0x0E: num = num + 0;break;
						case 0x0D: num = num + 4;break;
						case 0x0B: num = num + 8;break;
						case 0x07: num = num + 12;break;
					}
					
			}
			while(P3 !=0x0F);//松手检测
			
			
			beep = 0;
			delay(100);
			beep = 1;
	}
}

总结一下,矩阵按键,当按下那个按键时,他两端的为高电平的端被拉低,故**“两端为低”**,例如S15键,将他按下后,两端拉低,P35和P32为0;

故P3 = 0xDB(1101 1011)就是S15的数值。

同理于独立按键,我们将P3口全部拉高,独立按键的值就是这几个来;

S2 0xFE
S3 0xFD
S4 0xFB
S5 0xF7

最后我们将他们在数码管上显示出来

#include <reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char

//共阴极数码管段选表: 
uchar code table[] = { 
        
//0 1 2 3 4 5 6 7 8 9 A
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,
//B C D E F H L N u - 熄灭
0x7C,0x39,0x5E,0x79,0x71,0x76,0x38,0x54,0x3E,0x40,0x00};

sbit WE = P2^7;//位
sbit DU = P2^6;//段
sbit beep = P2^3;//蜂鸣器

uchar num = 20;//定义一个按键值

void delay(uint z)//定义毫秒级的延时函数
{ 
        
		uint  x,y;
		for(x = z ; z > 0 ; z-- )
				for( y = 114 ; y > 0 ; y--);
}

void scan()
{ 
        //4x4矩阵按键扫描
	//列扫描
	P3 = 0xF0;
	if(P3 != 0xF0){ 
        
		
	
			delay(10);//防抖动
			if(P3 != 0xF0){ 
        
					switch(P3){ 
        
						case 0xE0: num = 0; break;
						case 0xD0: num = 1; break;
						case 0xB0: num = 2; break;
						case 0x70: num = 3; break;
					}
			}
	P3 = 0X0F;//行扫描
			if(P3 != 0x0F){ 
        
					switch(P3){ 
        
						case 0x0E: num = num + 0;break;
						case 0x0D: num = num + 4;break;
						case 0x0B: num = num + 8;break;
						case 0x07: num = num + 12;break;
					}
					
			}
			while(P3 !=0x0F);//松手检测
			
			
			beep = 0;
			delay(100);
			beep = 1;
	}
	//独立按键扫描
	P3 = 0XFF;
			if(P3 != 0xFF
        标签: 二极管s5连接器s10b

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台