单片机代码烧录
028.0.2 单片机代码烧录
#include "reg52.h"
#include <intrins.h>
sbit LED1 = P1^0;
sbit LED2 = P1^1;
sbit LED3 = P1^2;
sbit LED4 = P1^3;
void Delay1000ms() //@11.0592MHz
{
unsigned char data i, j, k;
_nop_();
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
while(1)
{
LED1 = 0;
LED2 = 1;
LED3 = 1;
LED4 = 1;
Delay1000ms();
LED1 = 1;
LED2 = 0;
LED3 = 1;
LED4 = 1;
Delay1000ms();
LED1 = 1;
LED2 = 1;
LED3 = 0;
LED4 = 1;
Delay1000ms();
LED1 = 1;
LED2 = 1;
LED3 = 1;
LED4 = 0;
Delay1000ms();
}
}
一、从源码到单片机运行的完整流程
- 本节完成的工作可以概括为:
main.c源码 → Keil 编译和链接 →mcu51.hex→ AIapp-ISP 下载 → STC89C52 单片机运行。 - C 源码不能直接写入单片机。Keil C51 先把源码编译、链接为目标程序,再输出 Intel HEX 格式的
.hex文件;烧写工具读取该文件,并通过串口把程序写入单片机的 Flash。 - 本节使用的配套源码位于
2、51单片机部分/2、51单片机教学篇/代码/0template/main.c,完整代码列在主标题下方。 - 本节的电路分析依据课程配套的 51开发板电路.pdf。阅读原理图时,不要按元件在纸面上的远近判断连接关系;应沿导线和同名网络标号追踪电源、地及信号。
二、新建并组织 Keil 工程
2.1 建立文件夹层级
- 先建立一个总的“代码”文件夹,用于保存后续所有课程工程。每个独立实验再使用一个子文件夹,避免不同工程的源文件、配置和编译产物互相混杂。
- 本节把第一个工程作为模板工程,子文件夹命名为
0template;后续可以按照学习顺序建立 LED、中断、定时器、串口等不同工程目录。 - 工程名称可以自定义,视频中使用
mcu51。一个清晰的目录结构示例如下:
代码/
└─ 0template/
├─ mcu51.uvproj
├─ main.c
├─ STARTUP.A51
└─ Objects/
└─ mcu51.hex
2.2 创建工程
- 启动 Keil μVision5,选择
Project → New μVision Project。 - 进入总的代码目录,在其中新建并打开
0template文件夹。 - 输入工程名
mcu51,单击“保存”。Keil 会把工程文件保存在当前子文件夹中。 - 创建其他实验工程时,应为每个工程建立自己的子文件夹,不要把所有工程直接保存在同一目录。
三、选择目标器件并添加 C 文件
3.1 选择 AT89C52
- 在器件选择窗口中展开厂商
Atmel。 - 找到并选择
AT89C52,然后单击OK。 - Keil 询问是否把标准 8051 启动代码复制并加入工程时,选择“是”,工程中会出现
STARTUP.A51。
- 开发板实际使用的是 STC89C52RC/LE52RC 系列芯片,而 Keil 工程选择 AT89C52,是因为本节只使用标准 8051/52 内核兼容的寄存器和指令,AT89C52 的 C51 设备定义可以满足编译需要。
- Keil 中的目标器件选择与烧写工具中的实际芯片选择含义不同:Keil 负责决定编译环境和寄存器定义;烧写时必须选择开发板上的真实芯片型号。若后续使用 STC 芯片特有外设,应改用与实际芯片匹配的头文件和配置,不能始终假定所有型号完全相同。
- 只有启动文件的空工程在构建时可能出现警告。此时工程还没有
main入口和用户代码,添加main.c后再重新检查构建结果。
3.2 添加 main.c
- 在工程树中右键单击
Source Group 1。 - 选择
Add New Item to Group 'Source Group 1'。 - 文件类型选择
C File (.c),名称输入main.c,再单击Add。 - 将本节提供的模板源码粘贴到
main.c中并保存。
- 本工程使用的 C 源文件名是
main.c,它位于 Keil 工程的Source Group 1中。 - 复制整段模板代码时,可以在原代码文档中按
Ctrl+A全选、按Ctrl+C复制,再切换到 Keil 的main.c按Ctrl+V粘贴。
四、理解流水灯源码
4.1 头文件与引脚定义
#include "reg52.h"提供 8051/52 系列的特殊功能寄存器定义,例如程序中使用的端口寄存器P1。#include <intrins.h>提供 Keil C51 的内部函数,本程序中的_nop_()表示执行一条空操作指令。sbit LED1 = P1^0;等语句把 LED1~LED4 分别映射到 P1.0~P1.3。sbit和P1^0是 Keil C51 针对 8051 位寻址功能提供的扩展语法,不是通用标准 C 的写法。
4.2 低电平点亮
- 根据课程开发板的 LED 接线,端口输出低电平
0时 LED 点亮,输出高电平1时 LED 熄灭,这称为“低电平有效”。 - 第一组赋值令
LED1 = 0、其余 LED 为1,因此只点亮 LED1;后面三组依次只点亮 LED2、LED3 和 LED4。 - 原理图中的四路 LED 完全相同:LED1~LED4 的阳极接
+5V,阴极分别经过 R8~R11(均为10 kΩ)连接到 P1.0~P1.3。以 LED1 为例,电流路径如下:
正向电流方向
───────►
+5V ──────── LED1 ───── R8 10 kΩ ───── P1.0(单片机引脚)
│
引脚输出 0 时
│
GND
-
当
P1.0 = 0时,引脚电压接近 0 V,形成+5V → LED1 → R8 → P1.0 → GND的闭合回路,单片机引脚以“灌电流”的方式吸收电流,因此 LED1 点亮。 -
当
P1.0 = 1时,引脚电压接近电源电压,LED 两端缺少足够的正向压差,回路中几乎没有电流,因此 LED1 熄灭。这就是代码中“写 0 反而点亮”的电路原因。 -
R8 是限流电阻,用于保护 LED 和单片机 I/O 口。它画在 LED 后面还是前面不影响作用,只要与 LED 串联,流过二者的电流就相同。忽略引脚低电平残余电压时,电流可近似计算为:
I_LED ≈ (5V - V_F) / 10kΩ蓝色 LED 的正向压降
V_F通常约为 2.8~3.2 V,因此本板 LED 电流大约为 0.18~0.22 mA。该电流较小,适合作为状态指示,也减轻了单片机端口的负担。 -
P1.0~P1.3 与四路 LED 的对应关系是一一固定的。软件中的
sbit只是给物理引脚起了更容易理解的名字,并不会改变电路连接。
4.3 延时与循环
Delay1000ms()是按 11.0592 MHz 晶振频率生成的软件延时函数,调用一次约延时 1000 ms,也就是 1 秒。若晶振频率或编译器优化设置发生变化,实际延时时间也可能变化。main()是单片机 C 程序进入用户逻辑后的主函数。Keil C51 接受源码中的void main()写法。while(1)构成无限循环,使 LED1~LED4 按顺序反复点亮,最终形成循环流水灯效果,而不是执行一遍后停止。- 原理图中的时钟电路由晶振 X1(
11.0592 MHz)和两个22 pF负载电容 C9、C10 构成:
X1 11.0592 MHz
单片机 XTAL2 ───────────[ 晶振 ]─────────── XTAL1 单片机
│ │
C9 22 pF C10 22 pF
│ │
GND GND
- 晶振与单片机内部振荡放大电路共同产生稳定时钟。CPU 执行指令、定时器计数和软件延时都以该时钟为时间基准,所以
Delay1000ms()的循环次数必须与 11.0592 MHz 相匹配。 - 11.0592 MHz 还便于分频得到常见串口波特率,能够降低波特率误差。后续学习串口通信时,这个晶振频率会再次发挥作用。
- 如果把开发板换成其他晶振频率而不重新计算延时,函数名称虽然仍叫
Delay1000ms(),实际延时却不再等于 1 秒;这说明函数名是人的约定,真正决定时间的是时钟频率和执行的指令周期数。
五、编译工程并检查结果
5.1 编译
- 保存
main.c后,可以使用工具栏的 Build 或 Rebuild 按钮构建工程。Build 主要编译发生变化的文件,Rebuild 会重新编译整个目标;对于本节的小工程,两者都能得到最终结果。 - 在底部
Build Output窗口查看结果:0 Error(s), 0 Warning(s)表示本次构建没有错误和警告。 - 出现
Error表示编译或链接失败,必须根据错误位置修正;出现Warning时程序有时仍能生成,但也应理解原因并尽量消除,不能只看是否生成了文件。 - Build Output 区域太小时,可以向上拖动窗口边界,方便查看完整信息。
5.2 生成 HEX 文件
- 单击工具栏中的“魔术棒”按钮,打开
Options for Target 'Target 1'。 - 切换到
Output选项卡。 - 勾选
Create HEX File,单击OK保存配置。 - 重新 Build 或 Rebuild 工程,Keil 才会按照新配置生成 HEX 文件。
- 打开工程目录下的
Objects文件夹,检查是否出现mcu51.hex。可以结合文件修改时间确认它是刚刚构建生成的版本。
- 本节配套工程的默认输出目录是
Objects。如果修改过 Keil 输出路径,应以Options for Target → Output中配置的位置为准。 .hex文件是供烧写工具读取的机器码文本,不是 C 源码。修改main.c后必须重新编译,否则烧写的仍可能是旧 HEX 文件。
六、连接开发板并烧写程序
6.1 硬件与串口准备
- 将 Type-C 数据线连接到开发板上靠近 CH340 USB 转串口芯片的接口,不要插错到另一个供电接口。
- 打开 Windows“设备管理器”,展开“端口(COM 和 LPT)”,找到名称中包含
USB-SERIAL CH340的端口。 - 记下它的 COM 编号。视频中的电脑是
COM3,其他电脑可能显示为 COM6 或其他编号,应以自己的设备管理器为准。
- 开发板有两个 Type-C 接口。原理图中标为“供电/下载USB”的 USBC1 同时连接 VBUS、D+ 和 D-,既能供电又能传输数据;标为“供电USB”的 USB1 只连接电源和地,不能把程序传给 CH340。因此烧写时必须使用“供电/下载USB”。
- 从电脑到单片机的主要电源和信号路径如下:
电脑 USB
│
├─ VBUS 5V ── C3 10µF / C4 100nF ── D1(SS34) ── VCC ── 单片机
│
├─ D+、D- ── CH340N(USB 转串口)
│ ├─ TXD ── D2(1N4148) ─────────► P3.0 / RXD
│ └─ RXD ◄── R1(300Ω) ────────── P3.1 / TXD
│
└─ RTS# ── C7 47µF ── Q2(AO3400) ── 自动断开/接通板端地线
- **供电部分:**USBC1 的 VBUS 是电脑提供的 5 V。C3(10 µF)用于缓冲较慢的电压波动,C4(100 nF)用于旁路高频噪声;大、小电容配合,使电源更稳定。D1 是 SS34 肖特基二极管,串在 VBUS 与 VCC 之间,可减少板端电源向 USB 口反向灌电的风险,同时其正向压降比普通硅二极管小。
- **USB 转串口:**电脑发送的是 USB 数据,STC89C52 的下载接口使用 UART 串口,二者协议不同。CH340N 负责把 USB 数据转换成串口的 TX/RX 电平信号。串口必须交叉连接:发送端 TXD 接收对方的 RXD,接收端 RXD 接收对方的 TXD,所以 CH340 的 TXD 最终连接单片机 P3.0/RXD,而单片机 P3.1/TXD 连接 CH340 的 RXD。
- **串联保护:**R1(300 Ω)限制串口线上可能出现的瞬时电流,D2(1N4148)在另一条数据路径上提供单向隔离,降低两端电平冲突或反向供电对通信的影响。
- **自动下载:**原理图把 USB 侧地标为
GND_U,板端地标为GND。Q2 是串在两个地之间的 AO3400 N 沟道 MOSFET,R2(10 kΩ)给栅极提供正常导通偏置;CH340 的RTS#状态变化通过 C7(47 µF)耦合到 Q2 栅极,使两个地短暂断开再接通。对单片机而言,这相当于一次快速掉电重启,从而让 STC 的 ISP 引导程序获得接收新程序的时机。 - **为什么串口灯会闪:**原理图中的 LD2、LD3 分别接在 TX、RX 网络上。下载时 TX/RX 电平不断变化,相应指示灯闪烁,说明串口链路上正在传输数据;灯闪只能证明有活动,最终是否成功仍应以烧写软件提示为准。
- **Type-C 线的实际限制:**从这份原理图看,两个 Type-C 接口的 CC1、CC2 没有画出 USB-C 受电设备通常使用的下拉识别电阻。因此该板主要按 USB-A 转 Type-C 数据线的使用场景设计,部分 Type-C 转 Type-C 线或充电器可能不主动供电。若连接后完全不亮、设备管理器也没有新设备,可优先换用支持数据传输的 USB-A 转 Type-C 线。
- **板上电源关系:**电源开关 SW1 用于接通
VCC与板上的+5V电源网络;LED 等外围电路使用+5V。AMS1117-3.3 再把+5V转换为+3.3V,供排针或外接模块使用。不要把+3.3V与+5V直接短接。
6.2 配置 AIapp-ISP
- 双击课程配套的
【STC烧写工具】AIapp-ISP-v6.95A.exe。 - 在“芯片型号”中选择
STC89C52RC/LE52RC。不能仅根据列表中的位置选择,因为不同软件版本的排列顺序可能变化,应核对完整型号文字。 - 在“扫描串口”处选择设备管理器中看到的 CH340 COM 端口。
- 单击“打开程序文件”,进入
0template/Objects,选择刚刚生成的mcu51.hex。打开后可在软件底部核对文件路径。 - 单击“下载/编程”开始烧写。烧写过程中,开发板的串口指示灯会闪烁;软件提示操作成功后,程序即已写入单片机。
6.3 验证运行效果
- 烧写成功后,开发板上的四个 LED 应按照 LED1、LED2、LED3、LED4 的顺序依次点亮,每个状态保持约 1 秒,然后循环执行。
- 这个现象与源码中的四组端口赋值及每组后面的
Delay1000ms()一一对应。通过修改 LED 顺序或延时时间并重新编译、烧写,可以进一步验证“源码—HEX—硬件现象”的关系。
七、烧写失败的排查顺序
- 确认 Type-C 线插在靠近 CH340 芯片的接口,并且数据线支持数据传输。
- 确认 CH340/CH341 驱动已安装,设备管理器中能够看到对应 COM 端口。
- 确认 AIapp-ISP 中选择的是本机实际 COM 号,而不是照抄视频中的
COM3。 - 确认芯片型号为
STC89C52RC/LE52RC。 - 确认载入的是当前工程最新生成的
Objects/mcu51.hex,可通过修改时间和软件底部路径判断。 - 单击“下载/编程”后,如果一直等待目标单片机,可按一下开发板复位键,使芯片重新进入启动阶段。
- 仍然失败时,重新插拔数据线后再次尝试,并观察串口指示灯是否闪烁。
- 开发板的
RST为高电平有效,手动复位电路如下:
C8 100 nF
+5V ──────────||──────────┬──────── RST(单片机复位脚)
│
R4 10 kΩ
│
GND
+5V ────────── SW2(按下)───────── RST
- 正常稳定运行时,R4 把 RST 拉到低电平,避免引脚悬空而误复位。刚上电的一瞬间,C8 会把
+5V的电压变化耦合到 RST,形成一个短暂高脉冲,完成上电复位;随后 R4 将 RST 拉回低电平。 - 按下 SW2 时,RST 被直接接到
+5V,单片机立即复位;松开后又被 R4 拉低并重新运行。复位不会擦除已经写入 Flash 的程序,只会让 CPU 从复位入口重新开始执行。 - AIapp-ISP 等待下载时按一下复位键,是为了让 STC 芯片重新进入上电后的 ISP 检测阶段。它与前面 Q2 控制地线的“自动下载”电路目的相同,都是制造一次重新启动;一个由人工按键触发,另一个由 CH340 控制信号自动触发。
八、常见问题归纳
- 思维导图中提供了常见问题网页。选中浏览器小图标,单击右键,再选择“打开链接”或“打开外部链接”(视频中使用右键菜单第二项)即可打开。
- 归纳文档覆盖 51 单片机、STM32 和 RT-Thread 等课程中学员经常遇到的问题。
- 与本节有关的内容包括:工程代码如何打包、串口驱动安装失败、不同电脑的 COM 号不一致、烧写软件配置、代码下载失败,以及如何新建
.c和.h文件。 - 遇到问题时应先核对错误信息和上述关键配置,再查阅归纳文档。下一节将开始讲解 51 单片机的基本知识。