相信很多玩STM32的小伙伴都用过数码管来做什么数字时钟、数字秒表、数字计数器等等数显的有趣好玩的东西;我这里就简单说明一下对数码管的理解和应用吧。先上图给大家看看我的数字字母滚动显示屏效果吧!
单片机:STM32F103C8T6最小系统板
开发环境:keil MDK
开发模块:2个74HC595通过级联控制的8位数码管
对于初学者来说,数码管是一个很简单却又不简单的东西,应用场景非常多,对于一些普通的数码管我了解到的大概有以下这些:
那么我们先从最简单的来分析:
先从一位的共阳(BS)数码管来看
首先怎么检测共阳的数码管呢?可以直接用万用表:红表笔接电源正极,黑表笔接电源负极,档位打到电阻档或者短路档,单个的数码管一般有10个引脚,其中两个是地,可以用红表笔随便先接一个脚不动,黑表笔一个个点找到地就会亮,然后移动红表笔,你就能找你需要的脚位了。
接下来就是共阴(AS)数码管了
那共阴数码管怎么检测呢?参照上述方法,这里给大家一个思考的机会,欢迎评论区留言?
段选举例:一位8段LED数码管显示
那么如图所示,上面的abcdefg和小数点‘·’分别代表数码管的每一段,与刚才说的8位数码管要注意区分,简单来说一位数码管有8段LED,这么多段都可以通过自由组合亮灯的方式成为想要显示的数字或者字母;点亮过灯的应该都知道,这样一个GPIO控制一段LED会占用很多的IO口,而且每一段的led并不是同时高亮的,还是需要个先后顺序;只要扫描的速度变化足够快,就可以通过人眼的视觉暂留现象(约为0.1~0.4秒)以及发光二极管亮灭的余晖效应给人一种稳定显示的效果,变化太慢的话这个显示效果也不好,所以怎样选择这个变化的时间呢?根据某科学词条说法,人眼一般的静态和动态转化频率在24hz左右;这么说,是不是流水灯的频率达到一定程度就会看成全部高亮呢?
位选举例:两位8段LED数码管显示
那么一位数码管的段选显示大家应该都掌握了吧,那么如何让两位8段的数码管同时显示呢?这就涉及到模电上的知识了,其实只要用两个三极管就可以了,为什么用三极管?问得好,先复习一下三极管的知识,晶体三极管导通时有着电流放大的特性,能以基极电流微小的变化来控制集电极电流较大的变化;我们知道数码管每一段LED发光的导通电流大约在5~10mA左右,全部显示就是40到80mA了,我所用的单片机的引脚输出电流最大值是25mA,所以要额外用两个IO口来控制两位LED数码管最好是每一个IO口接一个三极管放大电流,这就是位选的硬件实现了(当然网上也有加上拉电阻等方式增大单片机的引脚输出电流,这里就不多说了);
除此之外如果你需要控制一个数码管,那么不可避免的是你需要8个引脚输出不同的高低电平来让每一段高亮或者暗,硬件上很占资源;从软件程序上来看,要让这么一位数码管显示不同的数字字母就要给8个GPIO分别GPIO_Setbit()和GPIO_Resetbit(),那这个时候就可以用74HC595这个串行输入并行输出的移位缓存器了(详情需要看规格书了)。
话不多说,直接进入主题,如何控制一个8位LED模块呢?
首先我买的是2个74HC595通过级联控制的8位数码管(可多块级联,最多尝试了4块8位数码管级联显示ADC采集的不同数据,可正常显示,不过工作电流非常大足足100mA左右)
接线: VCC
DIO (数据线)----------------------------------PA5
SCLK(数据输入时钟线)--------------------PA6
RCLK(输出存储器锁存时钟线)-----------PA7
GND
下面贴出部分代码
LED_8bits.c
#include "LED_8bit.h"
#define DIO PAout(5)
#define SCLK PAout(6)
#define RCLK PAout(7)
#define LED_segment 19
#define LED_bit 8
unsigned char fseg[LED_bit] = {
//共阴
0x80,0x40,0x20,0x10, 0x08,0x04,0x02,0x01
};
unsigned char segbit[LED_segment] = {
//共阴 数码管显示数字和字母
// /*0~9*/
// 0x3F ,0x60,0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F,0x6F,
// /*A~F*/ /*。 - 不显示*/
// 0X77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x80, 0x40, 0x00
//共阳 数码管显示数字和字母共阳和共阴的是取反的关系
/*0~9*/
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80,0x90,
/*A~F*/ /*。 - 不显示*/
0X88, 0x83, 0xC6, 0xA1, 0x86, 0x8E, 0x7F, 0xBF,0xFF
};
//**************************************************错误码
unsigned char error_num_wei[LED_bit] = {
//共阴
0x80,0x40,0x20,0x10, 0x08,0x04,0x02,0x01
};
char segment_buf[8];
void write_num(u16 temp)
{
u8 i;
for(i=0;i<8;i++)
{
if(temp & 0x80)
{
DIO = 1;
}
else
{
DIO = 0;
}
temp <<= 1;
SCLK = 0;
SCLK = 1;
}
}
void show_num(void)//0~F滚动显示
{
u8 i=0,n=0,m=0;
if(time >= 1000)
{
time = 0;
if((n<=16) && (m <= 7))
{
for(n=0;n<=16;n++)
{
segbit[n] = segbit[n+1];
fseg[m] = fseg[n];
m++;
}
}
else
{
segbit[0] = segbit[16];
fseg[0] = fseg[7];
}
}
for(i=0;i<8;i++)
{
write_num(segbit[i]);//段
write_num(fseg[i]);//位
RCLK=0;
RCLK=1;
}
}
int main(void)
{
delay_init(); //延时函数初始化
LED_Init();
key_init();
while(1)
{
show_num();
}
}
LED_8bits.h
#ifndef __LED_8BIT_H
#define __LED_8BIT_H
#include "sys.h"
void show_num(void);
void write_num(u16 temp);
以上就是本人对8位LED数码管显示模块的大致理解,或许理解还不到位或者还没见识到更高级的处理,需要大家多多指出和相互交流。
本文不足之处希望大家在评论区多多指出,非常感谢。