这篇教程专为单片机小白打造,从 51 单片机基础讲起,带你搭建开发环境,学习汇编与 C 语言编程。通过 LED 灯闪烁、按键控制、数码管显示等基础实验,以及简易电子钟、温度检测系统等应用案例,结合代码实操,助你快速掌握 51 单片机开发。
目录
一、本篇背景
在电子技术的广阔领域中,单片机作为一种高度集成化的计算机芯片,以其体积小、成本低、功能强等特点,在工业控制、智能家居、汽车电子等众多领域得到了广泛的应用。51 单片机作为单片机家族中的经典代表,具有结构简单、易于学习等优点,成为了众多电子爱好者和初学者入门单片机编程的首选。本文将以小白的视角,详细介绍 51 单片机的基础知识、开发环境搭建、编程语言、基本实验以及一些常见的应用案例,帮助初学者逐步掌握 51 单片机的开发技术。
二、51 单片机基础知识
2.1 什么是 51 单片机
51 单片机是指以 Intel 8051 内核为基础发展起来的一系列单片机的统称。它最早由 Intel 公司在 1980 年推出,具有 8 位 CPU、4KB 程序存储器(ROM)、128B 数据存储器(RAM)、两个 16 位定时 / 计数器、64KB 外部数据存储器和程序存储器寻址空间等基本资源。后来,许多半导体公司如 Atmel、STC 等在 8051 内核的基础上进行了改进和扩展,推出了各具特色的 51 单片机产品,这些产品在功能和性能上有所提升,但基本的指令系统和架构仍然与 8051 兼容。
2.2 51 单片机的硬件结构
51 单片机的硬件结构主要由 CPU、存储器、I/O 接口、定时 / 计数器、中断系统等部分组成。
- CPU(中央处理器):是单片机的核心,负责执行程序指令,完成数据的运算和处理。
- 存储器:包括程序存储器(ROM)和数据存储器(RAM)。程序存储器用于存储用户编写的程序代码,数据存储器用于存储程序运行过程中的临时数据。
- I/O 接口:是单片机与外部设备进行数据交换的通道,51 单片机通常有 4 个 8 位的并行 I/O 口(P0、P1、P2、P3),可以实现数据的输入和输出。
- 定时 / 计数器:用于实现定时和计数功能,可用于产生精确的定时信号、测量脉冲信号的频率等。
- 中断系统:允许单片机在执行主程序的过程中,响应外部或内部的中断请求,暂停主程序的执行,转去执行相应的中断服务程序,处理完中断后再返回主程序继续执行。
2.3 51 单片机的引脚功能
51 单片机通常采用双列直插式(DIP)封装,具有 40 个引脚。不同的引脚具有不同的功能,下面简要介绍一些主要引脚的功能:
- 电源引脚:VCC(+5V)和 GND(地),为单片机提供电源。
- 时钟引脚:XTAL1 和 XTAL2,用于连接外部晶体振荡器,为单片机提供时钟信号。
- 复位引脚:RST,当该引脚出现高电平并保持一定时间时,单片机将进行复位操作,恢复到初始状态。
- 并行 I/O 口引脚:P0、P1、P2、P3 口的引脚,用于实现数据的输入和输出。
- 控制引脚:如 ALE/PROG、PSEN、EA/VPP 等,用于控制单片机的工作模式和数据传输。
三、开发环境搭建
3.1 硬件准备
- 51 单片机开发板:市面上有多种类型的 51 单片机开发板可供选择,初学者可以选择一款功能较为齐全、价格适中的开发板,如普中科技的 51 单片机开发板。
- USB 转串口线:用于将开发板与计算机连接,实现程序的下载和调试。
- 电源适配器:为开发板提供电源。
3.2 软件准备
- Keil C51:是一款专门用于 51 单片机编程的集成开发环境(IDE),支持 C 语言和汇编语言编程,具有代码编辑、编译、调试等功能。
- STC-ISP 下载软件:用于将 Keil C51 编译生成的程序代码下载到 STC 系列 51 单片机中。
3.3 开发环境搭建步骤
- 安装 Keil C51:下载 Keil C51 安装程序,按照安装向导的提示进行安装。安装完成后,打开 Keil C51,创建一个新的工程,选择合适的单片机型号。
- 安装 STC-ISP 下载软件:下载 STC-ISP 下载软件,解压后运行安装程序。安装完成后,打开 STC-ISP 下载软件,设置好单片机型号、串口波特率等参数。
- 连接开发板:使用 USB 转串口线将开发板与计算机连接,确保开发板的电源开关处于打开状态。
- 编写并编译程序:在 Keil C51 中编写 51 单片机程序代码,点击编译按钮进行编译。如果代码没有错误,编译器将生成一个十六进制(.hex)文件。
- 下载程序:打开 STC-ISP 下载软件,选择刚才生成的.hex 文件,点击下载按钮,将程序下载到单片机中。
四、编程语言
4.1 汇编语言
汇编语言是一种面向机器的低级语言,它使用助记符来表示机器指令,与单片机的硬件结构密切相关。汇编语言的优点是执行效率高、代码简洁,适合对程序执行时间和内存空间要求较高的场合。下面是一个简单的 51 单片机汇编语言程序示例,实现 LED 灯的闪烁:
ORG 0000H ; 程序起始地址
LJMP MAIN ; 跳转到主程序
ORG 0030H ; 主程序起始地址
MAIN:
SETB P1.0 ; 将 P1.0 引脚置高电平,点亮 LED 灯
LCALL DELAY ; 调用延时子程序
CLR P1.0 ; 将 P1.0 引脚置低电平,熄灭 LED 灯
LCALL DELAY ; 调用延时子程序
SJMP MAIN ; 跳转到主程序开头,循环执行
DELAY: ; 延时子程序
MOV R7, #200 ; 设置外层循环次数
D1: MOV R6, #250 ; 设置内层循环次数
D2: DJNZ R6, D2 ; 内层循环,R6 减 1,不为 0 则继续循环
DJNZ R7, D1 ; 外层循环,R7 减 1,不为 0 则继续循环
RET ; 子程序返回
END ; 程序结束
4.2 C 语言
C 语言是一种高级编程语言,具有结构化、模块化、可读性强等优点,易于学习和掌握。在 51 单片机开发中,使用 C 语言可以大大提高开发效率,减少开发周期。下面是一个使用 C 语言实现 LED 灯闪烁的程序示例:
#include <reg51.h> // 包含 51 单片机的头文件
#define uchar unsigned char // 定义无符号字符型变量
#define uint unsigned int // 定义无符号整型变量
sbit LED = P1^0; // 定义 P1.0 引脚为 LED 控制引脚
// 延时函数
void delay(uint time) {
uint i, j;
for(i = 0; i < time; i++)
for(j = 0; j < 123; j++);
}
void main() {
while(1) {
LED = 1; // 点亮 LED 灯
delay(500); // 延时 500ms
LED = 0; // 熄灭 LED 灯
delay(500); // 延时 500ms
}
}
五、基本实验
5.1 LED 灯闪烁实验
LED 灯闪烁实验是 51 单片机开发中最基础的实验之一,通过该实验可以熟悉 51 单片机的 I/O 口操作和延时函数的使用。实验步骤如下:
- 硬件连接:将开发板上的 LED 灯连接到 P1.0 引脚。
- 编写程序:使用 C 语言编写 LED 灯闪烁的程序代码,如上述示例所示。
- 编译并下载程序:在 Keil C51 中编译程序,生成.hex 文件,然后使用 STC-ISP 下载软件将程序下载到单片机中。
- 观察实验现象:下载完成后,开发板上的 LED 灯将开始闪烁。
5.2 按键控制 LED 灯实验
按键控制 LED 灯实验可以让我们了解 51 单片机的输入输出控制原理。实验步骤如下:
- 硬件连接:将开发板上的按键连接到 P3.2 引脚,LED 灯连接到 P1.0 引脚。
- 编写程序:使用 C 语言编写按键控制 LED 灯的程序代码,示例代码如下:
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
sbit KEY = P3^2; // 定义按键连接的引脚
sbit LED = P1^0; // 定义 LED 连接的引脚
void main() {
while(1) {
if(KEY == 0) { // 检测按键是否按下
while(KEY == 0); // 等待按键释放
LED = ~LED; // 取反 LED 灯的状态
}
}
}
- 编译并下载程序:同 LED 灯闪烁实验。
- 观察实验现象:按下按键,LED 灯的状态将发生改变。
5.3 数码管显示实验
数码管显示实验可以让我们学习 51 单片机的数码管驱动原理和段码编码方法。实验步骤如下:
- 硬件连接:将开发板上的数码管连接到相应的 I/O 口。
- 编写程序:使用 C 语言编写数码管显示的程序代码,示例代码如下:
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
uchar code SEG_CODE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; // 数码管段码表
sbit LSA = P2^2;
sbit LSB = P2^3;
sbit LSC = P2^4;
void main() {
uchar i;
while(1) {
for(i = 0; i < 10; i++) {
LSA = 0; LSB = 0; LSC = 0; // 选择第一个数码管
P0 = SEG_CODE[i]; // 显示数字 i
for(uint j = 0; j < 50000; j++); // 延时
}
}
}
- 编译并下载程序:同前两个实验。
- 观察实验现象:数码管将依次显示 0 - 9 的数字。
六、常见应用案例
6.1 简易电子钟
简易电子钟可以实现时间的显示和调整功能,是一个比较综合的 51 单片机应用案例。实现步骤如下:
- 硬件连接:使用数码管显示时间,按键用于时间调整,同时可以使用定时器来实现精确的计时。
- 编写程序:使用 C 语言编写电子钟的程序代码,包括时间计时、数码管显示、按键扫描等功能。示例代码如下:
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
uchar code SEG_CODE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; // 数码管段码表
sbit LSA = P2^2;
sbit LSB = P2^3;
sbit LSC = P2^4;
sbit KEY1 = P3^2; // 调整小时按键
sbit KEY2 = P3^3; // 调整分钟按键
uchar hour = 0, minute = 0, second = 0; // 初始化时间
// 延时函数
void delay(uint time) {
uint i, j;
for(i = 0; i < time; i++)
for(j = 0; j < 123; j++);
}
// 数码管显示函数
void display_time() {
uchar h1, h2, m1, m2;
h1 = hour / 10;
h2 = hour % 10;
m1 = minute / 10;
m2 = minute % 10;
LSA = 0; LSB = 0; LSC = 0; P0 = SEG_CODE[h1]; delay(5); // 显示小时十位
LSA = 1; LSB = 0; LSC = 0; P0 = SEG_CODE[h2]; delay(5); // 显示小时个位
LSA = 0; LSB = 1; LSC = 0; P0 = 0x40; delay(5); // 显示冒号
LSA = 1; LSB = 1; LSC = 0; P0 = SEG_CODE[m1]; delay(5); // 显示分钟十位
LSA = 0; LSB = 0; LSC = 1; P0 = SEG_CODE[m2]; delay(5); // 显示分钟个位
}
// 定时器初始化函数
void timer_init() {
TMOD = 0x01; // 设置定时器 0 为模式 1
TH0 = (65536 - 50000) / 256; // 定时器初值
TL0 = (65536 - 50000) % 256;
ET0 = 1; // 使能定时器 0 中断
EA = 1; // 全局中断使能
TR0 = 1; // 启动定时器 0
}
// 定时器中断服务函数
void timer0_isr() interrupt 1 {
TH0 = (65536 - 50000) / 256; // 重新加载初值
TL0 = (65536 - 50000) % 256;
static uint count = 0;
count++;
if(count >= 20) { // 每 1 秒
count = 0;
second++;
if(second >= 60) {
second = 0;
minute++;
if(minute >= 60) {
minute = 0;
hour++;
if(hour >= 24) {
hour = 0;
}
}
}
}
}
// 按键扫描函数
void key_scan() {
if(KEY1 == 0) {
delay(20); // 消抖
if(KEY1 == 0) {
while(KEY1 == 0);
hour = (hour + 1) % 24;
}
}
if(KEY2 == 0) {
delay(20); // 消抖
if(KEY2 == 0) {
while(KEY2 == 0);
minute = (minute + 1) % 60;
}
}
}
void main() {
timer_init();
while(1) {
display_time();
key_scan();
}
}
- 编译并下载程序:同前面的实验。
- 观察实验现象:数码管将显示当前的时间,按下按键可以调整时间。
6.2 温度检测系统
温度检测系统可以实时检测环境温度,并将温度值显示在数码管上。实现步骤如下:
- 硬件连接:使用温度传感器(如 DS18B20)采集温度数据,数码管显示温度值。
- 编写程序:使用 C 语言编写温度检测系统的程序代码,包括温度传感器驱动、数码管显示等功能。示例代码如下:
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit DQ = P3^7; // DS18B20 数据引脚
uchar code SEG_CODE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; // 数码管段码表
sbit LSA = P2^2;
sbit LSB = P2^3;
sbit LSC = P2^4;
// 延时函数
void delay(uint time) {
uint i, j;
for(i = 0; i < time; i++)
for(j = 0; j < 123; j++);
}
// DS18B20 初始化函数
bit ds18b20_init() {
bit presence;
DQ = 1;
_nop_();
DQ = 0;
delay(500); // 延时 480 - 960us
DQ = 1;
delay(60); // 延时 60 - 240us
presence = DQ;
delay(440); // 延时 480 - 960us
return presence;
}
// DS18B20 写一个字节函数
void ds18b20_write_byte(uchar dat) {
uchar i;
for(i = 0; i < 8; i++) {
DQ = 0;
_nop_();
DQ = dat & 0x01;
delay(60); // 延时 60 - 120us
DQ = 1;
dat >>= 1;
}
}
// DS18B20 读一个字节函数
uchar ds18b20_read_byte() {
uchar i, dat = 0;
for(i = 0; i < 8; i++) {
DQ = 0;
_nop_();
dat >>= 1;
DQ = 1;
if(DQ)
dat |= 0x80;
delay(60); // 延时 60 - 120us
}
return dat;
}
// 读取 DS18B20 温度函数
int ds18b20_read_temp() {
uchar LSB, MSB;
int temp;
ds18b20_init();
ds18b20_write_byte(0xCC); // 跳过 ROM 操作
ds18b20_write_byte(0x44); // 启动温度转换
delay(750); // 等待转换完成
ds18b20_init();
ds18b20_write_byte(0xCC); // 跳过 ROM 操作
ds18b20_write_byte(0xBE); // 读取温度寄存器
LSB = ds18b20_read_byte();
MSB = ds18b20_read_byte();
temp = (MSB << 8) | LSB;
temp = temp * 0.0625 * 10 + 0.5; // 转换为实际温度值
return temp;
}
// 数码管显示函数
void display_temp(int temp) {
uchar t1, t2, t3;
t1 = temp / 100;
t2 = (temp % 100) / 10;
t3 = temp % 10;
LSA = 0; LSB = 0; LSC = 0; P0 = SEG_CODE[t1]; delay(5); // 显示百位
LSA = 1; LSB = 0; LSC = 0; P0 = SEG_CODE[t2] | 0x80; delay(5); // 显示十位,带小数点
LSA = 0; LSB = 1; LSC = 0; P0 = SEG_CODE[t3]; delay(5); // 显示个位
}
void main() {
int temp;
while(1) {
temp = ds18b20_read_temp();
display_temp(temp);
}
}
- 编译并下载程序:同前面的实验。
- 观察实验现象:数码管将显示当前的环境温度值。
七、小结下:
通过本文的学习,我们从 51 单片机的基础知识入手,逐步了解了开发环境的搭建、编程语言的使用、基本实验的实现以及常见应用案例的开发。对于初学者来说,掌握 51 单片机的开发技术需要不断地实践和积累,通过完成更多的实验和项目,加深对单片机原理和编程方法的理解。希望本文能够帮助广大电子爱好者和初学者快速入门 51 单片机开发,开启电子技术的探索之旅。