51单片机期末复习汇总

该文章已生成可运行项目,

目录

一、简答题

(1)常用编程语言有哪些及其特点?

1.机械语言​

2.​汇编语言​

3.高级语言(C 语言)​

(2)定时的方法有哪些?

1.软件定时 / 计数​

2.硬件 / 数字电路定时​

3.可编程定时 / 计数​

(3)中断系统有哪些应用、功能、概念、服务程序、中断源?

1. 核心概念​

2. 中断技术的应用场景​

3. 中断系统的核心功能​

(4)为什么计算机要进行调制与解调? 计算机通讯方式有哪些(优缺点)?通信数据校验方法?

1. 调制与解调的作用​

2. 计算机通讯方式及优缺点​

3. 通信数据校验方法​

(5)仿真涉及的软件名称及作用

二、程序填空

(1)流水灯程序

(2)流水灯程序

三、程序设计——数码管编程

(1)共阴极段码必背:

(2)数码管的段选和位选的作用

(3)静态显示与动态显示的区别

(4)例题及代码

四、程序设计——外部中断编程

(1)中断源数量:

(2)中断触发方式:

(3)中断优先级选择

(4)例题及代码:

例题1:单片机外中断‘INT0’应用

例题2:单片机中断优先级应用

例题3:

五、程序设计——定时器编程

(1)寄存器

  1.寄存器介绍

2.寄存器使用原理:

【1】GATE门控位:

【2】C/T:定时器/计数器工作模式选择位

【3】M1、M0:工作方式选择位:

【4】TF1/0: 定时器T1/0溢出中断请求标志位

【5】TR1/0: 定时器T1/0运行控制位

【6】IT1/0: 外部中断1/0的触发方式选择位

【7】IE1/0: 外部中断‘INT1’的中断请求标志位

(2)定时器/计数器工作方式及定时器初值计算

公式:

1.方式0:(13位)

2.方式1:(16位)​编辑

3.方式2:(8位)

4.方式3:(双8位仅T0)

(3)定时器计数器初值计算例题:

(4)例题及代码:

例题1:定时器设计秒表

例题2:交通信号灯

一、简答题

(1)常用编程语言有哪些及其特点?

1.机械语言​

        核心特点:计算机唯一能直接识别的语言​

        缺点:由二进制代码组成,阅读和编写难度极大

2.​汇编语言​

        核心特点:能利用单片机所有特性,可直接控制硬件;基于 CPU 指令系统和寻址方式,占用空间小、执行速度快​

        缺点:编写效率低,开发周期长​

3.高级语言(C 语言)​

        核心特点:需配合单片机 C 编译器使用,代码效率高,语法简单易读,开发效率高​

        适用场景:单片机开发主流语言,兼顾性能与开发效率​

(2)定时的方法有哪些?

定时方法按实现层级可分为软件定时、硬件定时、操作系统级定时三类,具体特点如下:​

1.软件定时 / 计数​

        实现方式:通过执行一段循环程序实现时间延迟​

        优点:不需要外加硬件电路,成本低​

        缺点:定时时间有限(不宜过长);占用 CPU 资源,增加 CPU 负担,影响其他任务执行​

2.硬件 / 数字电路定时​

        实现方式:利用硬件定时器 / 计数器,通过配置时钟源、设定计数初值实现精准定时​

        优点:定时 / 计数功能完全由硬件完成,定时精度高(可达微秒级),不占用 CPU 资源​

        缺点:使用灵活性差,修改定时时间需调整硬件电路参数​

3.可编程定时 / 计数​

        实现方式:通过对系统时钟脉冲进行计数实现定时,可通过程序修改计数值​

        优点:使用灵活,无需改动硬件,通过软件配置即可改变定时时间​

        缺点:依赖操作系统环境,实时性略低于纯硬件定时​

(3)中断系统有哪些应用、功能、概念、服务程序、中断源?

1. 核心概念​

        中断:CPU 暂停当前主程序,优先处理紧急事件(如硬件触发),处理完毕后返回原程序继续执行的机制​

        中断服务程序:中断触发后 CPU 执行的专用程序,代码需简洁高效,必须清除中断标志以避免重复触发​

        中断源:引起中断的具体来源,常见类型包括:​

                输入 / 输出设备(如键盘、串口)​

                实时时钟或计数信号​

                故障源(如电源异常、溢出错误)​

2. 中断技术的应用场景​

        实现分时操作:使 CPU 与外设并行工作,提高系统利用率​

        实时处理:快速响应外部紧急事件(如传感器触发信号)​

        故障处理:及时处理系统异常(如过载、错误指令)​

3. 中断系统的核心功能​

        实现中断及返回:确保 CPU 能正确暂停主程序并在中断处理后恢复执行​

        实现优先权排队:当多个中断同时触发时,按优先级顺序处理​

        实现中断嵌套:高优先级中断可打断低优先级中断的处理过程​

(4)为什么计算机要进行调制与解调? 计算机通讯方式有哪些(优缺点)?通信数据校验方法?

1. 调制与解调的作用​

        计算机处理的是数字信号,而远距离传输通常依赖模拟信道(如电话线、射频信道)。调制是将数字信号转换为模拟信号以适配传输信道,解调是将接收的模拟信号还原为数字信号,从而实现远距离稳定传输。​

2. 计算机通讯方式及优缺点​

通讯方式​

核心特点​

优点​

缺点​

异步通讯​

收发设备使用各自独立的时钟控制数据传输​

无需严格同步时钟,硬件要求简单​

每个字符需加起始位、停止位,帧间有间隔,传输效率较低​

同步通讯​

发送方时钟直接控制接收方时钟,实现完全同步​

以特定位组合 “01111110” 作为帧标志,数据位长度灵活,传输效率高​

硬件设备复杂,时钟同步要求严格​

3. 通信数据校验方法​

  • 奇偶校验:发送数据时,在数据末尾添加 1 位校验位(1 或 0),使整个数据块中 1 的个数为奇数或偶数​
  • 代码和校验:发送方对数据块求和(或各字节 “异或” 运算),生成 1 字节校验字符附加到数据块末尾​
  • 循环冗余校验(CRC):通过数学运算建立有效信息与校验位的循环关系,校验精度高,抗干扰能力强

(5)仿真涉及的软件名称及作用

Protues仿真软件:支持单片机原理图设计、虚拟仿真与软硬件联调,助力学习开发,降低硬件成本与调试难度。

二、程序填空

(1)流水灯程序

#include<reg52.h>         //52系列单片机头文件

unsigned int i,j;         //生成无符号整型变量i,j

void main(){              //主函数

    while(1){             //大循环

    P1=0xfe;                 //点亮发光二极管D1

        for(i=100;i>0;i--);    //延时

        for(j=110;j>0;j--);
    P1=0xfd;                 //点亮发光二极管D2

        for(i=100;i>0;i--);    //延时

        for(j=110;j>0;j--);
    P1=0xfb;                 //点亮发光二极管D3

        for(i=100;i>0;i--);    //延时

        for(j=110;j>0;j--);
    P1=0xf7;                 //点亮发光二极管D4

        for(i=100;i>0;i--);    //延时

        for(j=110;j>0;j--);
    P1=0xef;                 //点亮发光二极管D5

        for(i=100;i>0;i--);    //延时

        for(j=110;j>0;j--);
    P1=0xdf;                 //点亮发光二极管D6

        for(i=100;i>0;i--);    //延时

        for(j=110;j>0;j--);
    P1=0xbf;                 //点亮发光二极管D7

        for(i=100;i>0;i--);    //延时

        for(j=110;j>0;j--);
    P1=0x7f;                 //点亮发光二极管D8

        for(i=100;i>0;i--);    //延时

        for(j=110;j>0;j--);}

(2)流水灯程序

#include<reg52.h>         //包含单片机寄存器的头文件

#include<intrins.h>       //包含单片机寄存器的头文件

void delay(void){       //延时子程序

    unsigned char i, j;

    for(i=0;i<250;i++);

    for(j=0;j<250;j++);}

void main(void){         //主程序

    P1=Oxfe;             //第一个灯亮

    while(1){

        P1=_crol_(P1,1); //将P1口的二进制位循环左移一位,再赋给P1

        delay(); }        //调用延时函数
} 

三、程序设计——数码管编程

(1)共阴极段码必背:

字符

0

1

2

3

4

5

6

7

8

段码

3FH

06H

5BH

4FH

66H

6DH

7DH

07H

7FH

字符

9

A

B

C

D

E

F

段码

6FH

77H

7CH

39H

5EH

79H

71H

00H

40H

(2)数码管的段选和位选的作用

 - 段选:控制数码管a-g、dp段的亮灭,决定显示的数字/字符(如段选输出0x3F显示数字0);

- 位选:选中要点亮的数码管,控制多数码管中哪一个显示内容。

(3)静态显示与动态显示的区别

静态显示与动态显示
类型核心特点优缺点
静态显示每个数码管独立段选+位选,持续通电显示稳定无闪烁,占用I/O口多
动态显示分时选通各数码管,利用视觉暂留占用I/O少,需定时刷新,易闪烁

(4)例题及代码

设计AT89C51单片机与一个4位效码相连的Protues仿真显示电路,并用C语言编程使数码管从左到右显示1~4。

#include <reg51.h>

// 定义端口
sbit dula = P0;       // 段选端口(P0)
sbit wela1 = P2^0;    // 第1位数码管位选
sbit wela2 = P2^1;    // 第2位数码管位选
sbit wela3 = P2^2;    // 第3位数码管位选
sbit wela4 = P2^3;    // 第4位数码管位选

// 共阴极数码管段码表(0-9)
unsigned char code seg_table[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

// 延时函数(视觉暂留,约1ms)
void delay(unsigned int t) {
    unsigned int i,j;
    for(i=t;i>0;i--)
        for(j=110;j>0;j--);
}

// 动态显示函数:依次显示1、2、3、4
void display() {
    // 第1位显示1
    wela1 = 1;
    dula = seg_table[1];
    delay(1);
    wela1 = 0;
    
    // 第2位显示2
    wela2 = 1;
    dula = seg_table[2];
    delay(1);
    wela2 = 0;
    
    // 第3位显示3
    wela3 = 1;
    dula = seg_table[3];
    delay(1);
    wela3 = 0;
    
    // 第4位显示4
    wela4 = 1;
    dula = seg_table[4];
    delay(1);
    wela4 = 0;
}

void main() {
    while(1) {
        display(); // 循环动态显示
    }
}

四、程序设计——外部中断编程

(1)中断源数量:

51单片机中断源数量 经典8051核心的单片机(如AT89C51)默认有5个基础中断源

1. 外部中断0(‘INT0’):对应引脚P3.2;

2. 外部中断1(’INT1‘):对应引脚P3.3;

3.定时器/计数器0(T0)溢出中断;

4. 定时器/计数器1(T1)溢出中断;

5. 串行口中断(UART):包含发送完成、接收完成中断。

(2)中断触发方式:

中断触发方式分为内部触发(由单片机内部事件触发)和外部触发(由外部引脚电平 / 边沿变化触发)两类,具体如下:

中断源触发类型具体触发方式
外部中断 0(‘INT0’外部触发

可通过 TCON 寄存器的 IT0 位配置:

IT0=0:低电平触发,IE0置1,申请中断;(电平触发)

IT0=1:下降沿触发,IE0置1,申请中断;(边沿触发)

IT0外部中断0的触发方式选择位,

IE0外部中断‘INT0’的中断请求标志位

外部中断 1(‘INT1’外部触发

可通过 TCON 寄存器的 IT1 位配置:

IT1=0:低电平触发,IE1置1,申请中断;(电平触发)

IT1=1:下降沿触发,IE1置1,申请中断;(边沿触发)

IT1外部中断1的触发方式选择位,

IE1外部中断‘INT1’的中断请求标志位

定时器 / 计数器 0(T0)内部触发定时器 / 计数器计数溢出(计数值从最大值(如 0xFF)溢出到 0),触发溢出中断(TF0 标志置 1);
定时器 / 计数器 1(T1)内部触发定时器 / 计数器计数溢出(TF1 标志置 1);
串行口中断(UART)内部触发

串行口收发完成触发:

发送完成(TI 标志置 1)、

接收完成(RI 标志置 1),

TI/RI 共用该中断源,需手动清 0;

(3)中断优先级选择

上电时,中断优先级寄存器IP被清零,每个中断源都处于同一个优先级,这时如果其中几个中断同时产生中断请求,则CPU按照片内硬件优先级链路的顺序即自然优先级响应中断,硬件优先级有高到低的顺序如下表所示:

(4)例题及代码:

例题1:单片机外中断‘INT0’应用

        关于单片机外中断‘INT0’应用的Proteus仿真电路如图所示,要求单片机主程
序控制P2口所接的8段共阳极数码管各段依次循环点亮,当外部中断‘INT0’输入出现从高到
低的负跳变时,数码管开始亮灭闪烁显示“8”,闪烁显示8次后,8段数码管的各段继续依
次循环点亮。试编写程序,实现上述功能。

#include<reg51.h>        // 引入51单片机寄存器定义头文件,用于操作中断、I/O口等寄存器
#include <intrins.h>     // 引入内置函数头文件,包含_crol_(循环左移)等操作函数
#define uint unsigned int  // 宏定义:简化无符号整型变量声明(uint替代unsigned int)
#define uchar unsigned char // 宏定义:简化无符号字符型变量声明(uchar替代unsigned char)

uchar i, aa;             // 全局变量:i用于中断服务函数的循环计数;aa用于主循环流水灯控制
void delay(uint z);      // 延时函数声明:提前声明避免主函数调用时编译器报错

void main()              // 主函数:程序入口,执行核心逻辑
{
    EA=1;                // 置1:开启总中断(51单片机所有中断的总开关,必须开启才会响应中断)
    EX0=1;               // 置1:开启外部中断0(对应P3.2引脚,允许该中断请求被响应)
    IT0=1;               // 置1:设置外部中断0为下降沿触发(IT0=0为低电平触发,1为下降沿)
    aa =0xfe;            // 初始化aa为0xfe(二进制11111110),用于P2口流水灯初始状态
    P3=0xff;             // P3口全部置高电平(外部中断0引脚P3.2默认上拉,避免误触发)
    
    while(1)             // 死循环:主程序持续执行流水灯逻辑
    {
        P2=aa;           // 将aa的值输出到P2口,控制P2口外接设备(如LED/数码管)状态
        delay(1000);     // 调用延时函数,保持当前P2口状态1000个延时单位(约1ms)
        aa=_crol_(aa, 1); // 调用循环左移函数:将aa的二进制位左移1位(如0xfe→0xfd→0xfb…),实现流水灯
    }
}

// 软件延时函数:通过双层for循环实现延时,参数z控制延时时长(z越大,延时越久)
void delay(uint z)
{
    uint x, y;           // 局部变量:用于循环计数
    // 外层循环z次,内层固定循环110次(12MHz晶振下,单次内层循环约10us,整体delay(1000)≈1ms)
    for(x=z; x>0; x--)
        for(y=110; y>0; y--);
}

// 外部中断0服务函数:interrupt 0表示该函数对应中断号0(外部中断0),中断触发时执行
void exter0()interrupt 0
{
    // 循环8次:实现数码管8次“亮-灭”闪烁
    for(i=8; i>0; i--)
    {
        P2=0x00;        // P2口全部置低电平(若接共阴极数码管,此段码并非数字8,注释存在偏差;共阴8的段码是0x7f)
        delay(500);     // 延时500个单位(约0.5s),保持数码管点亮状态
        P2=0x7f;        // P2口输出0x7f(二进制01111111),尝试熄灭数码管(但段码逻辑仍有问题)
        delay(500);     // 延时0.5s,保持数码管熄灭状态
    }
}

例题2:单片机中断优先级应用

        单片机中断优先级应用的仿真电路如图所示,要求用单片机主程序控制
p1口流水灯循环显示;外部中断‘INT0’引脚出现负跳变时,P1口全部发光二极管亮5s,外部
‘INT1’引脚出现负跳变时,P2口所接的共阳极数码管显示1,保持时间为5s。外部中新
‘INT1’为高优先级,外部中断‘INT0’为低优先级。试编写程序,实现上述功能。

#include<reg51.h>        // 51单片机寄存器定义头文件
#include <intrins.h>     // 包含循环移位等内置函数(如_crol_)
#define uint unsigned int  // 宏定义:将uint替换为unsigned int,简化代码
#define uchar unsigned char // 宏定义:将uchar替换为unsigned char

uchar aa;     // 全局变量:用于控制P1口输出的段选数据(初始0xfe,对应单个LED亮)
uchar K1;     // 全局标志位:标记外部中断0是否触发(0=触发,1=未触发)

void delay(uint z);  // 延时函数声明:避免函数调用时未定义报错

void main()          // 主函数:程序入口
{
    EA=1;            // 开启总中断(51单片机所有中断的总开关,EA=1才允许中断响应)
    EX0=1;           // 开启外部中断0(INT0,对应P3.2引脚)
    EX1=1;           // 开启外部中断1(INT1,对应P3.3引脚)
    IT0=1;           // 设置外部中断0为下降沿触发(IT0=1:下降沿;IT0=0:低电平)
    IT1=1;           // 设置外部中断1为下降沿触发
    PX0=0;           // 设置外部中断0为低优先级(PX0=0:低优先级;PX0=1:高优先级)
    PX1=1;           // 设置外部中断1为高优先级(高优先级中断可打断低优先级)
    aa =0xfe;        // 初始化aa为0xfe(二进制11111110),初始让P1.0引脚输出低电平
    P2=0xff;         // P2口全部置高(默认关闭P2口外接设备,如数码管位选)
    K1=1;            // 初始化K1标志位为1(表示外部中断0未触发)
    P3=0xff;         // P3口全部置高(外部中断引脚默认上拉,避免误触发)
    
    while(1)         // 死循环:程序主逻辑持续运行
    {
        P1=aa;       // 将aa的值输出到P1口,控制P1口外接的LED/数码管等外设
        delay(1000); // 调用延时函数,持续显示当前aa对应的状态
        aa=_crol_(aa, 1); // 将aa循环左移1位(如0xfe→0xfd→0xfb…),实现P1口LED流水灯
    }
}

// 延时函数:软件延时,参数z控制延时时长(z越大,延时越久)
void delay(uint z)
{
    uint x, y;
    // 双层for循环实现延时,x从z递减到0,内层y固定循环110次
    for(x=z; x>0; x--)
        for(y=110; y>0; y--);
}

// 外部中断0服务函数:interrupt 0表示中断号0(对应INT0),优先级由PX0决定
void exter0()interrupt 0
{
    K1=0;            // 置位K1为0,标记外部中断0已触发
    P1=0xff;         // P1口全部置高(先关闭所有LED/外设)
    P1=0x00;         // P1口全部置低(点亮P1口所有LED)
    delay(5000);     // 延时5000个单位,保持全亮状态
    P1=0xff;         // 恢复P1口为全高(熄灭所有LED)
    K1=1;            // 恢复K1为1,标记外部中断0处理完成
}

// 外部中断1服务函数:interrupt 2表示中断号2(对应INT1),优先级由PX1决定
void exter1()interrupt 2
{
    P1=0xff;         // 先关闭P1口所有外设
    P2=0xf9;         // P2口输出0xf9(二进制11111001),控制P2口外接设备(如数码管显示数字1)
    delay(5000);     // 延时保持该状态
    P2=0xff;         // 恢复P2口为全高(关闭P2口外设)
    if(K1==0) P1=0x00; // 若K1=0(外部中断0刚触发过),则将P1口置低(点亮所有LED)
}

例题3:

        电路如图所示,要求单片机主程序控制P0口数码管循环显示0-9;外部中断‘INT0’发生时,控制p2口数码管显示0-9,外部中断‘INT1’发生时,控制p1口数码管显示0~9,外部中断‘INT1’为高优先级,外部中断‘INT0’为低优先级,都采用边沿触发方式,数码管为共阴极数码管。试编写程序。

#include <reg51.h>
#define uint unsigned int
#define uchar unsigned char

// 共阴极数码管段码表(0-9):段码对应a-g+dp,共阴极低电平点亮
uchar code seg_table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
uchar num = 0;          // 显示数字索引(0-9循环)
bit flag_int0 = 0;      // INT0中断触发标志(0=未触发,1=触发)
bit flag_int1 = 0;      // INT1中断触发标志(0=未触发,1=触发)

// 软件延时函数(稳定数码管显示,晶振12MHz时,delay(1000)≈1ms)
void delay(uint z) {
    uint x, y;
    for(x = z; x > 0; x--)
        for(y = 110; y > 0; y--);
}

// 外部中断0服务函数(INT0/P3.2,低优先级)
void int0_service() interrupt 0 {
    flag_int0 = 1;  // 置位INT0触发标志,主循环处理显示
}

// 外部中断1服务函数(INT1/P3.3,高优先级)
void int1_service() interrupt 2 {
    flag_int1 = 1;  // 置位INT1触发标志,主循环处理显示
}

void main() {
    // 中断初始化
    EA = 1;         // 开启总中断(核心,所有中断必须开总中断)
    EX0 = 1;        // 使能外部中断0
    EX1 = 1;        // 使能外部中断1
    IT0 = 1;        // 设置INT0为下降沿触发(边沿触发)
    IT1 = 1;        // 设置INT1为下降沿触发(边沿触发)
    PX0 = 0;        // 设置INT0为低优先级
    PX1 = 1;        // 设置INT1为高优先级

    while(1) {      // 主循环:持续处理显示逻辑
        if(flag_int1) {  // 优先处理高优先级INT1触发
            P1 = seg_table[num];  // P1口显示当前数字
            delay(1000);
            num++;
            if(num > 9) num = 0;  // 数字循环0-9
        } else if(flag_int0) {   // 处理INT0触发(INT1未触发时)
            P2 = seg_table[num];  // P2口显示当前数字
            delay(1000);
            num++;
            if(num > 9) num = 0;
        } else {                 // 无中断时,主程序逻辑
            P0 = seg_table[num];  // P0口显示当前数字
            delay(1000);
            num++;
            if(num > 9) num = 0;
        }
    }
}

五、程序设计——定时器编程

(1)寄存器

  1.寄存器介绍

        TMOD用于设置其工作方式;TCON用于控制其启动和中断申请。

                工作方式寄存器:TMOD,确定工作方式和功能;

                控制寄存器:TCON,控制T0、T1的启动和停止及设置溢出标志。

2.寄存器使用原理:

工作方式寄存器TMOD

控制寄存器TCON

【1】GATE门控位:

【2】C/T:定时器/计数器工作模式选择位

        C/T=0:   定时器工作

        C/T=1:计数器工作

【3】M1、M0:工作方式选择位:

注意:TMOD控制两个定时器T1,T2,所以有两个M0,M1。一对M0,M1控制一个定时器。

【4】TF1/0: 定时器T1/0溢出中断请求标志位
【5】TR1/0: 定时器T1/0运行控制位
【6】IT1/0: 外部中断1/0的触发方式选择位
【7】IE1/0: 外部中断‘INT1’的中断请求标志位

(2)定时器/计数器工作方式及定时器初值计算

模式位数核心结构计数/定时范围:重装方式核心特点 & 适用场景
模式 013 位TL0 低 5 位 + TH0高8 位

(1~8192)Tcy

手动早期兼容 8048,冗余(不如模式 1 灵活),极少使用
模式 116 位TLx8 位 + THx8 位(1~65536)Tcy手动定时范围最大(11.0592MHz 下≈71ms),灵活通用
模式 28 位自动重装TLx 计数,THx 存重装值(1~256)Tcy自动精度最高(无软件重装误差),适合短定时 / 串口波特率发生器
模式 3双 8 位(仅 T0)T0 拆为 TL0(独立定时器)+ TH0(借用 T1 的 TR1/TF1)(1~256)Tcy手动需两个独立 8 位定时器场景,T1 若设为模式 3 则停止工作
公式:

1.方式0:(13位)

2.方式1:(16位)
3.方式2:(8位)

4.方式3:(双8位仅T0)

(3)定时器计数器初值计算例题:

(4)例题及代码:

例题1:定时器设计秒表

        利用单片机的定时器设计一个秒表,使它从0~59s计数,晶振频率f=12MHz,设计秒表的Proteus仿真电路,并编写程序。

解:

#include<reg51.h>         // 引入51单片机寄存器定义头文件,用于操作定时器、中断、I/O口
#define uint unsigned int // 宏定义:简化无符号整型声明(uint替代unsigned int)
#define uchar unsigned char// 宏定义:简化无符号字符型声明(uchar替代unsigned char)

uchar temp, aa, shi, ge;  // 全局变量:
                          // temp:计时累计值(0-59循环,对应秒数);aa:定时器中断计数(累计20次=1秒)
                          // shi:十位数字(temp/10);ge:个位数字(temp%10)
// 共阴极数码管段码表(0-9):段码对应a-g+dp,低电平点亮,dp默认熄灭
uchar code table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

void display(uchar shi, uchar ge); // 显示子程序声明(十位、个位数字)
void delay(uint z);                // 延时子程序声明
void init();                       // 初始化子程序声明

void main()                        // 主函数:程序入口
{
    init();                        // 调用初始化函数(定时器、中断、变量初始化)
    while(1)                       // 死循环:持续处理计时和显示逻辑
    {
        if(aa == 20)               // 定时器0中断累计20次(20×50ms=1秒)
        {
            aa = 0;                // 重置中断计数,重新累计1秒
            temp++;                // 秒数+1
            if(temp == 60)         // 秒数到60,重置为0(0-59循环)
            {
                temp = 0;
            }
        }
        shi = temp / 10;           // 计算十位数字(如temp=12→shi=1)
        ge = temp % 10;            // 计算个位数字(如temp=12→ge=2)
        display(shi, ge);          // 调用显示函数,刷新数码管显示
    }
}

// 软件延时函数:参数z控制延时时长(12MHz晶振下,delay(5)≈5ms)
void delay(uint z)
{
    uint x,y;                      // 局部循环计数变量
    for(x=z; x>0; x--)             // 外层循环z次
        for(y=110; y>0; y--);      // 内层固定循环110次,单次约10us
}

// 数码管显示子程序:显示十位+个位数字(动态扫描,消影处理)
void display(uchar shi, uchar ge)
{
    P2 = 0xbf;                     // 送入十位数码管位选信号(0xbf=10111111,假设P2.6控制十位选通)
    P0 = table[shi];               // 送入十位数字的段选信号(如shi=1→table[1]=0x06)
    delay(5);                      // 短暂延时,确保段码稳定(消影)

    P2 = 0x7f;                     // 送入个位数码管位选信号(0x7f=01111111,假设P2.7控制个位选通)
    P0 = table[ge];                // 送入个位数字的段选信号(如ge=2→table[2]=0x5b)
    
    delay(5);                      // 主延时,保持显示状态
}

// 初始化子程序:定时器0、中断、变量初始化
void init()
{
    temp = 0;                      // 初始化秒数为0
    TMOD = 0x01;                   // 设置定时器0为“定时器模式+工作方式1”(16位定时器,最大计数65536)
    // 定时器0初值设置:定时50ms(晶振12MHz,机器周期1us,50000us=50ms)
    TH0 = (65536 - 50000) / 256;   // 高8位初值:(65536-50000)=15536 → 15536/256=60
    TL0 = (65536 - 50000) % 256;   // 低8位初值:15536%256=176
    EA = 1;                        // 开启总中断(所有中断的总开关,必须置1)
    ET0 = 1;                       // 允许定时器0中断(开启定时器0的中断请求)
    TR0 = 1;                       // 启动定时器0(定时器开始计数)
}

// 定时器0中断服务函数:interrupt 1表示中断号1(定时器0中断)
void timer0() interrupt 1
{
    // 重装定时器0初值(方式1无自动重装,需手动赋值,保证定时精度)
    TH0 = (65536 - 50000) / 256;
    TL0 = (65536 - 50000) % 256;
    aa++;                          // 中断计数+1(每50ms触发1次中断,aa=20时累计1秒)
}
例题2:交通信号灯

        利用单片机的定时器设计交通信号灯控制电路,用Proteus仿真软件验证。

#include <reg52.h>         // 引入STC89C52寄存器定义头文件(兼容51,扩展了更多资源)
#define uint unsigned int  // 宏定义:简化无符号整型声明
#define uchar unsigned char// 宏定义:简化无符号字符型声明

// 引脚定义:A组=东西向指示灯,B组=南北向指示灯(共阴极/共阳极需匹配硬件,1/0对应亮灭)
sbit RED_A = P0^0;         // 东西向红灯 → P0.0引脚
sbit YELLOW_A = P0^1;      // 东西向黄灯 → P0.1引脚
sbit GREEN_A = P0^2;       // 东西向绿灯 → P0.2引脚
sbit RED_B = P0^3;         // 南北向红灯 → P0.3引脚
sbit YELLOW_B = P0^4;      // 南北向黄灯 → P0.4引脚
sbit GREEN_B = P0^5;       // 南北向绿灯 → P0.5引脚

// 全局变量:
uchar Count = 0;           // 基础计数器(配合定时器,累计50ms中断次数)
uchar Flash_Count = 0;     // 闪烁计数器(统计黄灯闪烁次数)
uchar Operation_Type = 1;  // 交通灯工作模式(1-4循环)

// 定时器0中断服务函数:interrupt 1 → 中断号1(定时器0中断),每50ms触发1次
void T0_INT() interrupt 1
{
    // 重装定时器0初值(16位方式1,无自动重装,需手动赋值)
    // 晶振12MHz,机器周期1us,定时50ms:初值=65536-50000=15536
    TH0 = (65536 - 50000) / 256;  // 高8位初值:15536/256=60
    TL0 = (65536 - 50000) % 256;  // 低8位初值:15536%256=176

    // 根据工作模式执行不同逻辑(switch分支)
    switch(Operation_Type)
    {
        case 1:  // 模式1:东西向绿灯亮、南北向红灯亮(持续5秒)
            RED_A = 0; YELLOW_A = 0; GREEN_A = 1;  // 东西向:红灭、黄灭、绿亮
            RED_B = 1; YELLOW_B = 0; GREEN_B = 0;  // 南北向:红亮、黄灭、绿灭
            if(++Count != 100) return;  // 累计100次中断=100×50ms=5秒,未到则直接返回
            Count = 0;                  // 5秒到,基础计数器清零
            Operation_Type = 2;         // 切换到模式2(东西向黄灯闪烁)
            break;  // 退出当前分支
        
        case 2:  // 模式2:东西向绿灯灭、黄灯闪烁(闪烁5次,总计5秒)
            if(++Count != 8) return;    // 累计8次中断=8×50ms=400ms(单次闪烁的亮/灭时长)
            Count = 0;                  // 400ms到,基础计数器清零
            YELLOW_A = !YELLOW_A;       // 东西向黄灯状态翻转(亮→灭/灭→亮)
            GREEN_A = 0;                // 确保东西向绿灯熄灭
            if(++Flash_Count != 10) return;  // 闪烁10次翻转=5次完整闪烁(亮+灭=1次)
            Flash_Count = 0;            // 闪烁次数清零
            Operation_Type = 3;         // 切换到模式3(南北向绿灯亮)
            break;  // 退出当前分支
        
        case 3:  // 模式3:东西向红灯亮、南北向绿灯亮(持续5秒)
            RED_A = 1; YELLOW_A = 0; GREEN_A = 0;  // 东西向:红亮、黄灭、绿灭
            RED_B = 0; YELLOW_B = 0; GREEN_B = 1;  // 南北向:红灭、黄灭、绿亮
            if(++Count != 100) return;  // 累计100次中断=5秒,未到则返回
            Count = 0;                  // 5秒到,基础计数器清零
            Operation_Type = 4;         // 切换到模式4(南北向黄灯闪烁)
            break;  // 退出当前分支
        
        case 4:  // 模式4:南北向绿灯灭、黄灯闪烁(闪烁5次,总计5秒)
            if(++Count != 8) return;    // 累计8次中断=400ms(单次闪烁时长)
            Count = 0;                  // 400ms到,基础计数器清零
            YELLOW_B = !YELLOW_B;       // 南北向黄灯状态翻转
            GREEN_B = 0;                // 确保南北向绿灯熄灭
            if(++Flash_Count != 10) return;  // 10次翻转=5次完整闪烁
            Flash_Count = 0;            // 闪烁次数清零
            Operation_Type = 1;         // 切换回模式1,循环工作
            break;  // 退出当前分支
    }
}

void main()  // 主函数:程序入口,仅做初始化,逻辑由定时器中断驱动
{
    TMOD = 0x01;  // 设置定时器0为“定时器模式+工作方式1”(16位定时器,最大计数65536)
    // 初始化定时器0初值(定时50ms)
    TH0 = (65536 - 50000) / 256;
    TL0 = (65536 - 50000) % 256;
    IE = 0x82;    // 开启总中断(EA=1)+ 允许定时器0中断(ET0=1),0x82=10000010B
    TR0 = 1;      // 启动定时器0(定时器开始计数,溢出触发中断)
    while(1);     // 死循环:主程序无其他逻辑,所有交通灯控制由定时器中断完成
}
本文章已经生成可运行项目
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值