在进行课程2之前,先补一补数码管相关的知识。数码管,可以理解成摆成数字8形状的几个发光二极管组成的器件,在显示原理上,其实就是点亮对应的笔段的LED,实现不同数字的表示。点亮LED,需要根据LED的压降、电源电压,计算出需要的限流电阻的大小。切记,不能像点白炽灯那样直接把电压是加到LED上,很容易瞬间烧毁LED。对数码管也是一样的道理。根据驱动方式的不同,数码管有两种模式,共阴和共阳。共阴模式,表示所有笔段共用阴极,点亮不同笔段时,需要控制输出高电平给各个笔段的阳极;共阳模式,表示所有笔段共用阳极,点亮时不同笔段时,需要控制输出低电平给各个笔段的阴极;
为了方便驱动数码管,人们做出了对应的驱动集成块,典型的如4511,74HC595,前者是CMOS电路,输出能力有限,驱动数码管时需要加功率器件作为缓冲。而74HC595是高速硅栅CMOS器件和引脚兼容低功耗肖特基TTL(LSTTL),是8级串行移位寄存器与存储寄存器和三态输出。在SCK的上升沿,串行数据由SDL输入到内部的8位位移缓存器,并行输出则是在LCK的上升沿将在8位位移缓存器的数据存入到8位并行输出缓存器。当串行数据输入端OE的控制信号为低使能时,并行输出端的输出值等于并行输出缓存器所存储的值。
74HC595的引脚说明:
74HC595的处理逻辑真值表:

74HC595的工作方式:
第一步:目的:将要准备输入的位数据移入74HC595数据输入端上。
方法:送位数据到_595。
第二步:目的:将位数据逐位移入74HC595,即数据串入
方法:SH_CP产生一上升沿,将DS上的数据移入74HC595移位寄存器中,先送低位,后送高位。
第三步:目的:并行输出数据。即数据并出
方法:ST_CP产生一上升沿,将由DS上已移入数据寄存器中的数据送入到输出锁存器。
说明: 从上可分析:从SH_CP产生一上升沿(移入数据)和ST_CP产生一上升沿(输出数据)是二个独立过程,实际应用时互不干扰。即可输出数据的 同时移入数据。
用74HC595点亮数码管,只需要将合适的数据输出给75HC595,开放输出,完成对数码管各个笔段的控制,实现自己想要的数字显示效果。

活动中配套的数码管显示模块,使用了两组数码管模块和两个74HC595。数码管模块型号为3461BS1-7.3

原理图为

由原理图看,这是共阳数码管,显示数字0-9的段位码为:
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90
笔段输出高电平,笔段不亮;笔段输出低电平,笔段被点亮。
配套的数码管显示模组的原理图:

这个显示模组的构思很巧妙,一用一个74HC595的输出控制笔段,另一个74HC595控制数码管的位,只要配合好船型数据,就可以动态显示8个数字。而且模组的构成上,是可以做很多级联的。由于所有数码管共用A~G、小数点这个八个字段,因此一次只能显示一种字符。理论上可以同时点亮所有数码管为同一个字符
这个模块需要提供三个信号:
1、SCLK
这个是串行时钟信号,在时钟的上升沿,把串行数据送入移位寄存器。
2、RCLK
这个是锁存信号,在时钟的上升沿,将数据从移位寄存器存入存储寄存器,呈现到74HC595的Qn输出引脚上。
3、DIO
这个是串行数据输入端
这三个信号都是输入信号,对于开发板而言就是输出信号,刚好可以利用上次试验使用到的那三个驱动LED的信号,也就是PA13,PA26,PA27三个GPIO口。程序的处理逻辑如下:

实际上就是循环显示10 到0 的过程。由于8个笔段对所有数码管是共用的,所以显示10时,不能同时在两个数码管上显示,只能通过动态扫描方式显示。
主程序代码如下:
#include "ti_msp_dl_config.h"
void delay(uint32_t cnt);
void DispNum(unsigned char num, unsigned char pos);
/* This results in approximately 0.5s of delay assuming 32MHz CPU_CLK */
#define DELAY (16000000) // 500ms
#define ms50 (1600000) // 50ms
#define s1 (32000000) // 1s
#define ms1 (320) // 0.01ms模式延迟
// 16进制数字显示信史段码(0-9,A-F),段码位=1时,数码管的对应的笔段不会被点亮
unsigned char TAB_SEG[] = { 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x77, 0x83, 0xC6, 0xA1, 0x86, 0x8E, 0xFF, 0xBF };
// 数码管模块的显示位置,自左向右
unsigned char TAB_POS[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
// 发送数据给数码管模块用的串行时钟,时钟上升沿有效
#define SCLK_0 DL_GPIO_clearPins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN)
#define SCLK_1 DL_GPIO_setPins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN)
// 使数码管唯一寄存器数据被锁存到存储寄存器用的锁存信号,上升沿有效
#define RCLK_0 DL_GPIO_clearPins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_2_PIN)
#define RCLK_1 DL_GPIO_setPins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_2_PIN)
// 发送数据给数码管模块用的串行数据位
#define DIO_0 {DL_GPIO_clearPins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_3_PIN);}
#define DIO_1 {DL_GPIO_setPins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_3_PIN);}
void delay(uint32_t cnt) {
uint32_t d=cnt;
while(d--);
}
/**
* 显示一位数码管数据
* chr : 显示的数值字符(‘0’-‘9’,‘A’-‘F’)
* pos :显示的位置(最左侧开始:0-7, 对应的位置数据:0x80, 0x40,0x20,0x10,0x08,0x04,0x02,0x01)
* 暂时不考虑小数点的处理。数字后面有小数点的场合,相当于该数字的小数点笔段位清0
*/
void DispNum(unsigned char chr, unsigned char pos) {
unsigned char i, num;
// 根据字符,获取对应的段位码数据
if (chr>=0 && chr<16) {
num=TAB_SEG[chr];
} else if (chr>=' ') {
// 空格,所有笔段都不显示
num = 0xFF;
} else if (chr>='-') {
num = 0xBF;
} else {
return;
}
// 将段位码数据以串行方式发送给数码管显示模块
// 每个字符有八个笔段,小数点通常不用
for(i=0;i<8;i++) {
// 输出笔段对应的数据位
if ((num & 0x80)>0) {
// 笔段数据为1 的,DIO对应GPIO口输出高电平
DIO_1;
} else {
// 笔段数据为0 的,DIO对应GPIO口输出低高电平
DIO_0;
}
// 下一个笔段
num<<=1;
// 发出移位用串行时钟上升沿脉冲
SCLK_0;
delay_cycles(ms1);
SCLK_1;
delay_cycles(ms1);
}
// 发送完笔段数据,发送显示位置数据
num = TAB_POS[pos%8];
for(i=0;i<8;i++) {
// 输出对应的数据位
if ((num & 0x80)>0) {
DIO_1;
} else {
DIO_0;
}
// 下一个数码管位置
num<<=1;
// 发出移位用串行时钟上升沿脉冲
SCLK_0;
delay_cycles(ms1);
SCLK_1;
delay_cycles(ms1);
}
// 发出锁存信号,点亮数码管
RCLK_0;
delay_cycles(ms1);
RCLK_1;
delay_cycles(ms1);
}
int main(void) {
uint32_t i=0, j=0;
/* Power on GPIO, initialize pins as digital outputs */
SYSCFG_DL_init();
/* Default: LED1 and LED3 ON, LED2 OFF */
DL_GPIO_clearPins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_2_PIN);
DL_GPIO_setPins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN |
GPIO_LEDS_USER_LED_3_PIN |
GPIO_LEDS_USER_TEST_PIN);
DL_GPIO_clearPins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN | GPIO_LEDS_USER_LED_3_PIN | GPIO_LEDS_USER_TEST_PIN);
while (1) {
// 循环显示10递减到0 的过程
for (i=0; i<11; i++) {
if (i==0) {
// 因为笔段共用,10的显示不同于其他数字,只能通过动态扫描方式显示
for (j=0; j<1400; j++) {
DispNum(1, 6);
DispNum(0, 7);
}
} else {
// 显示字符9-0
DispNum(10-i, 7);
// 保持显示时长为1秒
delay_cycles(s1);
}
}
}
}运行效果

我要赚赏金
