MyBlog
首页归档笔记关于

© 2026 MyBlog. All rights reserved.

8051 单片机开发学习笔记(Keil C51 全套)

2026年03月13日学习笔记
#8051#单片机#Keil#嵌入式#教程#C51

8051 单片机开发学习笔记(Keil C51 全套)

更新日期:2026-03-13

一、学习路径(建议 6–8 周)

  1. Week 1:8051 架构、IO 口、寄存器、C51 工程创建。
  2. Week 2:GPIO 输入输出、按键消抖、LED/蜂鸣器。
  3. Week 3:定时器/计数器、外部中断。
  4. Week 4:串口通信(UART)、简单协议。
  5. Week 5:数码管/液晶显示、矩阵键盘。
  6. Week 6:综合小项目:温度采集/时钟/串口上报。

二、Keil C51 官方下载与文档

  • Keil 官方下载页:https://www.keil.com/download/product/(选择 C51)
  • C51 产品手册索引:https://www.keil.com/support/man_c51.htm
  • µVision 用户指南(C51 相关章节):https://www.keil.com/support/man/docs/uv4cl/uv4cl_dg_c51.htm
  • 51 单片机基础社区:http://www.51hei.com/

三、Keil C51 安装(官方版)

  1. 从官方页面下载 C51 安装包。
  2. 双击安装,按向导完成(默认路径即可)。
  3. 首次打开 µVision,建议以管理员身份运行。
  4. 可先使用评估版学习(官方说明:评估版有代码大小限制)。

四、工程模板与项目结构

  1. 新建工程:File → New uVision Project → 选择工程目录。
  2. 选择芯片:例如 AT89C51 / AT89S51(与你的实物一致)。
  3. 询问是否添加启动文件:选择 “Yes”。
  4. 新建源文件 main.c,加入工程组。
  5. Target Options:设置晶振频率(如 11.0592MHz)。

五、点灯与 IO 基础

硬件连接

  • LED 串 1k 电阻,接 P1.0 → LED → 电阻 → GND(低电平点亮)。
  • 晶振 + 复位电路按手册搭建最小系统。

点灯示例(C51)

#include <REGX51.H>

void delay_ms(unsigned int ms) {
    unsigned int i, j;
    for (i = 0; i < ms; i++) {
        for (j = 0; j < 110; j++) {
            ;
        }
    }
}

void main(void) {
    while (1) {
        P1_0 = 0;  // 低电平点亮
        delay_ms(500);
        P1_0 = 1;  // 高电平熄灭
        delay_ms(500);
    }
}

六、按键输入与消抖

#include <REGX51.H>

sbit KEY = P3^2; // INT0 引脚
sbit LED = P1^0;

void delay_ms(unsigned int ms) {
    unsigned int i, j;
    for (i = 0; i < ms; i++) {
        for (j = 0; j < 110; j++) { ; }
    }
}

void main(void) {
    LED = 1;
    while (1) {
        if (KEY == 0) { // 按下为低
            delay_ms(20); // 消抖
            if (KEY == 0) {
                LED = ~LED;
                while (KEY == 0); // 等待松手
            }
        }
    }
}

七、定时器/计数器(Timer0)

示例:每 1ms 进入中断,用于软件定时。

#include <REGX51.H>

unsigned int ms = 0;

void Timer0_Init(void) {
    TMOD &= 0xF0;    // 选择定时器0
    TMOD |= 0x01;    // 模式1(16位)
    TH0 = 0xFC;      // 11.0592MHz 下 1ms
    TL0 = 0x18;
    ET0 = 1;         // 允许T0中断
    EA = 1;          // 总中断开
    TR0 = 1;         // 启动T0
}

void Timer0_ISR(void) interrupt 1 {
    TH0 = 0xFC;
    TL0 = 0x18;
    ms++;
}

void main(void) {
    Timer0_Init();
    while (1) {
        // 主循环
    }
}

八、外部中断(INT0)

#include <REGX51.H>

void INT0_Init(void) {
    IT0 = 1;  // 下降沿触发
    EX0 = 1;  // 使能外部中断0
    EA = 1;   // 总中断开
}

void INT0_ISR(void) interrupt 0 {
    // 外部中断响应
}

void main(void) {
    INT0_Init();
    while (1) {}
}

九、串口通信(UART)

示例:9600bps,8N1,定时器1作为波特率发生器。

#include <REGX51.H>

void UART_Init(void) {
    SCON = 0x50;     // 8位UART, 允许接收
    TMOD |= 0x20;    // 定时器1模式2
    TH1 = 0xFD;      // 11.0592MHz, 9600
    TL1 = 0xFD;
    TR1 = 1;         // 启动T1
    EA = 1;
    ES = 1;          // 开启串口中断
}

void UART_Send(char c) {
    SBUF = c;
    while (TI == 0);
    TI = 0;
}

void UART_ISR(void) interrupt 4 {
    if (RI) {
        RI = 0;
        // 处理接收
    }
}

void main(void) {
    UART_Init();
    UART_Send('H');
    UART_Send('i');
    while (1) {}
}

十、数码管显示(共阴一位示例)

#include <REGX51.H>

unsigned char seg_code[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

void main(void) {
    while (1) {
        P0 = seg_code[3]; // 显示“3”
    }
}

十一、蜂鸣器/PWM(软件方式)

#include <REGX51.H>

sbit BEEP = P1^5;

void delay_us(unsigned int us) {
    while (us--) { ; }
}

void main(void) {
    while (1) {
        BEEP = 0;
        delay_us(200);
        BEEP = 1;
        delay_us(200);
    }
}

十二、Proteus 仿真步骤(简要)

  1. Proteus 新建工程,放置 AT89C51、LED、电阻、晶振、按键等元件。
  2. 设置单片机晶振频率与 Keil 一致。
  3. 编译生成 HEX,将 HEX 文件加载到单片机属性中。
  4. 运行仿真观察波形/灯闪烁。

十三、实物烧录与下载

  • 常见下载工具:USBasp、CH340 ISP、厂商下载器。
  • 流程:Keil 生成 HEX → 打开下载工具 → 选择芯片 → 写入 HEX → 验证。
  • 注意芯片电压、晶振与下载接口一致。

十四、综合项目建议(入门级)

  • 电子时钟:定时器 + 数码管。
  • 温度显示:DS18B20 + 数码管。
  • 串口助手:UART + PC 串口调试。
  • 键盘锁:矩阵键盘 + EEPROM。

十五、完整项目实战源码

1) 电子时钟(定时器 + 数码管 6 位动态扫描)

#include <REGX51.H>

unsigned char seg_code[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
unsigned char disp[6] = {0,0,0,0,0,0};
unsigned char idx = 0;
unsigned int ms = 0;
unsigned char hour=12, min=0, sec=0;

void Timer0_Init(void) {
    TMOD &= 0xF0;
    TMOD |= 0x01;
    TH0 = 0xFC;  // 1ms
    TL0 = 0x18;
    ET0 = 1; EA = 1; TR0 = 1;
}

void Timer0_ISR(void) interrupt 1 {
    TH0 = 0xFC; TL0 = 0x18;
    ms++;
    if (ms >= 1000) {
        ms = 0;
        sec++;
        if (sec >= 60) { sec=0; min++; }
        if (min >= 60) { min=0; hour++; }
        if (hour >= 24) { hour=0; }
    }

    // 动态扫描 6 位
    P2 = 0xFF;       // 关位选
    P0 = seg_code[disp[idx]];
    P2 = ~(1 << idx); // 低有效位选
    idx = (idx + 1) % 6;
}

void update_display(void) {
    disp[0] = hour / 10;
    disp[1] = hour % 10;
    disp[2] = min / 10;
    disp[3] = min % 10;
    disp[4] = sec / 10;
    disp[5] = sec % 10;
}

void main(void) {
    Timer0_Init();
    while (1) {
        update_display();
    }
}

2) 温度显示(DS18B20 + 数码管)

#include <REGX51.H>

sbit DQ = P3^7;
unsigned char seg_code[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

void delay_us(unsigned int us){ while(us--); }

bit ds18b20_reset(void){
    bit presence;
    DQ = 1; delay_us(5);
    DQ = 0; delay_us(500);
    DQ = 1; delay_us(60);
    presence = DQ; // 0 means present
    delay_us(240);
    return presence;
}

void ds18b20_write(unsigned char dat){
    unsigned char i;
    for(i=0;i<8;i++){
        DQ=0; delay_us(2);
        DQ = dat & 0x01; delay_us(60);
        DQ=1; dat >>=1;
    }
}

unsigned char ds18b20_read(void){
    unsigned char i, dat=0;
    for(i=0;i<8;i++){
        DQ=0; delay_us(2);
        DQ=1; delay_us(8);
        dat >>=1;
        if(DQ) dat |= 0x80;
        delay_us(50);
    }
    return dat;
}

int ds18b20_get_temp(void){
    unsigned char low, high;
    ds18b20_reset();
    ds18b20_write(0xCC); // Skip ROM
    ds18b20_write(0x44); // Convert T
    delay_us(50000);
    ds18b20_reset();
    ds18b20_write(0xCC);
    ds18b20_write(0xBE); // Read Scratchpad
    low = ds18b20_read();
    high = ds18b20_read();
    return (high<<8) | low; // raw
}

void main(void){
    int raw;
    unsigned char temp, tens, ones;
    while(1){
        raw = ds18b20_get_temp();
        temp = (unsigned char)(raw / 16); // 12-bit -> integer
        tens = temp / 10;
        ones = temp % 10;
        P0 = seg_code[tens]; // 简化演示,仅显示两位
        P2 = 0xFE;
        delay_us(2000);
        P0 = seg_code[ones];
        P2 = 0xFD;
        delay_us(2000);
    }
}

3) 串口协议示例(简单命令)

#include <REGX51.H>

void UART_Init(void) {
    SCON = 0x50;     // 8位UART, 允许接收
    TMOD |= 0x20;    // 定时器1模式2
    TH1 = 0xFD;      // 9600bps
    TL1 = 0xFD;
    TR1 = 1; EA = 1; ES = 1;
}

void UART_Send(char c) {
    SBUF = c;
    while (TI == 0);
    TI = 0;
}

void UART_SendStr(char *s){
    while(*s){ UART_Send(*s++); }
}

void UART_ISR(void) interrupt 4 {
    char c;
    if (RI) {
        RI = 0;
        c = SBUF;
        if (c == 'L') { // 点亮
            P1_0 = 0;
            UART_SendStr("LED ON
");
        } else if (c == 'O') { // 熄灭
            P1_0 = 1;
            UART_SendStr("LED OFF
");
        }
    }
}

void main(void) {
    P1_0 = 1;
    UART_Init();
    UART_SendStr("Ready
");
    while(1){}
}

十六、器件清单 + 接线图(入门套件)

器件清单

  • AT89C51/AT89S51 开发板或最小系统板
  • 晶振 11.0592MHz + 30pF 电容 x2
  • 复位电路:10uF 电容 + 10k 电阻 + 按键
  • LED + 1k 电阻
  • 数码管(共阴 4~6 位)+ 三极管驱动(可选)
  • DS18B20 温度传感器 + 4.7k 上拉电阻
  • USB 转串口模块(CH340)

简单接线示意(ASCII)

P1.0 ----[1k]----|> LED ---- GND
P3.0 (RXD) -------------- TX (USB-串口)
P3.1 (TXD) -------------- RX (USB-串口)
P3.7 (DQ) ---[4.7k]--- VCC   (DS18B20)
            |
          DS18B20

十七、常见问题排查

  • 晶振频率与定时器装载值不匹配 → 定时不准。
  • 端口未上拉或硬件连接反向 → LED 不亮。
  • 串口波特率不匹配 → 乱码。
  • 未加复位电路或电源不稳 → 程序不运行。

参考链接

  • Keil C51 下载页:https://www.keil.com/download/product/
  • C51 手册:https://www.keil.com/support/man_c51.htm
  • µVision 用户指南:https://www.keil.com/support/man/docs/uv4cl/uv4cl_dg_c51.htm
  • 51 单片机基础社区:http://www.51hei.com/

声明:本文为学习笔记,示例代码可直接用于教学与实验环境。