STM32HAL库驱动数码管

这篇具有很好参考价值的文章主要介绍了STM32HAL库驱动数码管。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文档创建于2023年3月7日

本文记录了我学习数码管驱动的过程,实际是微机原理课上留的一个作业。

本文作者:RobotFreak

本文参考《NANO_STM32F103开发指南-HAL库版本_V2.0》,正点原子官网可下载。

数码管驱动原理

数码管,也称LED数码管,按发光二极管单元连接方式可分为“共阳极数码管”和“共阴极数码管”。我们使用的正点原子NANO STM32F103开发板板载的数码管为四位共阴极数码管,实物图于内部引脚图如下:

STM32HAL库驱动数码管

共阳极数码管是指将所有发光二极管的阳极接到一起,而共阴极数码管则是发光二极管的阴极连到一起,连接方式如下:

STM32HAL库驱动数码管

从上图可以看到,数码管为共阴时,当某一字段的发光二极管阳极为高电平时,响应字段就点亮,为共阳时,当某一字段的发光二极管阴极为低电平时,相应字段则点亮。所以通过点亮相对应的字段就可以显示我们需要的字符。 数码管要正常显示,就要用驱动电路来驱动数码管的各个端码,从而显示出我们要的字符,因此根据数码管的驱动方式不同,可以分为“静态式”和“动态式”两类。

静态显示驱动,也称为直流驱动。静态驱动是指每个数码管的每一个端码都有一个单片机的 I/O 端口进行驱动,或者使用如 BCD 码二-十进制译码进行驱动。静态驱动的优点是编程简单,显示亮度高,缺点是占用 I/O 端口多,如驱动 5 个数码管静态显示则需要 5×8=40 个 I/O 端口来驱动,要知道 STM32 单片机可用的 IO 端口是有限的,实际应用时必须增加译码器进行驱动,但会增加电路的复杂性。

动态显示驱动,是单片机应用中最为广泛的显示方式,动态驱动是将所有数码管的 8 个显示笔划“a,b,c,d,e,f,g,dp”的同名端连载一起,另外为每个数码管的公共级 COM 增加位选通控制电路,位选通由各自独立 IO 线控制,当单片机输出字形码时,所有数码管都接收到相同的字形码,但究竟是哪个数码管会显示出字形,取决于单片机对位选通 COM 端电路的控制,所有我们只要将需要显示的数码管的选通控制打开,改为就显示出字形,没有选通的数码管就不会亮。通过分时轮流控制各个数码管的 COM 端,就可以使各个数码管轮流显示。在轮流显示过程中,每位数码管的点亮时间为 1~2ms,由于人的视觉暂留现象及发光二极管的余辉效应,尽管实际上各位数码管并非同时点亮,只要扫描的速度够快,给人的印象就是一组稳定的显示数据,不会有闪烁感,动态显示的效果和静止显示是一样的,能够节省大量的 IO 端口,功耗降低。

这里我们使用动态驱动的方式驱动数码管,为了节省 IO,使用到驱动电路,段选数据使用 74HC595D 串行数据转并行数据输出芯片,位选数据使用 74HC138D三-八译码器芯片。 下面将介绍这两款芯片。

74HC595D

74HC595D 是恩智浦 NXP 公司推出的一款低噪声、低功耗、高速的 CMOS 移位寄存器, 能够驱动 15 个 LS-TTL 的负载。该器件包含一个 8 位串行输入、并行输出的移位寄存器及带有三态输出控制的 8 位 D 型存储器。74HC595D 的特点如下:

  1. 带存储功能的 8 位串行输入,并行输出的移位寄存器
  2. 工作电压范围宽:2V-6V
  3. 可级联使用

74HC595D 广泛应用于点阵屏和主控 IO 较少数据串行转并行的场合,74HC595D 的框图如下:

STM32HAL库驱动数码管

引脚说明

STM32HAL库驱动数码管

时序图

数据的串行输入需要按照规定的时间才能正常写入,根据上面讲解,我们要知道的是 SH_CP 上升沿高电平和 ST_CP 正脉冲保持的时间,如下图:

STM32HAL库驱动数码管

从上图可以看到时序的时间都是 ns 级别的,在写软件时我们只需要几 us 的时间就可以了。 通过 74HC595D 的使用,我们就可以以串行数据输入,并行数据输出控制数码管的端选段, 从而显示对应的字符。

74HC138D

74HC138D 是恩智浦 NXP 公司推出的一款高速 CMOS、低功耗的 3-8 译码器。通过三个地 址的输入设置,可选择对应八种的状态输出。74HC138D 的特点如下

  1. 低功耗

  2. 工作电压范围宽:3V-5V

74HC138D 广泛应用于消费类电子产品,74HC138D 的框图如下:

STM32HAL库驱动数码管

引脚说明

STM32HAL库驱动数码管

真值表

Y0~Y7 的输出是 A0~A2 的设置的,而它们是依照 3-8 译码形式设置,以下是它们工作的真值表:

STM32HAL库驱动数码管

从图可以看到,当/E1、/E2、E3 使能端使能后,设置 A0、A1、A2 的输入(高电平有效), /Y0~/Y7 都会有对应的状态输出(低电平),例如 A0、A1、A2 设置的是(A2=0,A1=1,A2=1), 根据 BCD-421 码的换算,代表是 3,则 Y3 输出有效电平 L,其他的都输出为无效电平 H。设 置(A2=1,A1=1,A0=1),代表是 7,则 Y7 输出有效电平 L,其他的都输出为无效电平 H。 通过 74HC138D 的使用,我们就可以控制对应数码管的位选端了。

硬件部分

我使用的是正点原子的NANO STM32F103实验板,板子上的原理图如下:

STM32HAL库驱动数码管

STM32HAL库驱动数码管

原理图中74HC595D芯片标的引脚标号名称可能与芯片手册标的有点不一样,以下是引脚对应标号关系:

STM32HAL库驱动数码管

从上方的原理图可以看到,74HC138D 的使能端引脚默认已上拉或下拉硬件使能, 74HC595D 的 RST 复位引脚与开发板的复位线相连接,当按下开发板的复位按键或首次上电即可对 74HC595D 的芯片的数据清零,以到达复位的作用。由于没有做级联的功能,SDO 引脚上做了悬空处理。而使能端引脚也同样做了默认硬件使能。

在数码管中,两个数码管的 A~DOT 段选段都与 74HC595D 芯片的 QA~QH 相连接,而数码管的 CH1~CH4 位选端则单独分别与74HC138D 芯片的 Y0~Y7 引脚相连接。通过控制 74HC595D 输出的段码和控制 74HC138D 输出的位选就可以实现选择点亮数码管。

段选即一位数码管显示的符号,决定一位数码管的哪几段点亮,显示相应字符。位选决定数码管哪一位点亮。NANO板上使用的数码管为四位数码管,一个数码管模块有4位,共有2个模块。

软件部分

代码部分参考了正点原子官方HAL库例程。重点在于明白数码管的驱动代码,明白数码管是如何驱动起来的

CubeMX配置

CubeMX中选择NANO板对应的型号STM32F103RCTx,时钟配置如下:

STM32HAL库驱动数码管

GPIO选择了数码管用到的几个进行了配置,初始化为不影响使用时的状态:

STM32HAL库驱动数码管

启用了TIM2时钟,分频系数设为72-1,则TIM2内计数器的频率为1MHz,也即1us计一个数,这个定时器用来延时,不产生中断:

STM32HAL库驱动数码管

Keil代码

数码管驱动代码如下:

smg.h

#ifndef __SMG_H__
#define __SMG_H__

#include "stm32f1xx_hal.h"

/**
 * @brief   设定数码管控制的位
 * @param   num 要控制的数码管编号0~7(共8个数码管)
 * @details 设定数码管要控制哪一位,这个数字与输出有效的74HC138
 *          Y0~7的编号一致,也就是说num就是a2a1a0拼起来之后对应的十进制形式
 *          那么我们将num的二进制形式的最低三位取出来,就是a2a1a0的值
 */
void setDigitalTubeBit(uint8_t num);

/**
 * @brief   向HC595中写入数据
 * @param   seg 段segment,写入的段码数据
 * @param   num 数码管位的编号,0~7(共8个数码管)
 * @details 将段码写入HC595的移位寄存器,还没有输出
 */
void writeData2ShiftRegister(uint8_t seg, uint8_t num);

/**
 * @brief   将写入HC595的数据输出到数码管
 * @param   None
 * @details LCLK产生上升沿,将移位寄存器数据放入数据寄存器,输出到数码管
 */
void writeData2DigitalTube(void);

#endif

smg.c

#include "smg.h"
#include "tim.h"
#include "sys.h"
/**
 * 引脚对应
 * PB3  <-> HC595 DATA(SDI/DS)
 * PB4  <-> HC595 LCLK(STCP)
 * PB5  <-> HC595 SCLK(SHCP)
 * PC10 <-> HC138 A0
 * PC11 <-> HC138 A1
 * PC12 <-> HC138 A2
*/

/**
 * @brief   设定数码管控制的位
 * @param   num 要控制的数码管编号0~7(共8个数码管)
 * @details 设定数码管要控制哪一位,这个数字与输出有效的74HC138
 *          Y0~7的编号一致,也就是说num就是a2a1a0拼起来之后对应的十进制形式
 *          那么我们将num的二进制形式的最低三位取出来,就是a2a1a0的值
 */
void setDigitalTubeBit(uint8_t num)
{
	//一个二进制数与上0总是0,与上1还是它本身
	uint8_t bit0 = num & 0x01;      //取第一位
	uint8_t bit1 = (num&0x02) >> 1; //取第二位
	//int bit1 = (num >> 1) & 0x01; //与上一行操作等价
	uint8_t bit2 = (num&0x04) >> 2; //取第三位
	//int bit2 = (num >> 2) & 0x01; //与上一行操作等价
	//写入引脚
	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, bit0);
	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, bit1);
	//一开始上面的bit2是右移1位,当num第三位为1时,bit2是0x02,并不是我们想要的0或者1.现在改为了正确的右移两位
	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, bit2); //使用库函数时,即使输入的不为1,根据非零为真的原则,也会输出高电平.但是日常使用时应该规范使用0/1表示假和真
	//PCout(12) = bit2;                          //直接用位带操作时,输入就是0/1,当bit2为0x02时这一位输出出来还是0
}

/**
 * @brief   向HC595中写入数据
 * @param   seg 段segment,写入的段码数据
 * @param   num 数码管位的编号,0~7(共8个数码管)
 * @details 将段码写入HC595的移位寄存器,还没有输出
 */
void writeData2ShiftRegister(uint8_t seg, uint8_t num)
{
	uint8_t i;
	for(i = 0; i < 8; i++) //先写段码,一共8位输出
	{
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, (seg>>i)&0x01); //将seg从最低位开始一位一位取出来,写入DS(串行数据输入),进入移位寄存器
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, 0); //SCLK写入0;初始化是1,此处产生一个下降沿
		delayNus(5); //延时5us
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, 1); //SCLK写入1.此处产生一个上升沿,数据输出移位
	}
	setDigitalTubeBit(num); //选中位
}

/**
 * @brief   将写入HC595的数据输出到数码管
 * @param   None
 * @details LCLK产生上升沿,将移位寄存器数据放入数据寄存器,输出到数码管
 */
void writeData2DigitalTube(void)
{
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, 1); //产生上升沿
	delayNus(5); //延时5us
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, 0); //恢复到低电平
}

main.c中main()函数的代码如下:

/* USER CODE BEGIN PV */
// 0,1,2,3,4,5,6,7,8,9
uint8_t smgNum[] = {0xfc, 0x60, 0xda, 0xf2, 0x66, 0xb6, 0xbe, 0xe0, 0xfe, 0xf6};

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  /* USER CODE BEGIN 2 */
	uint8_t smgBit = 0; //位选
	uint8_t smgSeg = 0; //段选
	uint16_t t = 0;

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		writeData2ShiftRegister(smgNum[smgSeg], smgBit);
		writeData2DigitalTube();
		smgBit++;
		if(smgBit == 8)
			smgBit = 0;
		t++;
		if(t == 1000)
		{
			t = 0;
			smgSeg++;
			if(smgSeg == 10)
				smgSeg = 0;
		}
    HAL_Delay(1); //延时1ms,不像2ms时会出现频闪.
  }
  /* USER CODE END 3 */
}

实现效果

实现的效果如下,八位数码管显示同一个值,每过1s更新一次数码管的值:

STM32HAL库驱动数码管文章来源地址https://www.toymoban.com/news/detail-482620.html

到了这里,关于STM32HAL库驱动数码管的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 【洋桃一号板】STM32F103CBT6标准库函数驱动TM1640点亮数码管

    【洋桃一号板】STM32F103CBT6标准库函数驱动TM1640点亮数码管

    一、今天介绍如何使用STM32F103CBT6驱动TM1640点亮数码管,硬件用的洋桃开发板,点亮后效果如下,六个数码管依次显示0.1.2.3.4.5.6.7 硬件原理图如下,只用到了单片机的两个IO口即可实现上图的效果,该开发板上用的是PA11和PA12两个IO口,用来模拟IIC通信,其中PA11接SCLK,PA12接D

    2024年02月16日
    浏览(6)
  • STM32 数码管显示

    STM32 数码管显示

    一 认识二级管 常用的二级管分为两种 1,(b)图共阴极结构:是把所有 LED 的阴极作为公共端(COM) 连起来,接低电平,通常接地。通过控制每一个 LED 的阳极电平使其发光或熄灭,阳极为高电平时LED 发光,为低电平时 LED熄灭。如显示数字0时,a、b、ad.e、t端为高电平,其他各

    2024年02月08日
    浏览(12)
  • STM32-GPIO数码管动态显示

    STM32-GPIO数码管动态显示

    目录 一、数码管原理 1、LED数码管的结构 2、LED数码管工作原理 3、数码管动态显示 1)动态显示的概念 2)动态显示的接口 二、代码的实现 三、仿真结果展示   本篇文章将继续进一步了解GPIO外设输出模式 知道这一部分的朋友可以直接点击目录部分跳过这段跳过 ,这里介绍

    2023年04月08日
    浏览(10)
  • STM32 4位数码管和74HC595

    STM32 4位数码管和74HC595

            在使用一位数码管的时候,会用到8个IO口,那如果使用4位数码管,难道要使用32个IO口吗?肯定是不行的,太浪费了IO口了。把四个数码管全部接一起共用8个IO口,然后分别给他们一个片选。所以4位数码管共有12个IO口。         当选择数码管1显示的时候,这可以

    2024年04月17日
    浏览(16)
  • 基于STM32的四位数码管计数器设计与实现

    基于STM32的四位数码管计数器设计与实现

    ✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进, 代码获取、问题探讨及文章转载可私信。  ☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。 🍎获取更多嵌入式资料可点击链接进群领取,谢谢支持!👇 点击领取更多详细资料 本文介绍了一种基于STM

    2024年02月02日
    浏览(10)
  • stm32使用四位数码管制作简易时钟(库函数版)

    stm32使用四位数码管制作简易时钟(库函数版)

    1.数码管情况介绍 数码管接线引脚:    段码与上图情况,位选为:1-PB0,2-PB12,3-PB13,4-PB14。 本项目使用5461BS-1共四位数码管,为共阳型。  2.程序部分 Timer定时器: SMG数码管 main主函数 资料参考: (75条消息) STM32F103C8T6 I/O口驱动4位共阳数码管_io口控制数码管_seaup2011的博客-CSDN博

    2024年02月08日
    浏览(48)
  • arm学习stm32之spi总线数码管倒计时

    arm学习stm32之spi总线数码管倒计时

    由于时间没有用时间计时器操作,有些误差,后续有空会翻新计时器版本 main.c spi.c spi.h

    2024年02月13日
    浏览(11)
  • 基于STM32单片机的温度报警器(数码管)(Proteus仿真+程序)

    基于STM32单片机的温度报警器(数码管)(Proteus仿真+程序)

            本设计由STM32F103单片机最小系统+DS18B20温度传感器+数码管显示模块+声光报警模块+独立按键组成。 1、主控制器是STM32F103单片机 2、DS18B20温度传感器测量温度 3、数码管显示温度值,精度0.1摄氏度 4、三个按键可设置温度上限、下限报警值,温度超过上限、或者温度低

    2024年02月07日
    浏览(22)
  • arm学习stm32之spi总线数码管倒计时,裸机开发,soc

    arm学习stm32之spi总线数码管倒计时,裸机开发,soc

    由于时间没有用时间计时器操作,有些误差,后续有空会翻新计时器版本 main.c spi.c spi.h

    2024年02月16日
    浏览(4)
  • 基于STM32的时钟设计并在六位数码管上显示附proteus仿真

    基于STM32的时钟设计并在六位数码管上显示附proteus仿真

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。 提示:以下是本篇

    2024年02月12日
    浏览(9)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包