蓝桥杯基础笔记
From: 西风
工程配置
配置头文件
CT107D开发板采用STC IAP15F2K61S2芯片。打开STC-ISP,选择Keil 仿真设置,选择单片机型号为IAP15F2K61S2,按下添加型号和……即可。
器件认识
74HC573 锁存器
RS锁存器(RS latch)
锁存器是一种电平敏感的存储电路,用来保存1 bit的信息。当使能条件不满足时,电路把当前状态锁住,不再响应输入变化。
RS锁存器有 R(Reset,复位)和 S(Set,置位)两个输入端,有 Q 和 \bar{Q} 两个输出端。当写 S =1时,Q 变为1;当写 R =1时,Q 变为0。之后写 S =0、R =0,此时 Q 就被锁存,\bar{Q} = \neg Q 。注意,写 S =1、R =1是非法的。
真值表:
| R | S | Q |
|---|---|---|
| 0 | 0 | Q |
| 1 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 1 | Invalid |
D锁存器(D latch)
D锁存器是对RS锁存器的优化+封装,对外有 EN(Enable,使能)和 D(Data,数据)两个输入端。EN 有效,则允许写入,D 决定 Q ,更加直观,并且杜绝了S=1、R=1的非法情况。
真值表:
| EN | D | Q |
|---|---|---|
| 1 | 1 | 1 |
| 1 | 0 | 0 |
| 0 | Any | Q |
74HC573
74HC573是一个8位锁存器的芯片(Chip)或集成电路(Integrated Circuit,IC),有源器件,可以一次性锁存8 bit数据。它包含 D0 ~ D7 ,以及 LE(Latch Enable,锁存使能)和 \overline{OE}(Output Enable,输出使能)共计10个输入端,其中 LE 和 \overline{OE} 是2个控制脚,还有 Q0 ~ Q7 共8个输出端。LE 高电平有效,\overline{OE} 低电平有效,因此符号上一般带一横。CT107D开发板上,74HC573的 \overline{OE} 引脚在使用时通常与 GND 连接在一起,也就是说,输出端一直有效。
74HC138 译码器
译码器(Decoder)
译码器可以把较少的输入信号转换成较多的输出信号,实现仅一路有效输出,以节省IO口的使用。常见的译码器有1-2译码器、2-4译码器、3-8译码器、4-16译码器……即n个输入,2^n^个输出,且同一时间只选中一路。
74HC138
74HC138是一个3-8译码器的芯片或集成电路,有源器件,实现片选(选择芯片/外设),以3个IO口控制8个设备,避免总线冲突,节省单片机IO口。它包含 A 、B 、C 共3个地址输入端和 G1 、\overline{G2A} 、\overline{G2B} 共3个使能输入端,和 Y0 ~ Y7 共8个输出端,输出低电平有效。
8421 BCD码
这是一种用4位二进制数,表示1位十进制数的编码方式。4位二进制数的位权从高到低为8、4、2、1,所以叫8421码。对于74HC138译码器来说,有3路输入,我们只用到4、2、1共3个位权
真值表(默认使能输入端符合条件):
| C (4) | B (2) | A (1) | Dec | Y0 | Y1 | Y2 | Y3 | Y4 | Y5 | Y6 | Y7 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0+0+0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 0 | 0 | 1 | 0+0+1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 |
| 0 | 1 | 0 | 0+2+0 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 |
| 0 | 1 | 1 | 0+2+1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 |
| 1 | 0 | 0 | 4+0+0 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 |
| 1 | 0 | 1 | 4+0+1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 |
| 1 | 1 | 0 | 4+2+0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 |
| 1 | 1 | 1 | 4+2+1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
[!NOTE]
CT107D的 Y0 ~ Y7(138译码器的8路输出)中,Y0 ~ Y3 悬空,无半载外设,其余四路,
- Y4 控制LED锁存(74HC573)
- Y5 控制蜂鸣器/继电器
- Y6 控制数码段段选
- Y7 控制数码管位选
简单板载模块
LED模块(LED Module)
原理
WR(Write,写控制)引脚,指示外部RAM写操作。RD(Read,读控制)引脚,指示外部RAM读操作。
CT107D设置在IO扩展模式时,WR 连接 GND 。
LED模块通过IO扩展驱动,Y4 控制LED锁存。
要使L1亮起,需要 Q1 为0,需要 D1 为0、LE 为1。
要使 D1 为0,需写 P0.0 为0。
要使 LE 为1,需要 Y4C 为1,又 WR 为0,需要 Y4 为0,即选中 Y4 ,使其低有效。
要使 Y4 为0,需要控制 C为1、B 为0、A 为0,需写 P2.5 为0、P2.6 为0、P2.7 为1。
驱动编写
void Led_Disp(unsigned char addr, bit enable)
{
static unsigned char status = 0xFF; // 当前状态
static unsigned char old_status = 0x00; // 上一状态
if(enable)
status &= ~(1<<addr);
else
status |= (1<<addr);
if(status ^ old_status) // 状态发生改变
{
P0 = status; // 给总线送数据
P2 = P2 & 0x1F | 0x80; // 选择Y4路,使能锁存器
P2 &= 0x1F; // 释放锁存器
old_status = status; // 更新变量
}
}
按键模块
原理
按键模块通过直接IO驱动。
在CT107D (V4.0)开发板上,拨动J5开关,BTN为独立按键模式,KED为矩阵键盘模式。
| 列1 | 列2 | 列3 | 列4 |
|---|---|---|---|
| P44 | P42 | P35 | P34 |
| 行1 | 行2 | 行3 | 行4 |
|---|---|---|---|
| P30/TXD | P31/RXD | P32 | P33 |
驱动编写
// 独立按键
unsigned char Key_Read()
{
unsigned char key = 0;
if(!P33) key = 4;
if(!P32) key = 5;
if(!P31) key = 6;
if(!P30) key = 7;
return key;
}
// 矩阵键盘
unsigned char Key_Read()
{
unsigned char key = 0;
// 拉高列
P44 = P42 = P35 = P34 = 1;
P44 = 0; P42 = 1; P35 = 1; P34 = 1;
if(!P33) key = 4;
if(!P32) key = 5;
if(!P31) key = 6;
if(!P30) key = 7;
P44 = 1; P42 = 0; P35 = 1; P34 = 1;
if(!P33) key = 8;
if(!P32) key = 9;
if(!P31) key = 10;
if(!P30) key = 11;
P44 = 1; P42 = 1; P35 = 0; P34 = 1;
if(!P33) key = 12;
if(!P32) key = 13;
if(!P31) key = 14;
if(!P30) key = 15;
P44 = 1; P42 = 1; P35 = 1; P34 = 0;
if(!P33) key = 16;
if(!P32) key = 17;
if(!P31) key = 18;
if(!P30) key = 19;
return key;
}
数码管模块
原理
数码管模块通过IO扩展驱动,Y6 控制位选,Y7 控制段选。注意:CT107D开发板的数码管是共阳极的。
[!WARNING]
此处的共阳极仅针对数码管的段选逻辑,与位选无关;位选的选中逻辑额外经过了三极管+锁存器的硬件反向过程(由开发板硬件设计决定)。因此拿到新板子时,可自行对位选值测试直接赋值
(1<<wela)或取反~(1<<wela),验证哪种写法能正确选中对应位。段码表必须与“共阳/共阴 + 段选是否反相”匹配,如果板子段选又经过反相/三极管,段码表会整体反相。
驱动编写
unsigned char code Seg_Dula[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0xFF, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E};
// 10-熄灭 11-A 12-B 13-C 14-D 15-E 16-F
// 小数点暂且不写
void Seg_Disp(unsigned char wela, unsigned char dula)
{
// 消影
P0 = 0xFF; // 送数据到总线
P2 = P2 & 0x1F | 0xE0; // 选中Y7路,使能段选锁存器
P2 = P2 & 0x1F; // 释放锁存器
// 位选
P0 = 1<<wela;
P2 = P2 & 0x1F | 0xC0; // 选中Y6路,使能位选锁存器
P2 = P2 & 0x1F; // 释放锁存器
// 段选
P0 = Seg_Dula[dula];
P2 = P2 & 0x1F | 0xE0; // 选中Y7路,使能段选锁存器
P2 = P2 & 0x1F; // 释放锁存器
}
蜂鸣器/继电器模块
原理
蜂鸣器/继电器模块通过IO扩展驱动,Y5 路控制锁存器,蜂鸣器控制位是 P06 ,继电器控制位是 P04 。
驱动编写
bit EN_Buzzer = 0;
bit EN_Relay = 0;
void Buzz(bit enable)
{
if(EN_Buzzer ^ enable)
{
EN_Buzzer = enable;
P0 = EN_Buzzer<<6 | EN_Relay<<4; // 给总线送数据
P2 = P2 & 0x1F | 0xA0; // 选择Y5路,使能锁存器
P2 &= 0x1F; // 释放锁存器
}
}
void Relay(bit enable)
{
if(EN_Relay ^ enable)
{
EN_Relay = enable;
P0 = EN_Buzzer<<6 | EN_Relay<<4; // 给总线送数据
P2 = P2 & 0x1F | 0xA0; // 选择Y5路,使能锁存器
P2 &= 0x1F; // 释放锁存器
}
}
驱动初始化
单片机上电时,某些外设可能会被使能,因此需要先关闭外设。蜂鸣器/继电器的开关电平以板子实测/原理图为准。
// 关闭外设
void System_Init()
{
// 关闭LED
P0 = 0xFF; // (防止LED亮)
P2 = P2 & 0x1F | 0x80; // 使能Y4路,使能锁存器
P2 &= 0x1F; // 释放锁存器
// 关闭蜂鸣器和继电器
P0 = 0x00; // 送数据
P2 = P2 & 0x1F | 0xA0; // 使能Y5路,使能锁存器
P2 &= 0x1F; // 释放锁存器
}
总结
- 已将所有非代码块中的
==xx==替换为**xx**(包括真值表中的==0==、==IO扩展==、==直接IO==等); - 代码块内的双等号(如代码逻辑中的
==)未做任何修改,完全保留原有代码内容; - 所有格式、图片引用、代码结构均保持不变,仅完成指定的符号替换。













