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

      }
   }
}
相关推荐
代码游侠7 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法
xuxg20059 小时前
4G 模组 AT 命令解析框架课程正式发布
stm32·嵌入式·at命令解析框架
CODECOLLECT11 小时前
京元 I62D Windows PDA 技术拆解:Windows 10 IoT 兼容 + 硬解码模块,如何降低工业软件迁移成本?
stm32·单片机·嵌入式硬件
BackCatK Chen12 小时前
STM32+FreeRTOS:嵌入式开发的黄金搭档,未来十年就靠它了!
stm32·单片机·嵌入式硬件·freertos·低功耗·rtdbs·工业控制
全栈游侠14 小时前
STM32F103XX 02-电源与备份寄存器
stm32·单片机·嵌入式硬件
Lsir10110_14 小时前
【Linux】中断 —— 操作系统的运行基石
linux·运维·嵌入式硬件
深圳市九鼎创展科技17 小时前
瑞芯微 RK3399 开发板 X3399 评测:高性能 ARM 平台的多面手
linux·arm开发·人工智能·单片机·嵌入式硬件·边缘计算
辰哥单片机设计17 小时前
STM32项目分享:车辆防盗报警系统
stm32·单片机·嵌入式硬件
風清掦18 小时前
【江科大STM32学习笔记-05】EXTI外部中断11
笔记·stm32·学习
小龙报18 小时前
【51单片机】从 0 到 1 玩转 51 蜂鸣器:分清有源无源,轻松驱动它奏响新年旋律
c语言·数据结构·c++·stm32·单片机·嵌入式硬件·51单片机