【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
      {

      }
   }
}
相关推荐
ACP广源盛13924625673几秒前
M6/M5 Pro Mac mini 端侧 AI 爆发@ACP#YLB3118 存储扩展芯片在本地 AI 服务中的机会与落地场景
大数据·网络·数据库·人工智能·嵌入式硬件·macos
HUI-4741 小时前
EG1198|ESOP‑8 高性价比内置 MOS 降压 DC‑DC,10‑120V 小功率车载仪表优选
嵌入式硬件·硬件工程
智购科技自动贩卖机12 小时前
自动售货机嵌入式状态机设计实战:从45个事件源到层次型状态机的工程重构
大数据·人工智能·stm32·物联网·重构·硬件架构
长江后浪博客12 小时前
ESP32-SOLO-1 在 ESP-IDF v5.5 下启动不断重启问题分析与解决
单片机·嵌入式硬件·嵌入式·esp32·freertos·esp-idf
单片机仿真设计13 小时前
【proteus仿真】基于 STM32 单片机智能仓库设计(仿真图+程序)
stm32·单片机·嵌入式硬件·proteus·毕设
星游路13 小时前
单片机·电子时钟
单片机·嵌入式硬件
AOI小白新手上路17 小时前
江科协51单片机 7-2 LCD1602显示时钟实验
单片机·嵌入式硬件·51单片机
思麟呀17 小时前
嵌入式入门(一)宏观生态到首次烧录
c语言·嵌入式硬件
runningshark17 小时前
SC32L14GR8PJR
单片机·嵌入式硬件
智购科技无人售货机厂家17 小时前
2026自动售货机备用电池管理系统设计:从充放电保护到健康监测的工程实践~YH
大数据·linux·单片机·嵌入式硬件·微信