单片机串口控制单路共阳极数码管

1.1 程序功能

基于 STC89C52/AT89C52(reg52 内核)实现串口通信控制单只共阳极数码管

  1. 串口波特率固定 9600,上电打印就绪提示字符串;
  2. PC 串口助手发送字符 0~9、A~F、a~f,数码管实时显示对应十六进制数字;
  3. 收到非法字符时数码管熄灭;
  4. 串口接收采用中断方式,不阻塞主循环,实时响应上位机指令。

1.2 硬件资源分配

表格

外设 引脚 说明
数码管段选 P0 口 共阳极数码管段码输出,无位选(单数码管)
串口通信 P3.0(RXD)、P3.1(TXD) 标准 51 硬件 UART
定时器 1 Timer1 串口波特率发生器,模式 2 自动重装

1.3 开发环境

  • 内核:8051 标准内核
  • 头文件:reg52.h
  • 编译软件:Keil C51
  • 下载工具:STC-ISP / 普中 / 郭天祥下载器
  • 上位机:串口调试助手(波特率 9600,8N1)

二、宏定义与数据类型说明

2.1 类型重定义

c

运行

复制代码
typedef unsigned char uchar;   // 8位无符号字符
typedef unsigned int  uint;    // 16位无符号整型
#define uint8  uchar            // 标准8位类型别名
#define uint16 uint             // 标准16位类型别名

统一变量宽度命名,兼容嵌入式标准 uint8/uint16 写法,提升代码可移植性。

2.2 系统参数宏

c

运行

复制代码
#define BAUD_9600_TH  0xFA    // 9600波特率TH1初值(11.0592MHz晶振)
#define UART_INT_NUM  4       // 串口中断号,51单片机串口中断固定为4
#define SMG_A_DP_PORT	P0     // 数码管段码输出端口P0
  • BAUD_9600_TH:11.0592MHz 晶振、定时器 1 模式 2、波特率加倍 (SMOD=1) 下 9600 波特重装值;
  • UART_INT_NUM:中断服务函数 interrupt 关键字配套中断编号;
  • SMG_A_DP_PORT:数码管段口统一宏,修改硬件仅需改宏。

2.3 共阳极数码管段码表

c

运行

复制代码
uint8 gsmg_code[16]={
	0xC0,0xF9,0xA4,0xB0, // 0 1 2 3
	0x99,0x92,0x82,0xF8, // 4 5 6 7
	0x80,0x90,0x88,0x83, // 8 9 A B
	0xC6,0xA1,0x86,0x8E  // C D E F
};

共阳极逻辑:段脚输出高电平熄灭、低电平点亮,数组下标对应 0~F 十六进制数值。

三、全局变量说明

c

运行

复制代码
uchar uart_rec_buf;    // 串口单字节接收缓存,存储上位机下发指令
bit rec_flag = 0;      // 接收完成标志位,bit型占用单bit存储空间
  1. uart_rec_buf:中断中缓存串口接收字节,避免中断内处理耗时操作;
  2. rec_flag:中断置 1,主循环查询标志处理显示逻辑,分离中断与业务逻辑。

四、函数接口详细说明

4.1 延时函数 void delay_ms(uint16 x)

函数功能

软件毫秒级延时,仅用于预留拓展(本程序未调用,可用于多数码管动态扫描)。

参数

uint16 x:延时毫秒数

实现说明

双层循环软件延时,适配 11.0592MHz 标准晶振。

4.2 串口单字节发送 void UART_SendByte(uchar dat)

函数功能

通过硬件 UART 发送 1 字节数据,阻塞等待发送完成。

参数

uchar dat:待发送 8 位数据

执行流程
  1. 将数据写入发送寄存器 SBUF 启动发送;
  2. 循环等待发送完成标志 TI 置 1;
  3. 软件清零 TI 标志,退出函数。

4.3 串口字符串发送 void UART_SendString(uchar *str)

函数功能

循环调用单字节发送函数,输出以\0结尾的字符串。

参数

uchar *str:字符串首地址

执行流程

遍历字符串,逐字节发送,检测到结束符\0停止。

4.4 串口初始化 void UART_Init(uchar th_val)

函数功能

配置定时器 1、串口寄存器、中断总开关,初始化串口波特率。

参数

uchar th_val:定时器 1 高 8 位重装初值(波特率对应值)

寄存器配置拆解
  1. TMOD |= 0x20:Timer1 设为模式 2(8 位自动重装);
  2. SCON = 0x50:串口模式 1,8 位 UART,允许接收 REN=1;
  3. PCON |= 0x80:SMOD=1,波特率加倍;
  4. TH1、TL1 装载波特率初值;
  5. ES=1开启串口中断,EA=1开启总中断;
  6. TR1=1启动定时器 1 产生波特率时钟。

4.5 数码管全熄灭 void SMG_AllOff(void)

函数功能

共阳极数码管全部熄灭。

实现逻辑

P0 端口输出0xFF,所有段脚高电平,数码管无点亮段。

4.6 串口中断服务函数 void UART_ISR() interrupt UART_INT_NUM

函数功能

串口接收中断处理,仅缓存数据、置接收标志,无耗时操作。

中断触发条件

RXD 收到完整 1 字节数据,RI 硬件置 1 触发中断。

执行流程
  1. 判断接收标志 RI;
  2. 软件清零 RI;
  3. 将 SBUF 接收数据存入全局缓存uart_rec_buf
  4. 置位rec_flag=1通知主循环处理。
设计规范

中断函数禁止延时、数码管 IO 操作,保证中断快速退出,不干扰其他中断。

4.7 主函数 void main(void)

函数功能

系统入口,初始化外设、上电提示、循环检测串口指令并驱动数码管。

执行流程
  1. 调用UART_Init初始化串口 9600 波特率;
  2. 串口发送就绪提示字符串;
  3. 数码管上电熄灭;
  4. 死循环查询接收标志rec_flag
    • 收到新指令后清零标志;
    • 读取缓存字符,先熄灭数码管;
    • switch 匹配字符0~9,a/A~f/F,输出对应段码;
    • 非法字符保持数码管熄灭。

五、程序工作流程

  1. 上电初始化:串口、定时器、中断开启,打印就绪提示,数码管熄灭;
  2. 上位机下发字符:串口硬件接收触发中断;
  3. 中断缓存数据:中断保存字节,置接收标志后立即退出;
  4. 主循环响应指令:检测到标志后解析字符,输出对应段码到 P0 驱动数码管;
  5. 非法字符处理:收到非 0~F 字符,数码管保持熄灭。

六、通信协议规范

6.1 串口参数

  • 波特率:9600
  • 数据位:8
  • 校验位:无
  • 停止位:1

6.2 指令集

表格

上位机发送字符 数码管显示内容
'0' ~ '9' 数字 0~9
'A' / 'a' A
'B' / 'b' B
'C' / 'c' C
'D' / 'd' D
'E' / 'e' E
'F' / 'f' F
其他任意字符 数码管熄灭

6.3 上电打印信息

UART Ready! Send 0-9 A-F to display\r\n 串口助手上电自动接收,提示设备就绪。

七、硬件注意事项

  1. P0 口为开漏输出,驱动数码管建议外接上拉电阻(10K 排阻),否则亮度不足;
  2. 晶振必须使用 11.0592MHz,否则 9600 波特率存在较大误差,串口乱码;
  3. 数码管为共阳极 ,若使用共阴极需重新修改gsmg_code段码表;
  4. 单数码管无位选引脚,如需多位数码管拓展,需增加位选 IO 并添加动态扫描逻辑。

八、程序优点

  1. 中断接收,不阻塞主循环,实时响应上位机;
  2. 中断轻量化,无延时与 IO 操作,系统实时性高;
  3. 硬件端口、波特率使用宏定义,便于硬件修改移植;
  4. 大小写字母兼容,上位机操作更友好;
  5. 分层封装:发送、初始化、显示功能独立函数,可读性强;
  6. 非法字符容错,避免乱码导致数码管误显示。
cpp 复制代码
#include "reg52.h"

// 类型重定义统一
typedef unsigned char uchar;
typedef unsigned int  uint;
#define uint8  uchar
#define uint16 uint

// 系统参数宏定义
#define BAUD_9600_TH  0xFA
#define UART_INT_NUM  4

// 数码管端口定义 P0为段码输出
#define SMG_A_DP_PORT	P0

// 共阳极数码管 0~F 段码表
uint8 gsmg_code[16]={
	0xC0,0xF9,0xA4,0xB0,
	0x99,0x92,0x82,0xF8,
	0x80,0x90,0x88,0x83,
	0xC6,0xA1,0x86,0x8E
};

// 全局变量
uchar uart_rec_buf;    // 串口接收缓存
bit rec_flag = 0;      // 接收完成标志

/****************************
* @brief ms延时函数
****************************/
void delay_ms(uint16 x) 
{  
	uint16 j,i;   
	for(j=0;j<x;j++)   
	{    
		for(i=0;i<1100;i++);   
	}  
}

/****************************
* @brief 串口发送单个字节
****************************/
void UART_SendByte(uchar dat)
{
    SBUF = dat;
    while(TI == 0);
    TI = 0;
}

/****************************
* @brief 串口发送字符串
****************************/
void UART_SendString(uchar *str)
{
    while(*str != '\0')
    {
        UART_SendByte(*str++);
    }
}

/****************************
* @brief 串口初始化 9600波特率
****************************/
void UART_Init(uchar th_val)
{
    TMOD |= 0x20;
    SCON  = 0x50;
    PCON |= 0x80;

    TH1 = th_val;
    TL1 = th_val;

    ES  = 1;
    EA  = 1;
    TR1 = 1;
}

/****************************
* @brief 数码管全灭(输出0xFF,共阳极全熄灭)
****************************/
void SMG_AllOff(void)
{
    SMG_A_DP_PORT = 0xFF;
}

/****************************
* @brief 串口中断服务函数
* 仅缓存数据+置标志,无延时、无IO操作
****************************/
void UART_ISR() interrupt UART_INT_NUM
{
    if(RI == 1)
    {
        RI = 0;
        uart_rec_buf = SBUF;
        rec_flag = 1; // 标记收到新指令
    }
}

/****************************
* @brief 主函数
****************************/
void main(void)
{
    uchar cmd;
    UART_Init(BAUD_9600_TH);
    UART_SendString("UART Ready! Send 0-9 A-F to display\r\n");
    
    
    SMG_AllOff(); // 上电数码管熄灭

    while(1)
    {
        if(rec_flag == 1)
        {
            rec_flag = 0;
            cmd = uart_rec_buf;
            SMG_AllOff(); // 收到指令先熄灭数码管

            switch(cmd)
            {
                case '0': SMG_A_DP_PORT = gsmg_code[0]; break;
                case '1': SMG_A_DP_PORT = gsmg_code[1]; break;
                case '2': SMG_A_DP_PORT = gsmg_code[2]; break;
                case '3': SMG_A_DP_PORT = gsmg_code[3]; break;
                case '4': SMG_A_DP_PORT = gsmg_code[4]; break;
                case '5': SMG_A_DP_PORT = gsmg_code[5]; break;
                case '6': SMG_A_DP_PORT = gsmg_code[6]; break;
                case '7': SMG_A_DP_PORT = gsmg_code[7]; break;
                case '8': SMG_A_DP_PORT = gsmg_code[8]; break;
                case '9': SMG_A_DP_PORT = gsmg_code[9]; break;
                case 'A':
                case 'a': SMG_A_DP_PORT = gsmg_code[10]; break;
                case 'B':
                case 'b': SMG_A_DP_PORT = gsmg_code[11]; break;
                case 'C':
                case 'c': SMG_A_DP_PORT = gsmg_code[12]; break;
                case 'D':
                case 'd': SMG_A_DP_PORT = gsmg_code[13]; break;
                case 'E':
                case 'e': SMG_A_DP_PORT = gsmg_code[14]; break;
                case 'F':
                case 'f': SMG_A_DP_PORT = gsmg_code[15]; break;
                default: SMG_AllOff(); break; // 非法字符熄灭数码管
            }
        }
    }
}
相关推荐
南山电子nscn1 小时前
友顺科技UTC UR56XX系列在18V高压输入与1µA级超低功耗之间实现了出色的平衡
科技·单片机·嵌入式硬件·低压差线性稳压器
嵌入式-老费3 小时前
esp32开发与应用(与stm32f103工控板配合之上篇)
stm32·单片机·嵌入式硬件
周洲08305 小时前
裸机程序 vs RTOS架构深度对比|嵌入式项目选型标准、源码实战、优缺点全解析
stm32·嵌入式硬件
M海洋6 小时前
Ubuntu dialout 串口权限授权
linux·单片机·ubuntu
piaoyiren6 小时前
51单片机播放音乐
单片机·嵌入式硬件·51单片机
执迷不悟8236 小时前
51单片机
单片机·嵌入式硬件·51单片机
zjxtxdy7 小时前
TIM输入捕获
单片机·嵌入式硬件
西城微科方案开发8 小时前
西城微科蓝牙电子秤PCBA方案设计
单片机·嵌入式硬件
hongmai66688817 小时前
FH8856V310芯片详解:6M高清+0.5TOPS算力,赋能智能安防新方案
人工智能·单片机·嵌入式硬件·物联网·智能家居