一、GPIO — 通用输入输出

GPIO(General Purpose Input Output)是单片机与外部世界交互的基本通道,每个引脚均可配置为输入或输出模式。

1.1 GPIO 输入模式(检测引脚电平变化)

输入模式

说明

悬空输入

引脚未连接任何上下拉,电平不确定,容易受干扰

上拉输入

通过电阻连接到VCC,默认高电平;按键按下时拉低

下拉输入

通过电阻连接到GND,默认低电平

模拟输入

用于ADC采样,读取模拟电压值

1.2 GPIO 输出模式(给定引脚高电平/低电平,控制引脚输出高电平/低电平)

输出模式

说明

推挽输出

可主动输出高/低电平,驱动能力强

开漏输出

只能拉低,高电平需外部上拉电阻

1.3 检测引脚电平 — 实例

检测 P3_2 是否为低电平(按键是否按下):

// 读取P3第2位

if ((P3 & (1 << 2)) == 0)

{

    // P3_2 为低电平

}

// 位运算示意:

// P3      = 1111 1011

// (1<<2)  = 0000 0100

// 结果    = 0000 0000  → 等于0,说明该位为低

💡 

51单片机的P3口引脚默认为高电平(上拉输入)。检测按键时,按键一端接GND,另一端接P3引脚,按下时引脚被拉低。

二、中断系统

中断是单片机实时响应外部事件的核心机制,避免了CPU不断轮询的资源浪费。

2.1 核心概念

概念

解释

中断

CPU暂停当前任务,转去处理更紧急的事件,处理完后回到原处继续执行

中断源

能够触发中断的事件或硬件信号

中断优先级

多个中断同时请求时,优先处理级别高的

中断嵌套

处理一个中断时,被更高优先级中断再次打断(51最多嵌套2层)

中断向量表

存放各中断服务函数入口地址的数组

中断向量

中断服务函数在向量表中的编号标识

2.2 51单片机的5个中断源

中断源

中断号  interrupt N

外部中断 0(INT0,P3.2引脚)

interrupt 0

定时器 0 溢出中断

interrupt 1

外部中断 1(INT1,P3.3引脚)

interrupt 2

定时器 1 溢出中断

interrupt 3

串口中断(UART)

interrupt 4

2.3 中断处理流程

  1. 中断源发起中断请求
  2. CPU检查中断总开关(EA)及子开关是否打开
  3. 比较中断优先级,决定是否响应
  4. 保护现场(自动压栈保存PC、PSW等寄存器)
  5. 跳转并执行中断服务函数(ISR)
  6. 恢复现场,返回被打断处继续执行

                                                                        图1 中断处理流程

    2.4 外部中断0 — 代码实现

// 外部中断0 初始化

void int0_init(void)

{

    P3 |= (1 << 2);      // P3.2 拉高(上拉输入,等待下降沿)

    IE  |= (1 << 7);     // EA=1  打开CPU中断总开关

    IE  |= (1 << 0);     // EX0=1 打开外部中断0子开关

    TCON |= (1 << 0);    // IT0=1 设置为下降沿触发

}



// 外部中断0 服务函数(下降沿触发一次,g_n自增)

void int0_handler(void)  interrupt 0

{

    g_n++;

}

⚠️ 注意

中断服务函数不能有参数和返回值,函数名后必须加 interrupt N(N为中断号)。TCON寄存器的IE0位由硬件在响应后自动清零。

三、定时器

定时器用于产生精准时间间隔,对PWM、通信时序等时间敏感任务至关重要。

3.1 定时器原理

  • 51单片机有 Timer0 和 Timer1,均为 16位自增计数器(0 ~ 65535)
  • 从初值开始向上计数,溢出(超过65535归0)后向CPU发起中断请求
  • 计数速率 = 晶振频率 ÷ 12(机器周期)

3.2 定时器计算公式(晶振 11.0592MHz)

工作频率

11.0592 MHz ÷ 12

0.9216 MHz

每次计数时间

1 ÷ 0.9216 MHz

≈ 1.085 μs

1ms定时计数次数

1000μs ÷ 1.085μs

≈ 922

1ms定时初值

65535 - 922

64613

例1:

              

3.3 关键寄存器

寄存器 / 位

作用

TH0 / TL0

定时器0高8位/低8位初值,溢出后需重新装载

TMOD bit0

设置Timer0工作模式(1 = 16位定时器)

TCON TR0 (bit4)

置1启动Timer0开始计数

IE EA (bit7)

CPU中断总开关,必须置1才能响应任何中断

IE ET0 (bit1)

允许Timer0产生中断

3.4 工作模式2 — 8位自动重装

  • 实际计数只用 TL0(0~255),溢出后自动把 TH0 的值重新装入 TL0
  • 优点:无需在中断服务函数中手动重装初值,精度更高

3.5 定时器0 初始化代码

void timer0_init(void)

{

    TMOD &= ~(0x0F << 0);  // 清除低4位

    TMOD |= (1 << 0);      // 设置16位定时器模式(M0=1)

    TH0 = g_i >> 8;        // 装入初值高8位

    TL0 = g_i;             // 装入初值低8位

    TCON |= (1 << 4);      // TR0=1 启动定时器

    IE |= (1 << 7);        // EA=1  总中断开关

    IE |= (1 << 1);        // ET0=1 允许Timer0中断

}



// 定时器0 中断服务函数

void timer0_handler(void)  interrupt 1

{

    TH0 = g_i >> 8;        // 重装初值(防止误差累积)

    TL0 = g_i;

    P2 ^= (1 << 5);        // 翻转P2.5引脚(产生方波)

}

四、PWM — 脉冲宽度调制

PWM(Pulse Width Modulation)通过控制方波的高/低电平时间比,实现对亮度、速度、音调等的调节。

PWM 参数

定义

PWM 周期

一个完整方波所经历的时间(从一个上升沿到下一个上升沿)

PWM 占空比

高电平时间 ÷ 周期 × 100%

频率

1 ÷ 周期,单位 Hz

🔑 关键

占空比决定平均电压。LED: 占空比50% → 半亮;电机: 占空比越大转速越高。51单片机通过定时器中断翻转引脚电平来软件模拟PWM。

五、蜂鸣器

5.1 两种蜂鸣器对比

类型

特点

有源蜂鸣器

内置震荡源,通电即持续发出固定频率声音,控制简单

无源蜂鸣器

无内置震荡源,需外部提供PWM方波驱动,可改变音调

5.2 蜂鸣器音调计算(200Hz 为例)

周期

1 ÷ 200Hz

0.005s = 5ms

半周期(定时时间)

5ms ÷ 2

0.0025s = 2.5ms

计数次数

2.5ms ÷ 1.085μs

≈ 2304

定时器初值

65535 - 2304

63231

5.3 常用频率初值对照

频率 (Hz)

定时器初值(宏定义)

200 Hz

HZ_200 = 63231

400 Hz

HZ_400 = 64382

600 Hz

HZ_600 = 64767

800 Hz

HZ_800 = 64959

六、综合示例:按键控制蜂鸣器音调

本示例通过4个按键选择不同频率,驱动无源蜂鸣器发出不同音调。

6.1 按键检测 — key.c

void key_init(void)

{

    P3 |= (0x0F << 0);  // P3.0~P3.3 设为高电平(上拉输入)

}



int key_press(void)

{

    if ((P3 & (1 << 1)) == 0) return 1;  // KEY1: P3.1低 → 按下

    if ((P3 & (1 << 0)) == 0) return 2;  // KEY2: P3.0低 → 按下

    if ((P3 & (1 << 2)) == 0) return 3;  // KEY3: P3.2低 → 按下

    if ((P3 & (1 << 3)) == 0) return 4;  // KEY4: P3.3低 → 按下

    return 0;

}

6.2 主程序 — main.c

#define HZ_200  63231
#define HZ_400  64382
#define HZ_600  64767
#define HZ_800  64959

int main(void)

{

    timer0_init();

    key_init();

    while (1)

    {

        int ret = key_press();

        if      (ret == 1) g_i = HZ_200;  // 低音

        else if (ret == 2) g_i = HZ_400;

        else if (ret == 3) g_i = HZ_600;

        else if (ret == 4) g_i = HZ_800;  // 高音

        else               g_i = 0;        // 无按键,停止发声

    }

}

 工作原理

g_i 是全局变量,在定时器中断中用于重装初值。g_i越大,定时时间越短,翻转越快,频率越高,音调越高。g_i=0时不重装初值,定时器停止产生规律方波,蜂鸣器停止发声。

七、LED 驱动 — led.c 补充

void led_all_on(void)  { P2 = 0x00; }     // 全亮(低电平有效)

void led_all_off(void) { P2 = 0xFF; }     // 全灭

// 点亮第n个LED(其余熄灭)

void led_on(unsigned char n) { P2 = ~(1 << n); }

// 所有LED取反(全亮变全灭,全灭变全亮)

void led_nor(void) { P2 = P2 ^ 0xFF; }

八、关键寄存器速查表

寄存器

功能描述

P0 ~ P3

4组通用I/O口(8位),可读可写,操控外设引脚

IE(中断允许)

bit7=EA总开关;bit0=EX0;bit1=ET0;bit2=EX1;bit3=ET1;bit4=ES

TCON(定时/中断控制)

TR0(bit4)=启动Timer0;TR1(bit6)=启动Timer1;IT0(bit0)=INT0触发方式

TMOD(定时器工作模式)

低4位控制Timer0,高4位控制Timer1;bit0置1=16位定时器模式

TH0 / TL0

Timer0高8位/低8位计数寄存器

TH1 / TL1

Timer1高8位/低8位计数寄存器

附录:

一,TCON — 定时器/中断控制寄存器

地址:88H    可位寻址(每个bit可以单独用位地址操作)

作用:控制 Timer0 / Timer1 的启停,以及外部中断 INT0 / INT1 的触发方式和请求标志。

B7

B6

B5

B4

B3

B2

B1

B0

TF1

TR1

TF0

TR0

IE1

IT1

IE0

IT0

名称

功能说明

B7  TF1

TF1

Timer1 溢出标志位。Timer1 计数溢出时由硬件自动置1,CPU 响应中断后自动清0。也可软件清0。

B6  TR1

TR1

Timer1 运行控制位。置1 → 启动 Timer1 开始计数;清0 → 停止 Timer1。 操作:TCON |= (1 << 6)  启动 / TCON &= ~(1 << 6)  停止

B5  TF0

TF0

Timer0 溢出标志位。Timer0 计数溢出时由硬件自动置1,CPU 响应中断后自动清0。也可软件清0。

B4  TR0

TR0

Timer0 运行控制位。置1 → 启动 Timer0 开始计数;清0 → 停止 Timer0。 操作:TCON |= (1 << 4)  启动 / TCON &= ~(1 << 4)  停止

B3  IE1

IE1

外部中断1(INT1,P3.3)请求标志。检测到触发信号后由硬件置1,CPU 响应后自动清0。

B2  IT1

IT1

外部中断1 触发方式。IT1=0:低电平触发;IT1=1:下降沿触发(推荐,不会误触发)。 操作:TCON |= (1 << 2)  设置下降沿触发

B1  IE0

IE0

外部中断0(INT0,P3.2)请求标志。检测到触发信号后由硬件置1,CPU 响应后自动清0。

B0  IT0

IT0

外部中断0 触发方式。IT0=0:低电平触发;IT0=1:下降沿触发(推荐)。 操作:TCON |= (1 << 0)  设置下降沿触发

⚠️ 注意

TCON 可位寻址,也可用位运算直接操作整个字节。TF0/TF1/IE0/IE1 均由硬件自动置1、自动清0,不需要手动操作。TR0/TR1/IT0/IT1 需要手动配置。

二、TMOD — 定时器工作模式寄存器

地址:89H    不可位寻址(只能整字节操作,不能单独访问某一位)

作用:设置 Timer0 / Timer1 的工作模式(16位/8位/自动重装等)。

B7

B6

B5

B4

B3

B2

B1

B0

GATE

C/T

M1

M0

GATE

C/T

M1

M0

高4位控制 Timer1 →          低4位控制 Timer0 →

名称

功能说明

B7 / B3  GATE

GATE

门控位。GATE=0(常用):只要 TR0/TR1 置1,定时器就启动。GATE=1(少用):需同时满足 TR0/TR1=1 且 INT0/INT1 引脚为高电平,定时器才启动(用于测量脉冲宽度)。

B6 / B2  C/T

C/T

功能选择位。C/T=0:定时器模式(对内部机器周期计数,用于定时)。C/T=1:计数器模式(对外部引脚T0/T1的脉冲计数,用于测量外部事件次数)。

B5 / B1  M1

M1

工作模式高位(与M0组合选择模式,见下表)

B4 / B0  M0

M0

工作模式低位(与M1组合选择模式,见下表)

M1 M0 工作模式选择

M1

M0

模式

说明

0

0

模式0 — 13位定时器

由TH(高8位)+ TL(低5位)组成13位计数器,兼容老式8048,很少用

0

1

模式1 — 16位定时器 ★

TH(高8位)+ TL(低8位)组成16位计数器,范围0~65535,最常用!溢出后需手动重装初值

1

0

模式2 — 8位自动重装 ★

只有TL(0~255)参与计数,溢出后自动把TH的值重新装入TL,无需中断里手动重装,适合波特率发生器/PWM

1

1

模式3 — 分裂为两个8位

仅Timer0支持:TL0独立作8位定时器,TH0也独立作8位定时器,较少使用

三、IE — 中断允许寄存器(顺带整理)

地址:A8H    可位寻址

B7

B6

B5

B4

B3

B2

B1

B0

EA

ET2

ES

ET1

EX1

ET0

EX0

名称

功能说明

B7  EA

EA

中断总开关。EA=1 → 允许CPU响应所有中断(还需各子开关打开);EA=0 → 关闭所有中断,无论子开关状态。操作:IE |= (1 << 7)

B6  —

保留

该位保留,无实际功能,读取值为0。

B5  ET2

ET2

Timer2 中断允许位(STC89C52 有 Timer2)。ET2=1 允许 Timer2 中断。

B4  ES

ES

串口(UART)中断允许位。ES=1 允许串口中断。操作:IE |= (1 << 4)

B3  ET1

ET1

Timer1 中断允许位。ET1=1 允许 Timer1 溢出中断。操作:IE |= (1 << 3)

B2  EX1

EX1

外部中断1(INT1,P3.3)允许位。EX1=1 允许外部中断1。操作:IE |= (1 << 2)

B1  ET0

ET0

Timer0 中断允许位。ET0=1 允许 Timer0 溢出中断。操作:IE |= (1 << 1)

B0  EX0

EX0

外部中断0(INT0,P3.2)允许位。EX0=1 允许外部中断0。操作:IE |= (1 << 0)

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐