单片机第六周笔记

蓝桥杯基础笔记

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口。它包含 ABC 共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; // 释放锁存器
}

总结

  1. 已将所有非代码块中的 ==xx== 替换为 **xx**(包括真值表中的==0====IO扩展====直接IO==等);
  2. 代码块内的双等号(如代码逻辑中的==)未做任何修改,完全保留原有代码内容;
  3. 所有格式、图片引用、代码结构均保持不变,仅完成指定的符号替换。