前言
最近用到了188数码管,总结一下。
188数码管,用5个IO,在不借助外部驱动芯片的情况下,可以点亮20个灯。188数码管广泛应用于电子烟、充电器、充电宝、DVD、高级音响、工业设备控制面板、医疗器械等多个领域,满足不同设备和场景的需求。
有纰漏请指出,转载请说明。
学习交流请发邮件 1280253714@qq.com。
原理讲解
参考自文章 188数码管驱动程序(简洁)_188数码管电路图-CSDN博客
讲解非常到位,移植也很简单
这里我再给出数码管的顶层应用示例,即开、关、闪烁
代码
LED.H
#ifndef LED_H
#define LED_H
#include "SYS.h"
void LED_Init(void);
void Display_tube(void);
typedef enum {
eLedOff = 0,
eLedOn,
eLedIntermittent,
} LedSta_S;
typedef struct {
u16 period; //闪烁的周期
u16 time; //闪烁的次数
u16 cnt1; //临时计数1
u16 cnt2; //临时计数2
LedSta_S sta;
} LED_S;
extern LED_S stLed;
void LedSet(LedSta_S sta, u16 period, u16 time);
void LedLoopTask(void);
#endif
LED.C
#include "led.h"
/************************************************************************************/
void LED_Init(void)//初始化IO口
{
PIN1_IN();//把单片机IO口配置为输入模式
PIN2_IN();
PIN3_IN();
PIN4_IN();
PIN5_IN();
}
/********************************熄灭所有数码管***********************************/
void Set_AllPin_INPUT(void)
{
PIN1_IN();
PIN2_IN();
PIN3_IN();
PIN4_IN();
PIN5_IN();
}
u16 display_sram=0;
void Display_Scan1(void)
{
PIN1_L();//拉低Pin1
if(display_sram&0x8000)
PIN2_H();
if(display_sram&0x4000)
PIN3_H();
if(display_sram&0x2000)
PIN4_H();
if(display_sram&0x1000)
PIN5_H();
}
void Display_Scan2(void)
{
PIN2_L();
if(display_sram&0x0800)
PIN1_H();
if(display_sram&0x0400)
PIN3_H();
if(display_sram&0x0200)
PIN4_H();
if(display_sram&0x0100)
PIN5_H();
}
void Display_Scan3(void)
{
PIN3_L();
if(display_sram&0x0080)
PIN1_H();
if(display_sram&0x0040)
PIN2_H();
if(display_sram&0x0020)
PIN4_H();
if(display_sram&0x0010)
PIN5_H();
}
void Display_Scan4(void)
{
PIN4_L();
if(display_sram&0x0008)
PIN1_H();
if(display_sram&0x0004)
PIN2_H();
if(display_sram&0x0002)
PIN3_H();
if(display_sram&0x0001)
PIN5_H();
}
void Display_Scan5(void)
{
PIN5_L();
if(stSys.chargingFlag) {
PIN2_H();
PIN3_H();
} else {
PIN2_H();
}
}
/****************************显示函数***********************************/
//放在定时器中断函数,5ms运行一次,扫描一轮需要4*5ms=20ms,
//也就是50Hz的刷新频率,如果感觉闪烁,可以4ms运行。
void Display_tube(void)
{
u16 Segment[3][11]={
{0x0000,0x0006,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},//百位
{0x0770,0x0420,0x0741,0x0661,0x0431,0x0271,0x0371,0x0460,0x0771,0x0671,0x0000},//十位
{0xE888,0x8080,0xD808,0xD880,0xB080,0x7880,0x7888,0x8880,0xF888,0xF880,0x0000} //个位
};
static u8 case_cnt = 0;//逐行扫描
Set_AllPin_INPUT();//消影作用
//display_sram=0x84A6;//111
//display_sram=0xDF49;//022
//display_sram=0xE888;//0
display_sram=Segment[0][stSys.tube_bai] | Segment[1][stSys.tube_shi] | Segment[2][0];//显示百位,十位,个位
switch(case_cnt)
{
case 0x00:Display_Scan1();case_cnt++;break;
case 0x01:Display_Scan2();case_cnt++;break;
case 0x02:Display_Scan3();case_cnt++;break;
case 0x03:Display_Scan4();case_cnt++;break;
case 0x04:Display_Scan5();case_cnt=0;break;
default:case_cnt=0;break;
}
}
LED_S stLed;
void LedSet(LedSta_S sta, u16 period, u16 time)
{
stLed.period = period;
stLed.time = time;
stLed.sta = sta;
stLed.cnt1 = 0;
stLed.cnt2 = 0;
}
//此函数放在主循环,
void LedLoopTask(void)
{
static u8 tubeTaskCnt = 0;
tubeTaskCnt++;
if (tubeTaskCnt <= 2) {
return;
}
tubeTaskCnt = 0;
switch ( stLed.sta )
{
case eLedOn:
Display_tube();
break;
case eLedOff:
Set_AllPin_INPUT();
break;
case eLedIntermittent:
if(stLed.cnt1 < (stLed.period/2)){
Set_AllPin_INPUT();
stLed.cnt1++;
} else if(stLed.cnt1 < stLed.period){
Display_tube();
stLed.cnt1++;
} else {
stLed.cnt1 = 0;
stLed.cnt2++;
if (stLed.cnt2 >= stLed.time) {
stLed.cnt2 = 0;
stLed.sta = eLedOff;
}
}
break;
}
}
函数调用
/********************************************
* @函数名 SetLedSta
* @描述 设置Led灯闪状态
* @参数 无
* @返回值 无
* @注意 无
********************************************/
void SetLedSta(void)
{
if (stSys.ledUpdateFlag == 0)
return;
stSys.ledUpdateFlag = 0;
switch (stSys.sta.now)
{
case eStaOverLoad:
case eStaLowVolt:
LedSet(eLedIntermittent,320,5);
break;
case eStaRun:
case eStaOffChging:
LedSet(eLedOn,0,0);
break;
case eStaCalib:
LedSet(eLedIntermittent,320,6);
break;
default:
LedSet(eLedOff,0,0);
break;
}
}