目录
1. 单位数码管概述
数码管的内部基本单元是发光二极管,数码管是发光器件之一,内部由七个条形发光二极管(a、b、c、d、e、f、g)和一个圆点发光二极管(dp)构成。
按照数码管的公共接线不同,数码管又可分类为共阴极数码管和共阳极数码管两种,共阴极数码管的公共端接地,而共阳极数码管的公共端接电源。
2. 对应编码
2.1 共阳数码管
数码管中所有的正极连接在一起,这个端口被称之为位选端口,其余的数码管引脚a-h都为段选端口2、共阳极数码管的编码(CA):
u8 code[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}; //0-F
2.2 共阴数码管
是数码管所有的负极连接在一起,这个端口被称之为位选端口,其余的数码管引脚a-h都为段选端口4、共阴极数码管的编码(CC/CK):
u8 code[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; //0-F
3. SN74HC595驱动数码管
3.1 工作原理
74HC595是一个8位串行输入、平行输出的位移缓存器:平行输出为三态输出。
在SCK的上升沿,单行数据由SDL输人到内部的8位位移缓存器,并由Q7`输出,而平行输出则是在LCK的上升沿将在8位位移缓存器的数据存入到8位平行输出缓存器。
当串行数据输入端OE的控制信号为低使能时,平行输出端的输出值等于平行输出缓存器所存储的值而当OE为高电位,也就是输出关闭时,平行输出端会维持在高阻抗状态。
管脚编号 | 管脚名 | 说明 |
1、2、3、4、5、6、7、15 | Q1、Q2、Q3、Q4、Q5、Q6、Q7、Q0 | 8位并行数据输出(三态输出管脚) |
8 | GND | 电源地 |
9 | Q7’ | 串行数据输出,级联输出端,接下一个595的DS端(串行数据输出管脚) |
10 | MR(SCLR) | 低电平有效,清空移位寄存器中已有的数据,一般不用,接高电平即可(移位寄存器清零端) |
11 | SH_CP(SCK) | 移位寄存器时钟引脚,上升沿时,移位寄存器中的数据整体后移,并接受新的数据(从DS输入)(数据输入时钟线) |
12 | ST_CP(RCK) | 存储寄存器时钟输入引脚。上升沿时,数据从移位寄存器转存带存储寄存器(输出存储器锁存时钟线) |
13 | OE | 低电平有效,输出使能控制脚 |
14 | DS | 串行数据输入引脚(数据线) |
16 | VCC | 电源端 |
3.2 使用步骤
74HC595是将数据串转并的,也就是数据(8bit)串行输入,并行输出。
3.2.1 数据传输
先把要传输的数据(8bit)从引脚14(DS)输入到74HC595。
3.2.2 将数据移入移位寄存器
将从DS上的数据串行移入移位寄存器,需要时钟驱动,即引脚11 (SHCP)每产生一个上升沿, DS上的数据往移位寄存器送入一位,先送高位,后送低位,经过8个上升沿后, 8bit全部送入移位寄存器了。
3.2.3 将移位寄存器里的数据送入存储寄存器
将移位寄存器里的数据送入存储寄存器,引脚12 (STCP)产生一个上升沿后,该操作就完成了。
3.2.4 数据锁存
引脚13 (OE)为低电平,则步骤3送入存储寄存器的8bit数据(一个字节)就在Q7-Q0并行输出,并输出的数据会被所存起来。
注意:数据并行输出后,只要没有数据更新进来,原输出的数据保持不变,就是所谓的锁存(数据被锁存住)。在完成步骤123后,只要步骤4还没使能,输出都是保持不变的,当OE一使能,新的数据就输出覆盖旧输出。
3.3 运用
3.3.1 四位数码管模块使用
四位数码管电路图:
3.3.2 八位数码管模块使用
图中是8位数码管的电路图,与4位相似,都具有两片595驱动芯片,两片595级联在一起,第二片595(U4)是对数码管的8段码进行段码操作,第一片595(U3)是对8位数码管进行位选操作,即选择哪一个数码管进行显示操作。
虽然595具有存储寄存器,但是只能对一位数码管的数据进行数据锁存。
4. STM32F103C8T6代码编写
4.1 宏定义相关
为了方便后续代码的更改,我们可以对所用引脚进行宏定义:
/************************************************************************************
接线
74HC595_4位数码管模块-------------------------STM32F103C8T6
VCC------------------------------------------3.3/5V
GND------------------------------------------GND
DIO------------------------------------------GPIOA_0
RCK------------------------------------------GPIOA_1
SCLK-----------------------------------------GPIOA_2
*****************************************************************************************/
#define DIO_GPIO_PORT GPIOA
#define DIO_GPIO_CLK RCC_APB2Periph_GPIOA
#define DIO_GPIO_PIN GPIO_Pin_0
#define RCK_GPIO_PORT GPIOA
#define RCK_GPIO_CLK RCC_APB2Periph_GPIOA
#define RCK_GPIO_PIN GPIO_Pin_1
#define SCLK_GPIO_PORT GPIOA
#define SCLK_GPIO_CLK RCC_APB2Periph_GPIOA
#define SCLK_GPIO_PIN GPIO_Pin_2
#define DIO_1 GPIO_SetBits(DIO_GPIO_PORT, DIO_GPIO_PIN)
#define DIO_0 GPIO_ResetBits(DIO_GPIO_PORT, DIO_GPIO_PIN)
#define RCK_1 GPIO_SetBits(RCK_GPIO_PORT, RCK_GPIO_PIN)
#define RCK_0 GPIO_ResetBits(RCK_GPIO_PORT, RCK_GPIO_PIN)
#define SCLK_1 GPIO_SetBits(SCLK_GPIO_PORT, SCLK_GPIO_PIN)
#define SCLK_0 GPIO_ResetBits(SCLK_GPIO_PORT, SCLK_GPIO_PIN)
4.2 引脚初始化
这里对PA0、PA1、PA2进行初始化,期间使用的宏定义,要想更改引脚只需更改宏定义引脚即可(注意:若是使用其他外设时钟例如PB,不要忘记对其进行使能)。
void HC595_GPIO_Config(void)
{
/*定义一个MAX7219_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
/*开启LED相关的GPIO外设时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
/*选择要控制的GPIO引脚*/
GPIO_InitStructure.GPIO_Pin = DIO_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DIO_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = RCK_GPIO_PIN;
GPIO_Init(RCK_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = SCLK_GPIO_PIN;
GPIO_Init(SCLK_GPIO_PORT, &GPIO_InitStructure);
}
4.3 数据写入移位寄存器
将从DS上的数据串行移入移位寄存器,需要时钟驱动,即引脚11 (SHCP)每产生一个上升沿, DS上的数据往移位寄存器送入一位,先送高位,后送低位,经过8个上升沿后, 8bit全部送入移位寄存器了。
void Write_74HC595_byte(uint8_t DATA)
{
uint8_t i;
// 遍历每一位,从最高位到最低位
for(i = 8; i > 0; i--) // 修正循环条件
{
// 设置数据线的电平
if(DATA & 0x80)
{
DIO_1; // 设置数据线为高电平
}
else
{
DIO_0; // 设置数据线为低电平
}
// 左移数据以处理下一个比特
DATA = DATA << 1;
// 生成时钟脉冲
SCLK_0;
SCLK_1;
}
}
对于以下代码为什么这样,可以先了解一下与运算符:
// 设置数据线的电平
if(DATA & 0x80)
{
DIO_1; // 设置数据线为高电平
}
else
{
DIO_0; // 设置数据线为低电平
}
C语言菜鸟入门·运算符(算数运算符,关系运算符,逻辑运算符,位运算符,赋值运算符,三目运算符)详细介绍_算术运算符,逻辑运算符和关系运算符-CSDN博客
DATA & 0x80,这会将 DATA 的最高位与 0x80 进行按位与操作。
如果DATA 的最高位为 1,则结果会是 0x80 ,即10000000(非零值)。
如果DATA 的最高位为 0,则结果会是 0x00 (零值)。
4.4 共阳极数码管编码
unsigned char LED_DIS[] =
{// 0 1 2 3 4 5 6 7 8 9 A b C d E F -
0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x8C,0xBF,0xC6,0xA1,0x86,0xFF,0xbf
};
4.5 数据位选
首先,通过调用Write_74HC595_byte();函数,获取对应的要显示数据,然后通过Write_74HC595_byte(1 << (3 - Addr));生成一个位掩码,用于选择显示器的特定位置。
假设
Addr
的值是 0 到 3 之间的整数,它会生成一个 8 位值,其中只有一个位被设置为 1,其余为 0。例如,Addr
为 0 时生成的掩码是00001000
,Addr
为 1 时生成的掩码是00000100
,以此类推。
//Addr:显示位置,Dat:显示的数据
void Nixie_Display (uint8_t Addr, uint8_t Dat)
{
// 将数据转换为对应的七段显示器的编码
Write_74HC595_byte(LED_DIS[Dat]);
// 选择要显示的位,通过左移来选择对应的显示位置
Write_74HC595_byte(1 << (3 - Addr));
// 产生一个脉冲来更新显示
RCK_0;
RCK_1;
}
4.6 主函数
此时数码管第1位显示1,第二位显示2以此类推:
#include "stm32f10x.h"
#include "74HC595.h"
#include "delay.h"
int main(void)
{
uint8_t n;
HC595_GPIO_Config();
while (1)
{
Nixie_Display (0,1);
Nixie_Display (1,2);
Nixie_Display (2,3);
Nixie_Display (3,4);
}
}
完整代码: