【STM32】 数码管驱动

一、简单介绍

数码管驱动电路如图所示,笔者选用安世半导体生产的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
      {

      }
   }
}
相关推荐
Joshua-a17 分钟前
高云FPGA在线调试/逻辑分析仪简要使用流程
嵌入式硬件·fpga开发·高云
国科安芯22 分钟前
高轨航天器抗辐照MCU选型约束分析
单片机·嵌入式硬件·性能优化·机器人·安全性测试
CS Beginner36 分钟前
【单片机】嵌入式显示屏开发框架:QT、SDL、LVGL 深度解析
单片机·嵌入式硬件·qt
YouEmbedded1 小时前
解码从架构到嵌套向量中断控制器(NVIC)
stm32·软件架构·mcu中断·exti外设·启动文件分析
亿道电子Emdoor1 小时前
【Altium】原理图中网络标签作用范围的设置
单片机·嵌入式硬件
风行男孩1 小时前
stm32基础学习——串口(USART)的基本使用
stm32·嵌入式硬件·学习
点灯小铭1 小时前
基于单片机的多模式档位调节与过热保护风扇设计
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
星源~2 小时前
Zephyr - MCU 开发快速入门指南
单片机·嵌入式硬件·物联网·嵌入式开发·zephyr
星源~2 小时前
zephyr-开发环境配置疑难问题解决
单片机·嵌入式硬件·物联网·项目开发
BMS小旭2 小时前
CubeMx-DMA
单片机·学习·cubemx·dma