最近拿到了,只要用6个脚就能驱动
具体来说,原理是,两个脚一个脚为正,一个脚为负,就能点亮一段数码管。其他脚保持关闭状态
这样理论上可以实现6x5=30种点亮方式。3位数码管每位8个管脚加上一个小数点,刚好是27个灯
一次点亮一个灯,然后通过循环里一直切换,实现完整的显示
这里给一个数据手册的示意图

不过具体的引脚排列每个厂家都不一样,可以用万用表测出来。用红笔和黑笔接两个脚,某个灯管就亮了
管脚命名参考:

显示效果:

例程
使用方法:
c
#include "Display_seg.h"
int main()
{
SEG_Init();// 初始化引脚和变量
while(1)
{
SEG_Update();// 刷新显示
SEG_Display_Num(DIGIT_1, 1); // 第一位显示1
SEG_Display_Num(DIGIT_2, 2);
SEG_Display_Num(DIGIT_3, 3);
}
}
适配方法
注意每个单片机的函数不一样
把#include "sc.h"换成自己单片机的头文件
#define SEG1_PIN RB6 // 引脚1: PB6 ...
引脚改为自己的引脚代码
#define SEG1_INPUT() TRISB6 = 1 ...
引脚方向改为自己的引脚方向设置函数
灯序不一样的还要改一下这里的排序
static const SegMap seg_map[] = {
{2, 3, SEG_A, DIGIT_1}, ...
**{2,3...**表示电流方向是2->3时,亮第一个管脚
代码
Display_seg.h
c
#ifndef __SEG_DISPLAY_H
#define __SEG_DISPLAY_H
#include "sc.h"
//---------------------------------
// 用户自定义 数码管引脚
//---------------------------------
// 引脚定义(根据您的接线)
#define SEG1_PIN RB6 // 引脚1: PB6
#define SEG2_PIN RB5 // 引脚2: PB5
#define SEG3_PIN RB4 // 引脚3: PB4
#define SEG4_PIN RA3 // 引脚4: PA3
#define SEG5_PIN RA4 // 引脚5: PA4
#define SEG6_PIN RA5 // 引脚6: PA5
// 引脚方向
#define SEG1_INPUT() TRISB6 = 1
#define SEG2_INPUT() TRISB5 = 1
#define SEG3_INPUT() TRISB4 = 1
#define SEG4_INPUT() TRISA3 = 1
#define SEG5_INPUT() TRISA4 = 1
#define SEG6_INPUT() TRISA5 = 1
#define SEG1_OUTPUT() TRISB6 = 0
#define SEG2_OUTPUT() TRISB5 = 0
#define SEG3_OUTPUT() TRISB4 = 0
#define SEG4_OUTPUT() TRISA3 = 0
#define SEG5_OUTPUT() TRISA4 = 0
#define SEG6_OUTPUT() TRISA5 = 0
//---------------------------------
// 函数声明
void SEG_Init(void); // 初始化数码管
void SEG_Clear(void); // 清空显示
// 显示一位数字
// 变量:(数码管,数字)
void SEG_Display_Num(unsigned char digit, unsigned char num);
// 显示一个小数点
void SEG_Display_DP(unsigned char digit, unsigned char state);
// 刷新屏幕(需要在循环调用!!!重要)
void SEG_Update(void);
// 使用示例:
/*
int main()
{
SEG_Init();
while(1)
{
SEG_Update();// 刷新显示
SEG_Display_Num(DIGIT_1, 1); // 第一位显示1
SEG_Display_Num(DIGIT_2, 2);
SEG_Display_Num(DIGIT_3, 3);
}
}
*/
// 数码管编号
#define DIGIT_1 0
#define DIGIT_2 1
#define DIGIT_3 2
// 段码定义 (dp,g,f,e,d,c,b,a)
#define SEG_A 0x01
#define SEG_B 0x02
#define SEG_C 0x04
#define SEG_D 0x08
#define SEG_E 0x10
#define SEG_F 0x20
#define SEG_G 0x40
#define SEG_DP 0x80
// 数码管字段(A到G)
// AAAAA
// F B
// F B
// GGGGG
// E C
// E C
// DDDDD DP
//
// 数字0-9的字库
const unsigned char seg_code[] = {
SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F, // 0
SEG_B | SEG_C, // 1
SEG_A | SEG_B | SEG_G | SEG_E | SEG_D, // 2
SEG_A | SEG_B | SEG_G | SEG_C | SEG_D, // 3
SEG_F | SEG_G | SEG_B | SEG_C, // 4
SEG_A | SEG_F | SEG_G | SEG_C | SEG_D, // 5
SEG_A | SEG_F | SEG_G | SEG_E | SEG_C | SEG_D, // 6
SEG_A | SEG_B | SEG_C, // 7
SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G, // 8
SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G, // 9
SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G, // A [10]
SEG_C | SEG_D | SEG_E | SEG_F | SEG_G, // b [11]
SEG_A | SEG_D | SEG_E | SEG_F, // C [12]
SEG_B | SEG_C | SEG_D | SEG_E | SEG_G, // d [13]
SEG_A | SEG_D | SEG_E | SEG_F | SEG_G, // E [14]
SEG_A | SEG_E | SEG_F | SEG_G, // F [15]
SEG_B | SEG_C | SEG_E | SEG_F | SEG_G, // H [16]
SEG_D | SEG_E | SEG_F, // L [17]
SEG_A | SEG_B | SEG_E | SEG_F | SEG_G, // P [18]
SEG_E | SEG_G, // r [19]
SEG_G // - [20]
};
#define SEG_CODE_SIZE (sizeof(seg_code) / sizeof(unsigned char))
#endif
Display_seg.c
c
#include "Display_seg.h"
#include <stdint.h>
// 显示缓冲区(3位数码管)
static unsigned char seg_buffer[3] = {0, 0, 0};
// 当前扫描的数码管
static unsigned char current_digit = 0;
// 引脚配置表
// 格式: {阳极引脚, 阴极引脚, 段码位}
// 需要根据实际数码管内部连接关系填写
typedef struct
{
unsigned char anode; // 高电平引脚 (1-6)
unsigned char cathode; // 低电平引脚 (1-6)
unsigned char segment; // 段码
unsigned char digit; // 数码管位 (0-2)
} SegMap;
// 这里需要根据实际接线测试并修改
// 每个LED由两个引脚控制:一个阳极,一个阴极
static const SegMap seg_map[] = {
// 第1位数码管
{2, 3, SEG_A, DIGIT_1}, // A1: PB6->PB5
{2, 4, SEG_B, DIGIT_1}, // B1: PB5->PB4
{5, 2, SEG_C, DIGIT_1}, // C1: PB4->PA3
{2, 6, SEG_D, DIGIT_1}, // D1: PA3->PA4
{2, 5, SEG_E, DIGIT_1}, // E1: PA4->PA5
{3, 2, SEG_F, DIGIT_1}, // F1: PA5->PB6
{4, 2, SEG_G, DIGIT_1}, // G1: PB6->PB4
{2, 1, SEG_DP, DIGIT_1}, // DP1: PB5->PA3
// 第2位数码管
{5, 4, SEG_A, DIGIT_2}, // A2: PB4->PA4
{3, 5, SEG_B, DIGIT_2}, // B2: PA3->PA5
{4, 5, SEG_C, DIGIT_2}, // C2: PA4->PB6
{3, 4, SEG_D, DIGIT_2}, // D2: PA5->PB5
{6, 3, SEG_E, DIGIT_2}, // E2: PB6->PA3
{4, 3, SEG_F, DIGIT_2}, // F2: PB5->PA4
{5, 3, SEG_G, DIGIT_2}, // G2: PB4->PA5
{3, 1, SEG_DP, DIGIT_2}, // DP2: PA3->PB6
// 第3位数码管
{1, 6, SEG_A, DIGIT_3}, // A3: PA4->PB5
{3, 6, SEG_B, DIGIT_3}, // B3: PA5->PB4
{5, 6, SEG_C, DIGIT_3}, // C3: PB6->PA4
{6, 4, SEG_D, DIGIT_3}, // D3: PB5->PA5
{4, 6, SEG_E, DIGIT_3}, // E3: PB4->PB6
{6, 5, SEG_F, DIGIT_3}, // F3: PA3->PB5
{1, 5, SEG_G, DIGIT_3}, // G3: PA4->PB4
{6, 4, SEG_DP, DIGIT_3}, // DP3: PA5->PA3
};
#define SEG_MAP_SIZE (sizeof(seg_map) / sizeof(SegMap))
// 初始化数码管
void SEG_Init(void)
{
// 初始化所有引脚为输入高阻态
TRISA |= 0b00111000; // RB4,RB5,RB6 -> 输入
WPUA |= 0b00111000; // 上拉电阻
TRISB |= 0b01110000; // RB4,RB5,RB6 -> 输入
WPUB |= 0b01110000; // 上拉电阻
// 初始化显示缓冲区
seg_buffer[0] = 0;
seg_buffer[1] = 0;
seg_buffer[2] = 0;
current_digit = 0;
}
// 清除显示
void SEG_Clear(void)
{
// 初始化所有引脚为输入高阻态
TRISA |= 0b00111000; // RB4,RB5,RB6 -> 输入
WPUA |= 0b00111000; // 上拉电阻
TRISB |= 0b01110000; // RB4,RB5,RB6 -> 输入
WPUB |= 0b01110000; // 上拉电阻
}
// 操控6个引脚状态 (0:低电平, 1:高电平, 其他:高阻态)
static void set_pin(unsigned char pin, unsigned char state)
{
switch (pin)
{
case 1:
if (state == 1)
{
SEG1_OUTPUT();
SEG1_PIN = 1;
}
else if (state == 0)
{
SEG1_OUTPUT();
SEG1_PIN = 0;
}
else
{ // 高阻态
SEG1_INPUT();
SEG1_PIN = 0;
}
break;
case 2:
if (state == 1)
{
SEG2_OUTPUT();
SEG2_PIN = 1;
}
else if (state == 0)
{
SEG2_OUTPUT();
SEG2_PIN = 0;
}
else
{
SEG2_INPUT();
SEG2_PIN = 0;
}
break;
case 3:
if (state == 1)
{
SEG3_OUTPUT();
SEG3_PIN = 1;
}
else if (state == 0)
{
SEG3_OUTPUT();
SEG3_PIN = 0;
}
else
{
SEG3_INPUT();
SEG3_PIN = 0;
}
break;
case 4:
if (state == 1)
{
SEG4_OUTPUT();
SEG4_PIN = 1;
}
else if (state == 0)
{
SEG4_OUTPUT();
SEG4_PIN = 0;
}
else
{
SEG4_INPUT();
SEG4_PIN = 0;
}
break;
case 5:
if (state == 1)
{
SEG5_OUTPUT();
SEG5_PIN = 1;
}
else if (state == 0)
{
SEG5_OUTPUT();
SEG5_PIN = 0;
}
else
{
SEG5_INPUT();
SEG5_PIN = 0;
}
break;
case 6:
if (state == 1)
{
SEG6_OUTPUT();
SEG6_PIN = 1;
}
else if (state == 0)
{
SEG6_OUTPUT();
SEG6_PIN = 0;
}
else
{
SEG6_INPUT();
SEG6_PIN = 0;
}
break;
}
}
// 显示一位数字
void SEG_Display_Num(unsigned char digit, unsigned char num)
{
if (digit < 3 && num < 10)
{
seg_buffer[digit] = seg_code[num];
}
}
// 显示一个小数点
void SEG_Display_DP(unsigned char digit, unsigned char state)
{
if (digit < 3)
{
if (state == 1)
{
seg_buffer[digit] |= SEG_DP;
}
else
{
seg_buffer[digit] &= ~SEG_DP;
}
}
}
// 更新显示(需要在循环调用才能显示 !!!)
void SEG_Update(void)
{
// 一次更新一位数码管
static unsigned char seg_num = 0;
const SegMap *map = &seg_map[seg_num];
// 检查该段是否需要点亮
if (seg_buffer[map->digit] & map->segment)
{
// 点亮这个LED
SEG_Clear();
set_pin(map->anode, 1); // 阳极
set_pin(map->cathode, 0); // 阴极
}
else
{
// LED不需要时关闭 //注意:不加关闭会导致显示亮度不均
SEG_Clear();
}
seg_num = (seg_num + 1) % SEG_MAP_SIZE;
}