这个2位半的7段数码管只用5个管脚驱动。如果用常规的7段+共阳/阴则需要用10个管脚。
如果把每个段看成独立的灯。5个管脚来点亮,任选其中一个作为COM端时,另外4条线可以单独各控制一个灯。所以实际上最多能驱动5*4 = 20个段。但是这里会有一个小问题。如果想点亮B1,可以让第3条线(P3)置高,P4 置低,其它阳极连P3的灯对应阴极P2 P1都应置高,此时会发现C1也会点亮。实际操作时,可以把COM端线P3设置为PP输出,其它线为OD输出。就可以单独控制了。
实际的驱动程序如下:
先定义一个二维数组描述数码管段与管脚对应关系
const uint8_t DotDecode[16][2] =
{
/*
3 4 B1
2 4 C1
2 3 A2
3 2 B2
4 3 C2
4 2 D2
5 2 E2
5 3 F2
5 4 G2
1 2 A3
2 1 B3
1 3 C3
3 1 D3
1 4 E3
4 1 F3
5 1 G3*/
{3, 4},{2, 4},{2, 3},{3, 2},{4, 3},{4, 2},{5, 2},{5, 3},
{5, 4},{1, 2},{2, 1},{1, 3},{3, 1},{1, 4},{4, 1},{5, 1}
};
定义段与要显示的数据译码
const uint8_t SEGMENT_CODES[] = {
0x7E, // 0
0x30, // 1
0x6D, // 2
0x79, // 3
0x33, // 4
0x5B, // 5
0x5F, // 6
0x70, // 7
0x7F, // 8
0x7B, // 9
0x77, // A
0x1F, // b
0x4E, // C
0x3D, // d
0x4F, // E
0x47, // F
};
定义一个16位变量,用于存储需要点亮的段。
uint16_t vram;
编写一个函数,将需要显示的数据映射到vram中,如果不显示把vram清零
void RefreashVram(uint8_t dat,uint8_t on){
uint8_t temp;
uint16_t temp16 = 0;
temp = dat;
if(on){
if(temp >= 100){
temp16 = 0xc000;
temp %= 100;
temp16 |= (SEGMENT_CODES[temp/10] << 7);
temp16 |= SEGMENT_CODES[temp%10];
}
else if(temp >= 10){
temp16 |= (SEGMENT_CODES[temp/10] << 7);
temp16 |= SEGMENT_CODES[temp%10];
}
else
temp16 |= SEGMENT_CODES[temp];
vram = temp16;
}
else
vram = 0;
}
下面是对操作引脚的定义,为方便编程序,定义一个端口指针数组和一个引脚号数组,然后就可以定引脚设置PP OD 置高置低操作了。
GPIO_TypeDef *drvport[5] = {DRV1_GPIO_Port,DRV2_GPIO_Port,DRV3_GPIO_Port,DRV4_GPIO_Port,DRV5_GPIO_Port};
uint16_t drvpin[5] = {DRV1_Pin,DRV2_Pin,DRV3_Pin,DRV4_Pin,DRV5_Pin};
#define setpp(i) drvport[i-1]->OTYPER &= ~drvpin[i-1]
#define setod(i) drvport[i-1]->OTYPER |= drvpin[i-1]
#define drivehi(i) drvport[i-1]->ODR |= drvpin[i-1]
#define drivelo(i) drvport[i-1]->ODR &= ~drvpin[i-1]
编写一个刷新显示的程序,需要每1ms执行一次。每次选取一条线作为COM端。扫描点阵矩阵,如果单元1中与COM相同,并且vram的对应位是1,则将单元2对应的引脚置低。
其它引脚置高。最后设置COM引脚为PP,其它为OD。就能刷新显示数据了。
void DisplayDigtal(){ //1ms 刷新显示一次
static uint8_t com = 1;
uint8_t drv = 0xFF; // 存储 驱动线需要输出的状态
if(vram == 0){
for(uint8_t i = 5;i>0;i--)
drivelo(i);
return;
}
for(uint8_t i = 0;i<16;i++){
if(DotDecode[0]==com){
if((vram & (1<<(15-i))) != 0) // 对应位不为0
drv &= ~(1<<DotDecode[1]);
}
}
for(uint8_t i = 5;i>0;i--){
setod(i);
if((drv & (1<<i)) == 0)
drivelo(i);
else
drivehi(i);
}
setpp(com);
com = (com < 5)? com+1:1;
}
另外增加一个快速灭显示的函数,就是把所有引脚置为OD输出。
void TurnoffDigital(void){
setod(1);
setod(2);
setod(3);
setod(4);
setod(5);
}
使用时,调用RefreashVram函数,将需要显示的数据转化为vram中的点。就能显示出来。
下面是动态显示数据的实例。
作者: southcreek, 来源:面包板社区
链接: https://mbb.eet-china.com/blog/uid-me-408807.html
版权声明:本文为博主原创,未经本人允许,禁止转载!
eeNick 2025-5-7 17:10