前言
本人首次参加蓝桥杯单片机组比赛,利用寒假时间备赛,在此以笔记的方式记录自己每天的备赛过程。争取写满20篇(2/20)。
比赛大纲:通知详情 --- 全国大学生TMT行业赛事 (lanqiao.cn)
知识点大纲:通知详情 --- 全国大学生TMT行业赛事 (lanqiao.cn)
比赛赛规:通知详情 --- 全国大学生TMT行业赛事 (lanqiao.cn)
本期关键词:锁存器,译码器,模块化编程
引入
大家可能经常会看到电子专业的同学调侃自己为"点灯工程师",也经常能听到"点个灯先"、"能点灯就是胜利"等用语。其实呢,学习单片机的第一步通常是学习"点灯",也就是学习LED模块。有一定数模电基础的同学肯定知道,LED灯实际上就是发光二极管,二极管导通就会发出亮光。学习LED,我们就不能只学习LED,我们还要学习与其相关的锁存器,译码器等模块。
锁存器
这里以M74HC573M1R锁存器为例。
RS锁存器
-
RS锁存器电路图如下所示
-
真值表如下所示:
-
R端是0端,S端是1端;R表示Reset(复位),S表示Set(置位)。
-
RS锁存器有一个最主要的特点:R和S不能同时为1。
D锁存器
- D锁存器电路图如下图所示:
- D锁存器在RS锁存器的基础上添加了两个与门,巧妙地避免了RS锁存器同时为1的情况。
- D锁存器的E(EN)端是使能端,当EN=0时,锁存器的输出状态保持不变(原来是什么就还是什么);当EN=1时,锁存器的输出受D控制,当D=0时,Q=0;当D=1时,Q=1。
M74HC573M1R锁存器
- 原理图如下图所示:
- 从图中可以看出,一个锁存器控制了8个LED灯。
- 观察HC573锁存器的内部结构,如下图所示:(原理图是D1-D8,内部结构示意图是D0-D7,这个只是编号问题,不影响后续编程,编程以D0-D7为基础。)
- HC573锁存器主要由8个D锁存器构成,其中LE就是锁存器中的使能端。当LE=1时,LE'=0,锁存器使能。(LE'就是LE取反的意思,和图中LE上方加一条横线的表示含义一致。)
- OE'通常接地,HC573锁存器通过LE来选择锁存器的锁存与使用状态。
- 以D0为例,当D0=0时,Q0=0;当D0=1时,Q0=1。这种现象也称作"透明传输"。意思就是说,输入为0时,输出还是为0,虽然中间经过了很多步骤(与门、或非门等),但是结果还是和最初的输入一致,就好像中间的步骤透明了一样,对结果不产生影响。
- 仔细观察HC573的原理图我们会发现,LE引脚受Y4C的控制,查看单片机原理图,我们可以发现:
(J13默认WR与GND短接。)Y4C主要受Y4控制。而Y4则受74HC138译码器控制。
译码器
以74HC138译码器为例。
-
74HC138译码器原理图如下图所示:
-
内部电路图如下图所示:
-
译码器真值表如下图所示:
-
正常工作状态下,G1为高电平H,G2'为低电平L。
-
这里需要特别注意顺序:从左到右为C-B-A,Y0-Y7
-
示例:当CBA对应的值为100时,Y4输出为低电平,此时Y4C输出为高电平,则LE为高电平,锁存器使能。若此时D0=0,其他为1,则Q0=0,其他输出为1,此时仅LED1灯亮。
编程
准备工作
- 创建好需要的文件夹:
Driver
、Sys
。 - 创建好所需文件,并添加到相应文件夹,如下图所示:
- 在魔术棒的C51选项处,添加我们创建的.c、.h文件所在的路径:
- 尝试编译,这时没报错,但是会有警告,但问题不大
代码编写
- main.c代码编写
c
# include "bsp_init.h"
# include "bsp_led.h"
# include "delay.h"
void main()
{
unsigned char i,j;//为循环变量做准备
Cls_Peripheral();//关闭外设
while(1)
{
for(i=0;i<9;i++)//控制亮度等级
{
for(j=0;j<50;j++)//控制当前亮度等级的循环次数
{
Led_Disp(0xff);//全亮
Delay(i+1);//亮的时间
Led_Disp(0x00);//全灭
Delay(9-i);//灭的时间
}
}
}
}
- bsp_init.c代码编写
c
# include "bsp_init.h"
//函数名:关闭外设的初始化函数
//入口参数:无
//返回值:无
//函数功能:将LED、和外设全部关闭
void Cls_Peripheral(void)
{
P0 = 0x00;//将外设全都关闭的数据准备(外设关闭对应的输入为全0)
P2 = P2 & 0x1F | 0xA0; //选通Y5,也就是外设的锁存器,将数据透传过去
P2 &= 0x1F; //将打开的锁存器关闭
P0 = 0xFF;//将LED全都关闭的数据准备(LED灯关闭对应的输入为全1)
P2 = P2 & 0x1F | 0x80; //选通Y4,也就是LED的锁存器,将数据透传过去
P2 &= 0x1F; //将打开的锁存器关闭
//此时P27-P25均为0,按照真值表,Y0是输出为低电平的,但是我们的单片机没有使用Y0,所以可以认为当P27-P25均为0时,所有锁存器关闭。
}
- bsp_init.h代码编写
c
# include "STC15F2K60S2.H"
void Cls_Peripheral(void);
- bsp_led.c代码编写
c
# include "bsp_led.h"
//函数名:LED显示函数
//入口参数:要显示数值的十六进制数据,例如0XAA=1010 1010,L8~L1的顺序
//返回值:无
//函数功能:按照入口参数顺序将LED点亮,1为亮,0为灭
//这里需要特别注意:按照原理图,实际上是0为亮,1为灭。这里编写代码我们对ucLed进行了逐位取反
void Led_Disp(unsigned char ucLed)
{
P0 = ~ucLed;//将输入数据取反,做好数据准备,1为亮,0为灭。
P2 = P2 & 0x1F | 0x80; // 0x80,选通Y4,也就是LED的锁存器,将数据透传过去
P2 &= 0x1F; //将打开的锁存器关闭,使任何一个锁存器都不打开
}
- bsp_led.h代码编写
c
# include "STC15F2K60S2.H"
void Led_Disp(unsigned char ucLed);
- delay.c代码编写
c
# include "delay.h"
//函数名:延时毫秒函数
//入口参数:延时的数值,2个字节,16位,0---65535
//返回值:无
//函数功能:延时一定的毫秒数据
void Delay(unsigned int num)
{
unsigned int i;
while(num--)
// i的最大值和单片机的工作频率有关
for(i=0; i<628; i++);
}
- delay.h代码编写
c
// 不需要包含其他头文件
void Delay(unsigned int num);