目录
注意:一定要注意自己单片机的晶振周期,千万别无脑选12MHz,像下面这个单片机的主人,用12MHz调试了五个小时,没发现问题所在
一.矩阵键盘
1.使用原理:
与独立按键类型相似,通过快速扫描矩阵键盘来读取所按按键,每次扫描逐行或者逐列。
P1接口采用弱上拉的模式,若为0则按下.
2.原理图:
3.代码段(矩阵键盘密码锁):
1.读取矩阵键盘:
/**
* @brief 读取矩阵按键,范围1~16
* @param 无
* @retval 所读矩阵按键,范围1~16
*/
unsigned char MatrixKey()
{
unsigned char KeyNum;
//本次采用逐列扫描
P1=0xff;
P1_3=0;//令P1_3=0,开始第一列扫描,若按键在第一列则读出
if(P1_7==0){while(P1_7==0);KeyNum=1;}//若在P1_7则为按键1
if(P1_6==0){while(P1_6==0);KeyNum=5;}//若在P1_6则为按键5
if(P1_5==0){while(P1_5==0);KeyNum=9;}//若在P1_5则为按键9
if(P1_4==0){while(P1_4==0);KeyNum=13;}//若在P1_4则为按键13
//以此类推,下面都是重复的
P1=0xff;
P1_2=0;
if(P1_7==0){while(P1_7==0);KeyNum=2;}
if(P1_6==0){while(P1_6==0);KeyNum=6;}
if(P1_5==0){while(P1_5==0);KeyNum=10;}
if(P1_4==0){while(P1_4==0);KeyNum=14;}
P1=0xff;
P1_1=0;
if(P1_7==0){while(P1_7==0);KeyNum=3;}
if(P1_6==0){while(P1_6==0);KeyNum=7;}
if(P1_5==0){while(P1_5==0);KeyNum=11;}
if(P1_4==0){while(P1_4==0);KeyNum=15;}
P1=0xff;
P1_0=0;
if(P1_7==0){while(P1_7==0);KeyNum=4;}
if(P1_6==0){while(P1_6==0);KeyNum=8;}
if(P1_5==0){while(P1_5==0);KeyNum=12;}
if(P1_4==0){while(P1_4==0);KeyNum=16;}
return KeyNum;
}
2. 矩阵键盘密码锁:
unsigned int Password=0,Count=0,RightP=5414;
unsigned char KeyNum;
void main ()
{
LCD_Init();
LCD_ShowString(1,1,"Password:");
LCD_ShowNum(2,1,0,4);
while (1)
{
KeyNum=MatrixKey();
if(KeyNum)
{
LCD_ShowString(1,13," ");
if(KeyNum<=10)//如果S1~S10按下,输入密码
{
if(Count<4)//unsigned int类型范围是0~65535所以输入的数字不能超过65535
{
Password *=10; //密码左移一位
Password +=KeyNum%10; //获取一位密码
Count++; //如果次数小于4,计次加一
}
LCD_ShowNum(2,1,Password,4); //更新显示
}
if(KeyNum==11) //如果按下S11,确认
{
if(Password==RightP) //若密码正确则输出PASS
{
LCD_ShowString(1,13,"PASS");
Password=0;
Count=0;
LCD_ShowNum(2,1,Password,4); //更新显示
}
else //若密码错误则输出err
{
LCD_ShowString(1,13," err");
Password=0;
Count=0;
LCD_ShowNum(2,1,Password,4); //更新显示
}
}
if(KeyNum==12) //若按下S12则重新输入密码
{
Password=0;
Count=0;
LCD_ShowNum(2,1,Password,4); //更新显示
}
}
}
}
二.定时器
1.介绍:
定时器是单片机内部资源,其电路的连接和运转均在单片机内部完成。
2.作用:
1.可用于计时系统,实现软件计时,或使程序每隔一段时间完成一项操作
2.替代长时间的Delay,提高CPU的运行效率和处理速度。
3.个数:
一般有三个定时器(T0,T1,T2),T2是新增的定时器,T0和T1的操作方式是所有51单片机共有的。注意:可能有例外 如下图只有T0和T2两种操作方式
4.原理:
时钟提供计数单元的时钟脉冲,每次脉冲都使计数单元加一,当达到设定的计数时,计数单元会向中断系统发送中断请求,从而使程序跳转到中断服务函数中执行。
5.工作模式:
1.一般只用模式1,其他模式很少用(本内容也只讲模式1)
2.模式1的原理图+解释:
1.TH和TL的解释:TH是高字节,TL是低字节,0代表是定时器0,总共能存65535个数。每来一次脉冲,计数+1,当达到最高65535时,会产生溢出,TL和TH会归0,同时给出标志TF0,有TF0则产生中断。
2.SYSclk的解释:SYSclk:系统时钟,即晶振周期,本开发板上的晶振周期为12MHz.
若连接➗12线路,则是12分频,输出频率是1MHz,大约一微秒。
3.C/T的解释:若配置为1则是C模式(conter)即计时器,若配置为0则是T模式(timer)即定时器。
6.中断系统
1.51单片机中断源个数:
2.中断系统的内部结构:
7.定时器相关寄存器
1.寄存器的解释:
1.寄存器是连接软硬件的媒介。
2.在单片机中寄存器就是一段特殊的RAM存储器,一方面,寄存器可以存储和读取数据,另一方面,每一个寄存器背后都连接了一根导线,控制着电路的连接方式。
3.寄存器相当于一个“复杂机器”的操作按钮。
2.TCON寄存器:
各位的解释:
3.TMOD寄存器:
各位的解释:
8.配置定时器:
1.在STC软件中选择定时器计算器模块
2.选择适合的定时器模式,需要添加允许中断代码。注意AUXR是最新单片机的模式,本单片机没有,需要删除
3.最终代码如下:
/**
* @brief 定时器0初始化,1毫秒@12.000MHz
* @param 无
* @retval 无
*/
void Timer0_Init(void) //1毫秒@12.000MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1; //允许中断
EA=1; //允许总中断
PT0=0; //中断优先级等于0,低优先级
}
9.中断函数
1.中断函数在中断系统中第一点中断号中有给出
2.中断函数模板(代码段):
void Timer0_Rountine() interrupt 1 //定时器0的中断函数,时间为1秒
{
static unsigned char T0Count;//静态变量,可以保证函数结束T0Count不被销毁
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
T0Count++;
if(T0Count>=1000)
{
T0Count=0;
}
}
10.定时器控制LED流水线
定时器代码段:
void Timer0_Rountine() interrupt 1
{
static unsigned int T0Count=0;
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
T0Count++;
if(T0Count>=300)//每0.3秒移位
{
T0Count=0;
if(l==1)
// 在#include <INTRINS.H>头文件里面的_crol_和_cror_两个函数
// 其作用是让0x??向左或向右移n位,特点是循环
P2=_crol_(P2,1);
else
P2=_cror_(P2,1);
}
}
主函数代码段:
void main ()
{
unsigned char l=0,k=0;
P2=~0x80;//开始时让第一位亮
Timer0_Init();//定时器初始化
while (1)
{
k=Key();//获取独立按键键位
if(k)
{
if(k==1)
{
l++;
if(l>1) l=0;
}
}
}
}
11.定时器时钟
代码段:
unsigned char sec=0,mun=0,hour=0;
void main ()
{
LCD_Init();
Timer0_Init();
LCD_ShowString(1,1,"CLOCK:");
while (1)
{
LCD_ShowNum(2,1,hour,2);
LCD_ShowString(2,3,":");
LCD_ShowNum(2,4,mun,2);
LCD_ShowString(2,6,":");
LCD_ShowNum(2,7,sec,2);
}
}
//中断函数
void Timer0_Rountine() interrupt 1
{
static unsigned int T0Count=0;
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
T0Count++;
if(T0Count>=1000)
{
T0Count=0;
sec++;
if(sec>=60)
{
sec=0;
mun++;
if(mun>=60)
{
mun=0;
hour++;
if(hour>=24)
{
hour=0;
}
}
}
}
}
三.串口
1.硬件电路
1.TXD是发送端,RXD是接收端,要交叉连接。
2.当电平不一样时,需要加电平转换芯片。
2.接口以及引脚的定义
1.常见通信接口
3.51单片机的UART
1.UART
4.串口参数及时序图
1.波特率:串口通信的速率(发送和接收各数据位的间隔时间)
2.检验位:用于数据验证
3.停止位:用于数据帧间隔
5.串口模式图
SBUF:串口数据缓存寄存器,物理上是两个独立的寄存器,但占用相同的地址。写操作时,写入的是发送寄存器,读操作时,读出的是接收寄存器。
6.串口和中断系统原理图
7.串行口相关寄存器
· SCON:串行控制寄存器(可位寻址)
· PCON:电源控制寄存器(不可位寻址)
8.电脑通过串口控制LED
注意:一定要注意自己单片机的晶振周期,千万别无脑选12MHz,像下面这个单片机的主人,用12MHz调试了五个小时,没发现问题所在
代码段(全):
1.串口初始化
/**
* @brief 串口初始化
* @param 无
* @retval 无
*/
void UartInit() //4800bps@11.0592MHz
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xFA; //设置定时初始值
TH1 = 0xFA; //设置定时重载值
ET1 = 0; //禁止定时器%d中断
TR1 = 1; //定时器1开始计时
EA=1; //接口中断
ES=1; //使能中断
}
2.串口接收模板
/*串口接收模板
void URATRoutine() interrupt 4
{
if(RI==1)
{
RI=0;//RI需要靠软件回零
}
}
*/
3.主函数以及中断函数,需使用interrupt 4(在定时器,中断系统第一点有给)
void main ()
{
UartInit();
while(1)
{
}
}
void URATRoutine() interrupt 4
{
if(RI==1)
{
P2=~SBUF;
UartSendByte(SBUF);
RI=0;
}
}
四.LED点阵屏
1.LED点阵屏介绍:
1.点阵屏类似与数码管,只不过是数码管把每一列的像素以“8”字型排列而已
2.LED点阵屏与数码管一样,有共阴和共阳两种接法,不同的接法对应的电路结构不同
3.LED点阵屏需要进行逐行或逐列扫描,才能使所有LED同时显示
2.上原理图
如上图所示,每列可通过P0来控制亮灭,每一行需要用74HC595来控制。
此模块采用弱上拉模式,0即亮。
3.74HC595
1.74HC595介绍:
74HC595是串行输入并行输出的移位寄存器,可用3根线输入串行数据,8根线输出并行数据,多片级联后,可输出16位、24位、32位等,常用于IO口扩展。
使用规则:
串行输入:每位数从SER输入,即最高位,时钟SERCLK每来一个上升沿,寄存器会一位一位往下移(每次上升沿结束需要将SERCLK清零)
并行输出:输入完成后需要给RCLK高电平,寄存器的数全部输出给Q
QH‘:是下一片的移位寄存器,每次溢出的数会传递给QH’
RCLK:只要给RCLK一个上升沿,寄存器中的数就会输出
2.上原理图
3.sfr和sbit的作用:
sfr:特殊功能寄存器声明。例:sfr P0=0x80;
sbit:特殊位声明。例:sbit p0_1=P0^1;或sbit P0_1=0x81; 声明P0寄存器的第1位。
3.上代码
1.74HC595中的代码
用sbit声明P3_5,P3_6,P3_4的别称
定义P0的别称为MATEIXLED
#include <REGX52.H>
#include "Delay.h"
sbit RCK=P3^5;//RCLK
sbit SCK=P3^6;//SRCLK
sbit SER=P3^4;//SER
#define MATRIXLED P0
/**
* @brief 初始化74HC595
* @param 无
* @retval 无
*/
void _74HC595_Init()
{
SCK=0;//初始时SCK是高电平,需要调为低电平
RCK=0;//初始时RCK是高电平,需要调为低电平
}
/**
* @brief 向74HC595写入一个字节
* @param Byte 写入的字节
* @retval 无
*/
void _74HC595_WriteByte(unsigned char Byte)
{
unsigned char i;
for(i=0;i<8;i++)
{
SER=Byte&(0x80>>i); //给寄存器各位上填数字1或0
SCK=1;//给高电平,来一个上升沿
SCK=0;//给低电平,为下一次上升沿做准备
}
RCK=1;//给RCK上升沿就能使寄存器中的数输出
RCK=0;
}
/*
* @brief LED点阵屏显示一列数据
* @param Colum是所选列
* @param Data是所选亮的LED
* @retval 无
*/
void MatrixLED(unsigned char Column,Data)
{
_74HC595_WriteByte(Data);
MATRIXLED=~(0x80>>Column);
Delay(1);//同数码管一样需要进行消影
MATRIXLED=0xff;
}
2.主函数中的代码
#include <REGX52.H>
#include "74HC595.h"
#include "Timer0.h"
unsigned char NB[]={
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xC3,0xC3,0xFF,0xFF,0xFF,0xC3,0xC3,0x00,
0x00,0x30,0x78,0xCC,0xC6,0x63,0x33,0x63,
0xC6,0xCC,0x78,0x30,0x00,0x00,0x00,0xC0,
0xE0,0x70,0x3F,0x3F,0x3F,0x70,0xE0,0xC0,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
unsigned char i,offset;
void main ()
{
Timer0_Init();//配置定时器
_74HC595_Init();
while (1)
{
for(i=0;i<8;i++)
{
MatrixLED( i,NB[i+offset]);
}
}
}
void Timer0_Rountine() interrupt 1 //定时器0的中断函数
{
static unsigned int T0Count;//静态变量,可以保证函数结束T0Count不被销毁
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
T0Count++;
if(T0Count>=500)
{
T0Count=0;
offset++;
if(offset>38) offset=0;
}
}