MCS-51单片机完整教程
第一部分:基础入门
第1章:什么是MCS-51单片机?
1 概念 MCS-51(通常简称为51单片机)是由美国Intel公司于1980年代推出的一种8位微控制器架构,由于其结构简单、稳定可靠、学习资料丰富,至今仍在工业控制、教学、消费电子等领域广泛应用,许多厂商(如Atmel、STC、宏晶科技)都生产兼容8051内核的单片机,其中最著名的是AT89C52和STC89C52RC。

2 核心特点
- 8位CPU:一次能处理8位(一个字节)的数据。
- 哈佛结构:程序存储器和数据存储器是两个独立的物理空间,可以同时访问,提高了执行效率。
- 特殊功能寄存器:用于控制单片机各个功能模块(如I/O、定时器、串口)的寄存器。
- 布尔处理器:专门用于位操作,使得对单个二进制位的控制变得非常高效。
- 丰富的外设:通常包含4个8位I/O口、2-3个16位定时器/计数器、1个全双工串行口等。
3 常见型号对比 | 型号 | 制造商 | 特点 | | :--- | :--- | :--- | | 8051 | Intel | 原始型号,需要外接ROM和RAM。 | | AT89C52 | Atmel | 内置4KB Flash ROM,8KB RAM,经典教学型号。 | | STC89C52RC | STC/宏晶 | 国产主流,内置8KB Flash,512B RAM,抗干扰能力强。 | | STC12C5A60S2 | STC/宏晶 | 1T架构(速度是传统8051的8-12倍),内置ADC、PWM等更多外设。 |
推荐初学者使用:STC89C52RC,因为它价格便宜、下载方便(通过USB转串口)、资料多。
第2章:开发环境搭建
1 硬件工具

- 单片机最小系统板:包含单片机、晶振(通常11.0592MHz或12MHz)、复位电路、电源电路,这是最基础的。
- USB转TTL串口模块:用于给STC单片机下载程序和与电脑通信。
- 杜邦线:用于连接外设(如LED、按键、传感器)。
- 电源:通常是USB供电或5V直流电源适配器。
2 软件工具
-
集成开发环境
- Keil C51:最经典、最强大的51单片机开发工具,支持C语言和汇编,可以下载评估版(代码限制在2KB以内)。
- SDCC:开源的C51编译器,完全免费。
- IAR Embedded Workbench:商业级IDE,功能强大,但价格昂贵。
推荐初学者使用:Keil C51。
-
程序下载工具
(图片来源网络,侵删)- STC-ISP:宏晶科技官方提供的下载软件,用于将编译好的
.hex文件烧录到STC单片机中,功能强大,支持多种型号。
- STC-ISP:宏晶科技官方提供的下载软件,用于将编译好的
-
串口调试助手
- SSCOM、串口助手等:用于在电脑上接收和发送单片机串口的数据,方便调试。
第3章:第一个程序 - Hello World (点亮一个LED)
1 硬件连接 将LED的正极(长脚)通过一个限流电阻(220Ω-1kΩ)连接到单片机的P1.0引脚,LED的负极(短脚)接地。
2 C语言代码分析
#include <reg52.h> // 包含51单片机的特殊功能寄存器定义头文件
// sfr 是特殊功能寄存器的关键字
// sbit 是单个位的定义关键字
sbit LED = P1^0; // 将P1.0引脚命名为LED,方便操作
void main(void) // 主函数,程序从这里开始执行
{
// 设置P1口的第0位为低电平 (0)
// 在51单片机中,引脚输出低电平(0V)时,LED会点亮
LED = 0;
while(1) // 无限循环,防止程序跑飞
{
// 程序在此处停止,LED保持点亮状态
}
}
3 代码编译与下载
- 打开Keil C51,新建一个工程,选择你的单片机型号(如STC89C52RC)。
- 新建一个C文件(如
main.c),将上面的代码粘贴进去。 - 编译代码,生成
.hex文件。 - 打开STC-ISP软件,选择
.hex文件,选择正确的串口和波特率,点击“下载”。 - 给单片机断电再上电,程序开始运行,LED被点亮。
第二部分:核心功能详解
第4章:I/O端口操作
1 端口结构 51单片机的4个I/O口(P0, P1, P2, P3)结构不同。
- P0口:作为通用I/O时,是开漏输出,必须外接上拉电阻才能输出高电平,通常用作数据/地址总线。
- P1, P2, P3口:内部有上拉电阻,可以直接用作输入输出。
2 输入/输出操作
- 输出:直接对端口寄存器赋值。
P1 = 0x55;(P1.0=1, P1.1=0, ...) - 输入:先要将对应端口的位置1(使其内部上拉有效),然后读取端口值。
sbit KEY = P3^2; KEY = 1; // 先将P3.2置1,准备读取 if(KEY == 0) // 如果检测到低电平,说明按键按下 { // 按键按下处理 }
实践:按键控制LED 连接一个按键到P3.2,当按键按下时,改变LED的状态。
第5章:中断系统
中断是单片机的核心机制之一,允许CPU在处理紧急事件时暂停当前任务,处理完后再返回继续执行。
1 51单片机的中断源
- 外部中断0 (INT0):P3.2引脚
- 外部中断1 (INT1):P3.3引脚
- 定时器0中断 (TF0)
- 定时器1中断 (TF1)
- 串行口中断 (RI/TI)
2 中断处理流程
- 设置中断允许寄存器:
EA(总开关),EX0/EX1(外部中断开关)。 - 设置中断优先级寄存器(可选)。
- 编写中断服务函数:格式为
void 函数名(void) interrupt 中断编号。 - 触发中断:硬件事件发生。
实践:使用外部中断0控制LED
#include <reg52.h>
sbit LED = P1^0;
// 外部中断0的中断服务函数
void INT0_ISR(void) interrupt 0
{
LED = ~LED; // 取反LED状态
}
void main(void)
{
LED = 0; // 初始LED熄灭
// 1. 设置INT0为下降沿触发
IT0 = 1; // IT0=1为下降沿触发,IT0=0为低电平触发
// 2. 开启总中断和外部中断0
EA = 1;
EX0 = 1;
while(1); // 主循环等待中断
}
第6章:定时器/计数器
51单片机通常有2个16位的定时器/计数器(Timer0和Timer1)。
1 工作模式
- 模式0:13位定时器/计数器。
- 模式1:16位定时器/计数器(最常用)。
- 模式2:8位自动重装定时器/计数器(适用于波特率发生器)。
- 模式3:Timer0拆分为两个8位定时器,Timer1无此模式。
2 定时器计算
假设使用12MHz晶振,机器周期 = 12 / 12MHz = 1μs。
要定时50ms,需要计数的次数 = 50ms / 1μs = 50000。
因为定时器是向上计数,所以初值 = 65536 - 50000 = 15536。
转换为十六进制:15536 = 0x3CB8。
实践:使用定时器0实现LED闪烁(500ms亮,500ms灭)
#include <reg52.h>
sbit LED = P1^0;
unsigned int count = 0; // 用于计数中断次数
// 定时器0的中断服务函数
void Timer0_ISR(void) interrupt 1
{
TH0 = (65536 - 50000) / 256; // 重新装载高8位
TL0 = (65536 - 50000) % 256; // 重新装载低8位
count++;
if(count >= 10) // 10次中断 * 50ms = 500ms
{
count = 0;
LED = ~LED; // 翻转LED
}
}
void main(void)
{
LED = 0;
// 1. 设置定时器0为模式1(16位)
TMOD = 0x01;
// 2. 装载初值
TH0 = (65536 - 50000) / 256;
TL0 = (65536 - 50000) % 256;
// 3. 开启定时器0中断和总中断
ET0 = 1;
EA = 1;
// 4. 启动定时器0
TR0 = 1;
while(1); // 主循环等待中断
}
第7章:串行通信
串行通信用于单片机之间、单片机与电脑、单片机与GPS/蓝牙模块等设备的数据交换。
1 模式1:8位UART(最常用)
- 波特率:由定时器1产生,公式:波特率 = (2^SMOD / 32) * (定时器1溢出率)。
- 常用波特率:9600, 19200, 115200。
- 关键寄存器:
SCON(控制寄存器)、TMOD(设置定时器1模式2)、PCON(设置波特率加倍位SMOD)。
实践:单片机向电脑发送 "Hello World!"
#include <reg52.h>
void UART_Init(void)
{
// 设置定时器1为模式2(8位自动重装)
TMOD = 0x20;
// 设置波特率为9600 (12MHz晶振)
TH1 = 0xFD; // 9600 baud
TL1 = 0xFD;
// 开启定时器1
TR1 = 1;
// 设置串口为模式1
SCON = 0x50;
// 开启串口中断
ES = 1;
// 开启总中断
EA = 1;
}
// 串口发送一个字节
void UART_SendByte(unsigned char dat)
{
SBUF = dat; // 将数据写入发送缓冲区
while(!TI); // 等待发送完成
TI = 0; // 清除发送中断标志位
}
// 串口中断服务函数
void UART_ISR(void) interrupt 4
{
if(RI) // 如果是接收中断
{
RI = 0; // 清除接收中断标志位
// 可以在这里处理接收到的数据
}
}
void main(void)
{
UART_Init();
UART_SendByte('H');
UART_SendByte('e');
UART_SendByte('l');
UART_SendByte('l');
UART_SendByte('o');
UART_SendByte(' ');
UART_SendByte('W');
UART_SendByte('o');
UART_SendByte('r');
UART_SendByte('l');
UART_SendByte('d');
UART_SendByte('!');
UART_SendByte('\r'); // 回车
UART_SendByte('\n'); // 换行
while(1);
}
第三部分:综合项目实践
项目1:数字时钟
- 功能:在4位或6位数码管上显示时、分、秒。
- 涉及技术:
- 数码管动态扫描(利用人眼视觉暂留效应)。
- 定时器中断精确计时。
- 数组存储数字的段码。
- 拓展:增加按键调整时间、增加闹钟功能。
项目2:温湿度监测仪
- 功能:使用DHT11或DHT22传感器采集温湿度数据,并通过串口在电脑上显示。
- 涉及技术:
- 单总线协议(DHT11通信协议)。
- 精确的时序控制(延时函数)。
- 串口通信。
- 拓展:增加OLED屏幕本地显示、增加阈值报警。
项目3:智能小车
- 功能:通过红外循迹传感器或超声波传感器,实现自动寻迹或避障。
- 涉及技术:
- 传感器数据采集。
- 电机驱动(通常使用L298N模块)。
- PWM(脉冲宽度调制)控制电机转速。
- 状态机编程逻辑。
第四部分:进阶与资源
第8章:从51到更广阔的世界
- STC增强型51:学习STC系列1T架构的单片机,它们速度更快、集成度更高(内置ADC、PWM、比较器等),是51单片机的现代发展方向。
- ARM Cortex-M:当你掌握了51单片机的底层寄存器操作和中断思想后,可以转向更强大的ARM Cortex-M系列(如STM32),它们性能更强、外设更丰富、开发更便捷(使用HAL库或LL库),是当今嵌入式领域的主流。
推荐学习资源
- 书籍:
- 《单片机C语言程序设计实训100例——基于8051+Proteus仿真》
- 《手把手教你学51单片机》
- 在线教程/视频:
- Bilibili:搜索“51单片机教程”,有大量从入门到精通的免费视频课程。
- 野火、正点原子:这些厂商的教程质量非常高,虽然是针对STM32,但其编程思想和架构讲解对51学习也很有帮助。
- 社区/论坛:
- CSDN
- 电子发烧友
- STC官方论坛
学习MCS-51单片机,关键在于理解其硬件结构和掌握寄存器操作,不要害怕直接操作寄存器,这是嵌入式开发的基石,从点亮一个LED开始,逐步学习I/O、中断、定时器、串口等核心模块,每个模块都动手实践一个完整的小项目,当你能够熟练使用这些功能时,你将打下坚实的嵌入式系统开发基础,无论未来转向哪种平台,都能快速上手,祝你学习愉快!
