本工程实现了一个极简、通用的88数码管 7 段数码管驱动,适用于 MCU 引脚资源紧张、需要复用 IO 的场景。

特点:  

✔ 仅需 5 个 IO 就能驱动两个数码管  
✔ 支持 0~99 任意数字显示  
✔ 代码结构清晰,便于移植  
✔ 有完整段码映射、扫描状态机

数码管引脚对应表

数码管实物图

不多说直接上代码-V-

里面的gpio.h,delay.h可以查看我之前发布的文章哦

1.digit.c

#include "digit.h"        // 数码管相关头文件
#include "gpio.h"         // GPIO 头文件
#include <stdint.h>       // 标准整数类型
#include <sc.h>           // 单片机相关头文件
#include "delay.h"        // 延时函数

// 定义数码管使用的 GPIO 引脚
#define LED1  RB4
#define LED2  RB5
#define LED3  RB2
#define LED4  RB1
#define LED5  RB0

#define HIGH  1            // 高电平
#define LOW   0            // 低电平

// 数码管段码表(0~9),显示0->001111111
uint8_t digit_table[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

//--------------------------------------------------
// 数码管初始化
//--------------------------------------------------
void Digite_Init(void)
{
    DIG_PowerOFF();       // 默认关闭显示
}

//--------------------------------------------------
// 清屏(所有引脚设为浮空输入)
//--------------------------------------------------
void DIG_Reset(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;  

    GPIO_InitStructure.Pin  = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 | GPIO_PIN_5;  
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT;  
    GPIO_InitStructure.Pull = GPIO_NOPULL;       // 浮空输入
    
    GPIO_Init(GPIOB, &GPIO_InitStructure);       // 初始化 GPIOB 引脚
}

//--------------------------------------------------
// 控制某个 LED 引脚输出高/低电平
//--------------------------------------------------
void DIG_LEDx_Control(DIG_PIN_t ledx, uint8_t level)
{
    GPIO_InitTypeDef GPIO_InitStructure;  
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; // 设置为推挽输出  

    // 选择要配置的引脚
    switch(ledx)
    {
        case 1: GPIO_InitStructure.Pin = GPIO_PIN_4; break;
        case 2: GPIO_InitStructure.Pin = GPIO_PIN_5; break;
        case 3: GPIO_InitStructure.Pin = GPIO_PIN_2; break;
        case 4: GPIO_InitStructure.Pin = GPIO_PIN_1; break;
        case 5: GPIO_InitStructure.Pin = GPIO_PIN_0; break;
    }

    GPIO_Init(GPIOB, &GPIO_InitStructure); 初始化 GPIOB 引脚

    // 设置输出电平
    switch(ledx)
    {
        case 1: LED1 = level; break;
        case 2: LED2 = level; break;
        case 3: LED3 = level; break;
        case 4: LED4 = level; break;
        case 5: LED5 = level; break;
    }
}

//--------------------------------------------------
// //显示左边数码管引脚1,是低电平的段码
//--------------------------------------------------
void DIG1_1L(uint8_t data_ten)
{
    DIG_LEDx_Control(DIG_PIN1, LOW);  // 设置为共阴脚

    if(digit_table[data_ten] & 0x01) DIG_LEDx_Control(DIG_PIN2, HIGH);
    if(digit_table[data_ten] & 0x02) DIG_LEDx_Control(DIG_PIN3, HIGH);
    if(digit_table[data_ten] & 0x04) DIG_LEDx_Control(DIG_PIN4, HIGH);
    if(digit_table[data_ten] & 0x08) DIG_LEDx_Control(DIG_PIN5, HIGH);
}

//--------------------------------------------------
// //显示左边数码管引脚2,是低电平的段码
//--------------------------------------------------
void DIG1_2L(uint8_t data_ten)
{
    DIG_LEDx_Control(DIG_PIN2, LOW);  

    if(digit_table[data_ten] & 0x10) DIG_LEDx_Control(DIG_PIN1, HIGH);
    if(digit_table[data_ten] & 0x20) DIG_LEDx_Control(DIG_PIN3, HIGH);
    if(digit_table[data_ten] & 0x40) DIG_LEDx_Control(DIG_PIN4, HIGH);
}

//--------------------------------------------------
//显示右边数码管引脚2,是低电平的段码
//--------------------------------------------------
void DIG2_2L(uint8_t data_bit)
{
    DIG_LEDx_Control(DIG_PIN2, LOW);

    if(digit_table[data_bit] & 0x01) DIG_LEDx_Control(DIG_PIN5, HIGH);
}

//--------------------------------------------------
// //显示左边数码管引脚3,是低电平的段码
//--------------------------------------------------
void DIG2_3L(uint8_t data_bit)
{
    DIG_LEDx_Control(DIG_PIN3, LOW);

    if(digit_table[data_bit] & 0x02) DIG_LEDx_Control(DIG_PIN1, HIGH);
    if(digit_table[data_bit] & 0x04) DIG_LEDx_Control(DIG_PIN2, HIGH);
    if(digit_table[data_bit] & 0x08) DIG_LEDx_Control(DIG_PIN4, HIGH);
    if(digit_table[data_bit] & 0x10) DIG_LEDx_Control(DIG_PIN5, HIGH);
}

//--------------------------------------------------
//显示左边数码管引脚4,是低电平的段码
//--------------------------------------------------
void DIG2_4L(uint8_t data_bit)
{
    DIG_LEDx_Control(DIG_PIN4, LOW);

    if(digit_table[data_bit] & 0x20) DIG_LEDx_Control(DIG_PIN1, HIGH);
    if(digit_table[data_bit] & 0x40) DIG_LEDx_Control(DIG_PIN2, HIGH);
}

//==================================================
// 变量定义区
//==================================================
uint8_t scan_cnt = 0;               // 扫描计数器
bit     digite_display_flag;        // 显示开关标志
uint8_t display_value;              // 显示的数字
uint8_t tens;                       // 十位
uint8_t ones;                       // 个位

//--------------------------------------------------
// 数码管扫描
//--------------------------------------------------
void Digite_Display(void)
{
        if(digite_display_flag)
        {
            DIG_Reset();  

            tens = display_value / 10;
            ones = display_value % 10;

            switch(scan_cnt)
            {
                case 0: DIG1_1L(tens); scan_cnt++; break;
                case 1: DIG1_2L(tens); scan_cnt++; break;
                case 2: DIG2_2L(ones); scan_cnt++; break;
                case 3: DIG2_3L(ones); scan_cnt++; break;
                case 4: DIG2_4L(ones); scan_cnt = 0; break;
                default: scan_cnt = 0; break;
            }
        }
}

//==================================================
// 显示固定数字的接口(给外部调用)
//==================================================
void Display_45(void){ display_value = 45; digite_display_flag = 1; }
void Display_55(void){ display_value = 55; digite_display_flag = 1; }
void Display_65(void){ display_value = 65; digite_display_flag = 1; }
void Display_88(void){ display_value = 88; digite_display_flag = 1; }

// 关闭显示
void Digite_Display_OFF(void)
{
    digite_display_flag = 0;
    DIG_Reset();
    display_value = 0;
}

//==================================================
// 状态机:循环显示 65 → 55 → 45
//==================================================
uint8_t digNumState = 0;  

void Digite_Switch(void)
{
    if(digNumState == 0)
    {
        Display_65();
        digNumState = 1;
    }
    else if(digNumState == 1)
    {
        Display_55();
        digNumState = 2;
    }
    else
    {
        Display_45();
        digNumState = 0;
    }
}

// 开机默认显示 65
void DIG_PowerON(void)
{
    Display_65();
    digNumState = 1;
}

// 关机清除显示
void DIG_PowerOFF(void)
{
    Digite_Display_OFF();
    digNumState = 0;
}

2.digit.h

#ifndef _DIGIT_H_
#define _DIGIT_H_
#include <stdint.h>

// 定义数码管,引脚编号的枚举类型
typedef enum
{
    DIG_PIN1 = 1,  // 枚举成员1,对应原宏定义1
    DIG_PIN2,      // 自动+1,对应2
    DIG_PIN3,      // 自动+1,对应3
    DIG_PIN4,      // 自动+1,对应4
    DIG_PIN5       // 自动+1,对应5
} DIG_PIN_t;       // 枚举类型名

void	Digite_Init(void);//数码管初始化
void	DIG_Reset(void);//清屏
// 函数作用:控制指定编号的LED输出高或低电平
// 参数 ledx:要控制的LED编号
// 参数 level:输出电平,1为高电平,0为低电平
void DIG_LEDx_Control(DIG_PIN_t ledx, uint8_t level);

void Digite_Display(void);

void Display_45(void);

void Display_55(void);

void Display_65(void);
void Display_88(void);
void Digite_Display_OFF(void);
void Digite_Switch(void);
// 开机初始化灯状态,只亮红灯
void DIG_PowerON(void);

// 关机时关闭所有灯
void DIG_PowerOFF(void);

#endif

3.把这个函数Digite_Display();放到定时器里面,我设置的是1ms扫描一次。

/***********************************************
函数名称:Interrupt
函数功能:中断服务
入口参数:无
出口参数:无
备注:只能有一个中断服务函数,1ms进入一次
************************************************/
void interrupt Interrupt(void)
{
	if(TMR2IF)
	{
		TMR2IF = 0;
		Digite_Display();//数码管扫描
	}
}

4.数码管显示65


void main(void)
{
	Init_System();//系统初始化
	Display_65();//显示65
	while(1)
	{
        asm("nop");          // 空操作指令
	}
}

5.真实拍摄图片

欢迎关注,更多精彩内容将持续更新,感谢您的支持!

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐