一、简单介绍

数码管驱动电路如图所示,笔者选用安世半导体生产的74HC138D和74HC595D芯片驱动共阴极数码管。原理图如下:

数码管

四位贴片共阴极数码管,6、8、9、12分别是四个数码管的阴极。单看每一个数字,由8个发光二极管组成,这些二极管的阴极是连在一起的。
abcdefg等代表四个数码管的每一个短线(小数点)。当其中段选一个高电平,同时位选是低电平,发光二极管导通,对应的短线就会亮起来。
74HC138D

74HC138D具有3条地址线和8个输出,唯有E1和E2均为低电平且E3是高电平,输出才不会都是高(大部分使用场景)。


真值表和逻辑框图如上。输入A2是高位,输出Y7是高位。
如果要4个数码管的阴极输出低电平,Y3=0 -> A2A1A0 = 3 -> 0b011。
74HC595D

74HC595是8bit的串行输入,并行输出寄存器芯片,移位和存储具有单独的时钟(SHCP引脚或者STCP引脚的上升沿)。
SHCP上升沿:数据移位,会频繁触发。
STCP上升沿:将移位寄存器的数据搬运到存储寄存器,偶尔触发。
OE控制输出:当OE为低时,存储寄存器的值体现在输出引脚上,OE为高时,输出引脚高阻态。
Q7S是为级联提供便利而设置的。


观察时序图,发现在SHCP的上升沿,对DS引脚电平采样,把DS电平存放在内部寄存器(每来一个SHCP上升沿,内部寄存器就移位一次),当STCP上升沿,内部寄存器输出到Q0~Q7引脚上(OE为低电平)。

例如显示"1"那么"b"和"c"是高电平,其余是低电平。
abcdefgh输出值0b0110 0000亦即0x60。
每来一个SHCP上升沿,数据就会移位一次,因此Q7是第一次采样时DS值,连接到数码管的DPX引脚。以此类推,Q2是第5次采样(c),Q2是第6次采样(b)。
二、驱动代码
cpp
#define DIGITAL_A0_LOW() HAL_GPIO_WritePin(A0_GPIO_Port,A0_Pin,GPIO_PIN_RESET)
#define DIGITAL_A0_HIGH() HAL_GPIO_WritePin(A0_GPIO_Port,A0_Pin,GPIO_PIN_SET)
#define DIGITAL_A1_LOW() HAL_GPIO_WritePin(A1_GPIO_Port,A1_Pin,GPIO_PIN_RESET)
#define DIGITAL_A1_HIGH() HAL_GPIO_WritePin(A1_GPIO_Port,A1_Pin,GPIO_PIN_SET)
#define DIGITAL_A2_LOW() HAL_GPIO_WritePin(A2_GPIO_Port,A2_Pin,GPIO_PIN_RESET)
#define DIGITAL_A2_HIGH() HAL_GPIO_WritePin(A2_GPIO_Port,A2_Pin,GPIO_PIN_SET)
#define DIGITAL_A3_LOW() HAL_GPIO_WritePin(A3_GPIO_Port,A3_Pin,GPIO_PIN_RESET)
#define DIGITAL_A3_HIGH() HAL_GPIO_WritePin(A3_GPIO_Port,A3_Pin,GPIO_PIN_SET)
#define DIGITAL_SER_LOW() HAL_GPIO_WritePin(SER_GPIO_Port,SER_Pin,GPIO_PIN_RESET)
#define DIGITAL_SER_HIGH() HAL_GPIO_WritePin(SER_GPIO_Port,SER_Pin,GPIO_PIN_SET)
#define DIGITAL_DISEN_LOW() HAL_GPIO_WritePin(DISEN_GPIO_Port,DISEN_Pin,GPIO_PIN_RESET)
#define DIGITAL_DISEN_HIGH() HAL_GPIO_WritePin(DISEN_GPIO_Port,DISEN_Pin,GPIO_PIN_SET)
#define DIGITAL_SHCP() do{HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);} while (0)
#define DIGITAL_STCP() do{HAL_GPIO_WritePin(DISLK_GPIO_Port, DISLK_Pin, GPIO_PIN_RESET);HAL_GPIO_WritePin(DISLK_GPIO_Port, DISLK_Pin, GPIO_PIN_SET);} while (0)
cpp
const uint8_t DigitalNum_Table[] = {0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xBE,0xE0,0xFE,0xF6,0xEE,0x3E,0x9C,0x7A,0x9E,0x8E, 0x00, 0x02};
void Digital_Show(uint8_t num, uint8_t point)
{
uint8_t number = DigitalNum_Table[num];
if (point == 1)
{
number++;
}
DIGITAL_DISEN_HIGH();
for (uint8_t i = 0; i < 8; i++)
{
if ((number >> i) & 0x01 == 0x01)
{
DIGITAL_SER_HIGH();
}
else
{
DIGITAL_SER_LOW();
}
DIGITAL_SHCP();
}
DIGITAL_STCP();
DIGITAL_DISEN_LOW();
}
定义数字显示结构体类型:
cpp
typedef struct
{
int8_t number;
uint8_t point;
}DigitalType;
周期调用数码管位选函数,配合单个数字显示,就可以动态扫描显示。
cpp
void Digital_CC(uint8_t channel)
{
Digital_Show(numbers[channel].number, numbers[channel].point);
switch (channel)
{
case 0:
{
DIGITAL_A0_LOW();
DIGITAL_A1_LOW();
DIGITAL_A2_LOW();
break;
}
case 1:
{
DIGITAL_A0_HIGH();
DIGITAL_A1_LOW();
DIGITAL_A2_LOW();
break;
}
case 2:
{
DIGITAL_A0_LOW();
DIGITAL_A1_HIGH();
DIGITAL_A2_LOW();
break;
}
case 3:
{
DIGITAL_A0_HIGH();
DIGITAL_A1_HIGH();
DIGITAL_A2_LOW();
break;
}
default:
break;
}
}
想要显示什么数字,就设置结构体数组的内容。
cpp
/**
* @param num means number
* @param pointPos which number have point,if -1 means no point
*/
void Digital_ShowNumber(int16_t num, uint8_t pointPos)
{
for (uint8_t i = 0; i < 4; i++)
{
numbers[i].number = 16;
numbers[i].point = 0;
}
if (pointPos != -1)
{
numbers[pointPos].point = 1;
}
if (num >= 0)
{
if (num < 10)
{
numbers[3].number = num;
}
else if (num < 100)
{
/* 99 */
numbers[2].number = num / 10 % 10;
numbers[3].number = num % 10;
}
else if (num < 1000)
{
/* 999 */
numbers[1].number = num / 100 % 10;
numbers[2].number = num / 10 % 10;
numbers[3].number = num % 10;
}
else if (num < 10000)
{
/* 9999 */
numbers[0].number = num / 1000 % 10;
numbers[1].number = num / 100 % 10;
numbers[2].number = num / 10 % 10;
numbers[3].number = num % 10;
}
else
{
}
}
else
{
num = 0 - num;
if (num < 10)
{
numbers[2].number = 17;
numbers[3].number = num;
}
else if (num < 100)
{
/* 99 */
numbers[1].number = 17;
numbers[2].number = num / 10 % 10;
numbers[3].number = num % 10;
}
else if (num < 1000)
{
/* 999 */
numbers[0].number = 17;
numbers[1].number = num / 100 % 10;
numbers[2].number = num / 10 % 10;
numbers[3].number = num % 10;
}
else
{
}
}
}