本文为博主 LED-执棋困局,csdn原创首发。希望看完后能对你有所帮助,不足之处请指正!一起交流学习,共同进步!
> 发布人:LED-执棋困局
> 欢迎你为独创博主LED-执棋困局点赞❤❤❤+关注👍+收藏🌹+评论☺。系列专栏:CSDN-单片机学习系列🎁
> 我的格言是:“尽最大努力,做最好的自己!💪
版权声明:本文为CSDN博主「LCD-执棋困局」的原创文章,CSDN独一份。如需转载,还请通知一声噢⚠!
————————————————
版权声明:本文为CSDN博主「LCD-执棋困局」的原创文章,转载请附上原文出处链接及本声明。
本文介绍一些常用基本元件。
目录
一、LED灯
1.1基本理论1
LCD灯由一个二极管组成,通常LED灯一端接地GND/电源,另一端接I/O口(最好接个电阻,以防LED灯烧坏)。二极管一端是阳极,另一端是阴极,所以多个LCD灯接法有两种:共阴极接法和共阳极接法。
共阳极接法,LED灯要导通(发亮),接IO口那端要是低电平(0),另一端接电源。共阴极接法,LCD灯要导通(发亮),接IO口那端要是高电平(1),另一端接地GND。
以8个LED灯为例,采用共阳极接法(IO口接P2),若要让第一个灯亮,则P1^0=0,其他引脚为1,即1111 1110(0xfe)。
1.2流水灯
实现流水灯编码有3种方法,分别是一步步法、数组法、库函数法。
1.2.1一步步法
这个不常用,就是一步一步写出来。简单来说,第一个灯亮,接着第二个灯亮,又接着是第三个灯亮,……,第八个灯亮。
P2=0xfe;
delay(200);
P2=0xfd;
delay(200);
P2=0xfb;
delay(200);
P2=0xf7;
delay(200);
1.2.2数组法
将流水灯二进制存储,利用for语句实现流水灯功能。
unsigned char a[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf 0xbf,0x7f};
while(1)
{
unsigned chari;
for(i=0;i<8;i++)
{
P2=a[i];
delay(200);
}
}
1.2.3库函数法
#include<intrins.h> //含_crol_()和_cror_()函数
while(1)
{
static unsigned char temp;
temp=0xfe;
P2=temp;
temp=_crol_(temp,1); //temp循环左移1位
}
二、数码管
2.1基本理论2
数码管内部由LED和电阻组成,接法可以分为共阳极接法和共阴极接法(接法同上)。数码管线码[abcdefg、dp(用于显示小数)]用于显示字符,位码用于控制显示第几个数码管。数码管线码相当于LED的接IO端,位码相当于LED的公共端。
数码管类型很多,如带:的数码管、带小数点的数码管等。
参考下图(以共阳极接法为例,则线码=1亮,=0不亮),若要显示字符2,则线码abdeg要亮,即:
dp g f e d c b a
0 1 0 1 1 0 1 1 0x5b
数码管显示有四个步骤:
位码→线码→延时1ms→消隐(线码=0)
若要用定时器定时1ms延时,需要将消隐移动到第一步。
另外,可以设置缓冲区,方便显示字符的修改,并定义数组用于存储数码管可以显示的字符。
2.2数码管模块
display.c
#include "display.h"
unsigned char code leddata[]={
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
0x71, //F
0x76, //H
0x38, //L
0x37, //n
0x3E, //u
0x73, //P
0x5C, //o
0x40, //-
0x00 //熄灭
};//数码管段码表
unsigned char LEDBuf[]={8,8,8,8};//缓冲区
unsigned char code PLACE_COOE[]={0xfe,0xfd,0xfb,0xf7};//位码
/******************************************************************************************
函数名:display
功能:数码管显示函数
参数:无
返回值:无
******************************************************************************************/
void display()
{
unsigned char i;
IO_DIG=leddata[LEDBuf[i]];//段码
IO_PLACE=PLACE_COOE[i];//位码
delay(1);//延时1ms
IO_DIG=0x00;//消隐
i++;
if(N==i)
i=0;
}
定时器定时1ms时数码管模块:
#include "display.h"
unsigned char code leddata[]={
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
0x71, //F
0x76, //H
0x38, //L
0x37, //n
0x3E, //u
0x73, //P
0x5C, //o
0x40, //-
0x00 //熄灭
};//数码管段码表
unsigned char LEDBuf[]={0,0,0,0};//缓冲区
unsigned char code PLACE_COOE[]={0xfe,0xfd,0xfb,0xf7};//位码
/******************************************************************************************
函数名:display
功能:数码管显示函数
参数:无
返回值:无
******************************************************************************************/
void display()
{
static unsigned char i=0;
switch(i)
{
case 0:
IO_DIG=0x00;//消隐
IO_DIG=leddata[LEDBuf[0]];//段码
IO_PLACE=PLACE_COOE[0];//位码
i++;
break;
case 1:
IO_DIG=0x00;//消隐
IO_DIG=leddata[LEDBuf[1]];//段码
IO_PLACE=PLACE_COOE[1];//位码
i++;
break;
case 2:
IO_DIG=0x00;//消隐
IO_DIG=leddata[LEDBuf[2]];//段码
IO_PLACE=PLACE_COOE[2];//位码
i++;
break;
case 3:
IO_DIG=0x00;//消隐
IO_DIG=leddata[LEDBuf[3]];//段码
IO_PLACE=PLACE_COOE[3];//位码
i=0;
break;
}
}
/***********************************************************
函数名:Timer0_Init
参 数:无
返回值:无
***********************************************************/
void Timer0_Init(void) //1毫秒@12.000MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
ET0=1; //定时器0中断开关打开
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
void T0_timer() interrupt 1 //实现数码管的动态刷新
{
TR0=0; //暂时关闭定时器T0
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
display(); //数码管显示函数
TR0=1; //再次打开定时器T0
}
display.h
#ifndef __DISPLAY_H__
#define __DISPLAY_H__
#include <reg51.h>
#include "delay.h"
#define IO_DIG P0 //段码IO
#define IO_PLACE P2 //位码IO
#define N 4 //数码管个数
unsigned char code leddata[];//变量声明
extern unsigned char LEDBuf[];
void display();//数码管显示函数声明
#endif
2.3数码管显示服务函数
参考2.2模块,若要显示一个四位数,可以计算出每一位并赋给缓冲区,从而在屏幕中显示这四位数。
unsigned char temp=1234;
dis_service()
{
LEDbuf[0]=temp/1000;
LEDbuf[1]=temp/100%10;
LEDbuf[0]=temp/10%10;
LEDbuf[0]=temp%10;
}
三、按键
3.1基本理论3
按键种类很多,从插入方式,可分为贴片式和插入式。从功能上,可分为一键单义、一键二义、一键多义(一按键多功能)。
按键如何接呢?通常是一端接地,另一端接到IO口。
按键按下时,会有抖动现象,严重影响功能的实现,所以要进行消抖。消抖有两种方法,分别是硬件消抖、软件消抖。硬件消抖外接电路,软件就是利用延时法进行消抖,如下图所示。
3.2按键扫描
如何判断按键按下被按下呢?主要有行列扫描、中断法。
行列扫描,可以分为行扫描、列扫描。行扫描就是键盘一端列接地,逐行进行扫描,当按下按键时,接IO口的另一端连通地,由高电平变成低电平,松开键盘时,断开地,低电平又变回高电平,依据此原理,可以判断出哪个按键被按下,列扫描同理,键盘一端行接地,另一端接IO口。
步骤:(1)判断是否按下(2)延时5ms-10ms(3)再次判断是否按下(4)等待松开
代码如下:
#include "key.h"//独立键盘头文件
#include "delay.h"//延时头文件
/******************************************************************************************
函数名:key
功能: 独立键盘函数
参数: 无
返回值:unsigned char
******************************************************************************************/
unsigned char key()//独立键盘按键函数
{
unsigned char temp=0;
//方法1:
/*if(key1==0)//判断是否按下键盘
{
delay(10);//消抖
if(key1==0)//再次判断是否按下键盘
{
temp=1;//键盘按下,中间值temp赋为1
}while(key1==0);//松手等待
}
if(key2==0)
{
delay(10);
if(key2==0)
{
temp=2;
}while(key2==0);
}
if(key3==0)
{
delay(10);
if(key3==0)
{
temp=3;
}while(key3==0);
}
if(key4==0)
{
delay(10);
if(key4==0)
{
temp=4;
}while(key4==0);
}*/
//方法2:
if(key1==0||key2==0||key3==0||key4==0)
{
delay(10);
if(key1==0||key2==0||key3==0||key4==0)
{
if(key1==0)
temp=1;
if(key2==0)
temp=2;
if(key3==0)
temp=3;
if(key4==0)
temp=4;
}while(key1==0||key2==0||key3==0||key4==0);
}
return temp;//返回中间值
}
3.3线反转法
常见与矩阵键盘。先将行输出(0),列端输入(1),利用按下按键时,一端接地(0),接IO口的另一端(1)连通地,由高电平变成低电平,松开键盘时,断开地,低电平又变回高电平原理,计算出temp,接着行输入(1),列输出(0),再次利用该原理,计算出temp2,最后计算出temp+temp2的结果,这个结果就是这个按键独有的编码。
代码如下:key_scan.c
#include "key_scan.h"//独立键盘头文件
#include "delay.h"//延时头文件
/******************************************************************************************
函数名:key
功能: 独立键盘函数
参数: 无
返回值:unsigned char
******************************************************************************************/
unsigned char key_scan()//独立键盘按键函数
{
unsigned char temp,temp2;
static unsigned char keynum=20;
KEYPIO=0xf0;//1为输入 0位输出 令高4位为1 低4位为0
temp=KEYPIO;
if(temp!=0xf0)//判断是否按下按键
{
delay(10);//消抖延时10ms
if(temp!=0xf0)//再次判断是否按下按键
{
temp=KEYPIO&0xf0;//确定行
KEYPIO=0x0f;//反转
temp2=KEYPIO&0x0f;//确定列
}
}
switch(temp+temp2)
{
case 0xee:keynum=1;break;
case 0xed:keynum=2;break;
case 0xeb:keynum=3;break;
case 0xe7:keynum=4;break;
case 0xde:keynum=5;break;
case 0xdd:keynum=6;break;
case 0xdb:keynum=7;break;
case 0xd7:keynum=8;break;
case 0xbe:keynum=9;break;
case 0xbd:keynum=0;break;
case 0xbb:keynum=10;break;
case 0xb7:keynum=11;break;
case 0x7e:keynum=12;break;
case 0x7d:keynum=13;break;
case 0x7b:keynum=14;break;
case 0x77:keynum=15;break;
default:break;
}
return keynum;
}
key_scan.h
#ifndef __KEY_SCAN_H__
#define __KEY_SCAN_H__
#include <reg51.h>//51头文件
#define KEYPIO P3 //矩阵键盘两端所接的IO口
unsigned char key_scan();//独立键盘函数声明
#endif
3.4中断法
以at89c51单片机为例,有2个外部中断,引脚分别为INT0、INT1。一般初始化时,要打开允许外部中断开关EX0/EX1和总中断EA,同时设置触发方式IT0/IT1,外部中断0的入口编号为0,外部中断1的入库编号为2。
代码如下:
void EX1_init()
{
IT1=1;//下降沿触发
EA=1;//开启总中断
EX1=1;//开启外部中断1
}
void time1() interrupt 2 //中断服务函数--外部中断1
{
switch(P2&0x0f)//判断哪个按键按下
{
case 0x0e:
num++;if(num>9999) num=0;//实现加法运算
break;
case 0x0d:
num--;if(num>9999) num=9999;//实现减法运算
break;
case 0x0b:
num=0;//实现清0
break;
case 0x07:
num=8888;//数码管显示8888
break;
default:break;
}
}
本次学习了单片机三大基本元件,分别介绍了它们的原理和代码解析,下文将继续讲述单片机的知识全集,我们敬请期待!!!
——————————————————————————————————————————
本次介绍了三大元件,同时提供模块代码和原理,帮助大家理解相关编码思路。
hi!我是博主LED-执棋困局🔥,喜欢或期待更好作品的,可以关注一下我LED-执棋困局🙏🙏🙏,我们一起进步,另外欢迎大家的点评😊!!!
关注博主:点击支持——LED-执棋困局
———————————————————————————————————————————