188数码管显示问题
求大佬帮助!在使用188数码管显示数字时,可能因为使用查理复用原理导致拉高拉低过快,导致数码管的一些灯的不显示和多显示问题怎么解决?针对您提到的188数码管在使用查理复用(Charlieplexing)原理时出现的显示异常问题,如部分LED不亮或误亮,以下是专业分析与解决方案:
一、问题分析
1. 查理复用原理简介
查理复用是一种通过控制I/O端口的输入/输出状态,实现多路LED显示的技术。其核心在于利用单个引脚在不同状态下作为驱动或感应端,从而减少所需的I/O数量。然而,该技术对时序和电压控制要求较高。
2. 可能原因
时序控制不当:查理复用依赖精确的扫描周期,若刷新频率过低或时序混乱,可能导致某些LED未能及时响应。
电压波动或电流不足:LED点亮需要足够的驱动电流,若电源不稳定或电路设计不合理,可能造成部分LED无法正常工作。
引脚配置错误:未正确设置I/O方向或电平,可能导致部分LED处于高阻态或被误触发。
硬件干扰:共阴/共阳接法错误或外部噪声干扰,也可能导致显示异常。
二、解决方案建议
1. 优化时序控制
提高刷新频率:确保每帧刷新时间足够短(通常建议高于60Hz),以避免人眼察觉闪烁,同时保证所有LED能被正确点亮。
严格控制扫描顺序:按照设计文档中的逻辑顺序逐个激活LED,避免因跳变导致信号干扰。
2. 检查硬件连接与电源
确认共阴/共阳接法:根据数码管类型(共阴或共阳)正确连接电源和地线,避免因极性错误导致部分LED不亮。
增强电源稳定性:使用稳压器或滤波电容(如10μF电解电容)稳定供电,防止电压波动影响显示效果。
增加限流电阻:为每个LED添加适当阻值的限流电阻(一般推荐220Ω~330Ω),避免过流损坏或亮度不均。
3. 验证I/O配置
确保I/O方向正确:在查理复用中,需动态切换I/O引脚的输入/输出状态,确保每次仅有一个引脚为输出,其余为输入或高阻态。
避免浮空引脚:使用上拉/下拉电阻或软件配置为高阻态,防止引脚悬空引发误触发。
4. 排查干扰与信号完整性
缩短走线距离:尽量减少I/O引脚与数码管之间的走线长度,降低寄生电容和电感的影响。
屏蔽干扰源:若系统存在高频噪声,可考虑在电源端加装磁珠或使用屏蔽线。
三、调试建议
逐步测试:从简单模式(如单独点亮一个LED)开始,逐步扩展至复杂场景,定位具体故障点。
示波器辅助:使用示波器观察I/O信号波形,确保高低电平符合预期,无毛刺或抖动。
代码逻辑检查:确保程序中未出现逻辑错误,如重复激活同一引脚或未及时关闭其他引脚。
四、总结
188数码管在查理复用下的显示问题,主要源于时序、电源、硬件配置及信号干扰等因素。通过优化时序控制、完善电源设计、规范I/O配置及排查干扰,可有效解决显示异常问题。如问题仍未解决,建议进一步检查硬件布局或提供更详细的电路图以便深入分析。
如需进一步技术支持,请提供更多系统参数或代码片段,我们将为您定制化分析。
[本文内容由国芯人工智能辅助生成,仅供参考] https://www.stcaimcu.com/thread-7580-1-1.html #include "SMG.h"
//数码管
//P13->P1
//P15->P2
//P54->P3
//P11->P4
//P31->P5
//高阻输入
#defineP0_MODE_IN_HIZ(Pin) P0M1 |= (Pin), P0M0 &= ~(Pin);
#defineP1_MODE_IN_HIZ(Pin) P1M1 |= (Pin), P1M0 &= ~(Pin);
#defineP2_MODE_IN_HIZ(Pin) P2M1 |= (Pin), P2M0 &= ~(Pin);
#defineP3_MODE_IN_HIZ(Pin) P3M1 |= (Pin), P3M0 &= ~(Pin);
#defineP4_MODE_IN_HIZ(Pin) P4M1 |= (Pin), P4M0 &= ~(Pin);
#defineP5_MODE_IN_HIZ(Pin) P5M1 |= (Pin), P5M0 &= ~(Pin);
#defineP6_MODE_IN_HIZ(Pin) P6M1 |= (Pin), P6M0 &= ~(Pin);
#defineP7_MODE_IN_HIZ(Pin) P7M1 |= (Pin), P7M0 &= ~(Pin);
//推挽输出
#defineP0_MODE_OUT_PP(Pin) P0M1 &= ~(Pin), P0M0 |= (Pin);
#defineP1_MODE_OUT_PP(Pin) P1M1 &= ~(Pin), P1M0 |= (Pin);
#defineP2_MODE_OUT_PP(Pin) P2M1 &= ~(Pin), P2M0 |= (Pin);
#defineP3_MODE_OUT_PP(Pin) P3M1 &= ~(Pin), P3M0 |= (Pin);
#defineP4_MODE_OUT_PP(Pin) P4M1 &= ~(Pin), P4M0 |= (Pin);
#defineP5_MODE_OUT_PP(Pin) P5M1 &= ~(Pin), P5M0 |= (Pin);
#defineP6_MODE_OUT_PP(Pin) P6M1 &= ~(Pin), P6M0 |= (Pin);
#defineP7_MODE_OUT_PP(Pin) P7M1 &= ~(Pin), P7M0 |= (Pin);
sbit PSEG_1 = P1^3;
sbit PSEG_2 = P1^5;
sbit PSEG_3 = P5^4;
sbit PSEG_4 = P1^1;
sbit PSEG_5 = P3^1;
#define PIN1_IN() P1_MODE_IN_HIZ(0x08); //把单片机IO口配置为高阻输入
#define PIN2_IN() P1_MODE_IN_HIZ(0x20);
#define PIN3_IN() P5_MODE_IN_HIZ(0x10);
#define PIN4_IN() P1_MODE_IN_HIZ(0x02);
#define PIN5_IN() P3_MODE_IN_HIZ(0x02);
#define PIN1_L() P1_MODE_OUT_PP(0x08);PSEG_1 = 0; //配置为推挽输出,且拉低
#define PIN2_L() P1_MODE_OUT_PP(0x20);PSEG_2 = 0;
#define PIN3_L() P5_MODE_OUT_PP(0x10);PSEG_3 = 0;
#define PIN4_L() P1_MODE_OUT_PP(0x02);PSEG_4 = 0;
#define PIN5_L() P3_MODE_OUT_PP(0x02);PSEG_5 = 0;
#define PIN1_H() P1_MODE_OUT_PP(0x08);PSEG_1 = 1;//配置为推挽输出,且拉高
#define PIN2_H() P1_MODE_OUT_PP(0x20);PSEG_2 = 1;
#define PIN3_H() P5_MODE_OUT_PP(0x10);PSEG_3 = 1;
#define PIN4_H() P1_MODE_OUT_PP(0x02);PSEG_4 = 1;
#define PIN5_H() P3_MODE_OUT_PP(0x02);PSEG_5 = 1;
/************************************************************************************/
void LED_GPIO_Init(void)//初始化IO口
{
// P11 = 0;
// P13 = 0;
// P15 = 0;
// P31 = 0;
// P54 = 0;
//P13,P11,P15
P1_MODE_OUT_PP( 0x02 | 0x08 | 0x20 );
//P31
P3_MODE_OUT_PP( 0x02 );
//P54
P5_MODE_OUT_PP( 0x10 );
Set_AllPin_INPUT();
}
/********************************熄灭所有数码管***********************************/
void Set_AllPin_INPUT(void)
{
// P11 = 1;
// P13 = 1;
// P15 = 1;
// P31 = 1;
// P54 = 1;
PIN1_IN();//把单片机IO口配置为输入模式
PIN2_IN();
PIN3_IN();
PIN4_IN();
PIN5_IN();
}
unsigned char bai=0,shi=0,ge=0;//百位,十位,个位,
unsigned short display_sram=0;
unsigned short code Segment={
{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} //个位
};
// 扫描函数 - 确保所有段线明确输出高低电平
void Display_Scan1(void)
{
if(display_sram & 0x8000) {
PIN2_H();
} else {
PIN2_L();
}
if(display_sram & 0x4000) {
PIN3_H();
} else {
PIN3_L();
}
if(display_sram & 0x2000) {
PIN4_H();
} else {
PIN4_L();
}
if(display_sram & 0x1000) {
PIN5_H();
} else {
PIN5_L();
}
PIN1_L();// 最后使能位选
}
void Display_Scan2(void)
{
if(display_sram & 0x0800) {
PIN1_H();
} else {
PIN1_L();
}
if(display_sram & 0x0400) {
PIN3_H();
} else {
PIN3_L();
}
if(display_sram & 0x0200) {
PIN4_H();
} else {
PIN4_L();
}
if(display_sram & 0x0100) {
PIN5_H();
} else {
PIN5_L();
}
PIN2_L();// 使能位选
}
void Display_Scan3(void)
{
if(display_sram & 0x0080) {
PIN1_H();
} else {
PIN1_L();
}
if(display_sram & 0x0040) {
PIN2_H();
} else {
PIN2_L();
}
if(display_sram & 0x0020) {
PIN4_H();
} else {
PIN4_L();
}
if(display_sram & 0x0010) {
PIN5_H();
} else {
PIN5_L();
}
PIN3_L();// 使能位选
}
void Display_Scan4(void)
{
if(display_sram & 0x0008) {
PIN1_H();
} else {
PIN1_L();
}
if(display_sram & 0x0004) {
PIN2_H();
} else {
PIN2_L();
}
if(display_sram & 0x0002) {
PIN3_H();
} else {
PIN3_L();
}
if(display_sram & 0x0001) {
PIN5_H();
} else {
PIN5_L();
}
PIN4_L();// 使能位选
}
/****************************显示函数***********************************/
//放在定时器中断函数,5ms运行一次,扫描一轮需要4*5ms=20ms,
//也就是50Hz的刷新频率,如果感觉闪烁,可以4ms运行。
void Display_tube(void)
{
static unsigned char case_cnt = 0;
Set_AllPin_INPUT();// 先关闭所有位选
display_sram = Segment | Segment | Segment;
switch(case_cnt) {
case 0: Display_Scan1(); break;
case 1: Display_Scan2(); break;
case 2: Display_Scan3(); break;
case 3: Display_Scan4(); break;
default: case_cnt = 0; return;
}
case_cnt++;
if(case_cnt >= 4) case_cnt = 0;
}
void Dispaly_Dig(unsigned int dig)//拆分
{
bai =dig/100;
shi = (dig/10) %10;
ge=dig%10;
Display_tube();
}
主要是我这个代码不清楚哪有问题。参考的代码是:https://blog.csdn.net/weixin_42401119/article/details/120704663。 晓飛飛 发表于 2025-8-13 10:43
https://www.stcaimcu.com/thread-7580-1-1.html
感谢,我先阅读一下您的文章。
晓飛飛 发表于 2025-8-13 10:43
https://www.stcaimcu.com/thread-7580-1-1.html
这个数码管在PCB布线时,每一个引脚的线长需要等长吗?我驱动显示不全有没有可能是这个问题呢?
逐段显示,只有亮的段两个IO推挽,其他IO高阻,点亮前后加延时 晓飛飛 发表于 2025-8-13 10:43
https://www.stcaimcu.com/thread-7580-1-1.html
您好我这边按照您的驱动程序重新写了数码管的驱动程序,但是还是出现了显示错误的问题。
主函数:
#include "Config.h"
#include "SMG.h"
#include "Delay.h"
#include "Timer.h"
//========================================================================
void Sys_Init(void);
void Project_Task(void);
//========================================================================
//========================================================================
// 主函数
void main()
{
Sys_Init();
while(1)
{
Project_Task();
}
}
//========================================================================
void Sys_Init(void)
{
P_SW2 |= 0x80;// 使能访问XSFR
// 配置引脚
//P10_PWM1P,冷白
//P12_PWM2P,红色
//P14_PWM3P,绿色
//P16_PWM4P,蓝色
//P17_PWM5_2,暖白
//P33_INT1,人体
//P34_ADC12,光敏
//P32_INT0_ADC10,拨键
//P30_INT4,按键1
//P37_INT3,按键2
//数码管
//P13->P1
//P15->P2
//P54->P3
//P11->P4
//P31->P5
//P36_INT2_ADC14,充电
//P35_ADC13,电池电压
P1M1 = BIN(00101010);
P1M0 = BIN(11010101);
P3M1 = BIN(01111110);
P3M0 = BIN(00000000);
P5M1 = BIN(00010000);
P5M0 = BIN(00000000);
P10 = 0;
P12 = 0;
P14 = 0;
P16 = 0;
P17 = 0;
SMG_GPIO_Init();
Timer0_Init();
Timer1_Init();
EA = 1;
}
//========================================================================
void Project_Task(void)
{
display(0,0,0,0,1);
}
数码管驱动:
#include "SMG.h"
//数码管
//P13->P1
//P15->P2
//P54->P3
//P11->P4
//P31->P5
//高阻输入
#defineP0_MODE_IN_HIZ(Pin) P0M1 |= (Pin), P0M0 &= ~(Pin);
#defineP1_MODE_IN_HIZ(Pin) P1M1 |= (Pin), P1M0 &= ~(Pin);
#defineP2_MODE_IN_HIZ(Pin) P2M1 |= (Pin), P2M0 &= ~(Pin);
#defineP3_MODE_IN_HIZ(Pin) P3M1 |= (Pin), P3M0 &= ~(Pin);
#defineP4_MODE_IN_HIZ(Pin) P4M1 |= (Pin), P4M0 &= ~(Pin);
#defineP5_MODE_IN_HIZ(Pin) P5M1 |= (Pin), P5M0 &= ~(Pin);
#defineP6_MODE_IN_HIZ(Pin) P6M1 |= (Pin), P6M0 &= ~(Pin);
#defineP7_MODE_IN_HIZ(Pin) P7M1 |= (Pin), P7M0 &= ~(Pin);
//推挽输出
#defineP0_MODE_OUT_PP(Pin) P0M1 &= ~(Pin), P0M0 |= (Pin);
#defineP1_MODE_OUT_PP(Pin) P1M1 &= ~(Pin), P1M0 |= (Pin);
#defineP2_MODE_OUT_PP(Pin) P2M1 &= ~(Pin), P2M0 |= (Pin);
#defineP3_MODE_OUT_PP(Pin) P3M1 &= ~(Pin), P3M0 |= (Pin);
#defineP4_MODE_OUT_PP(Pin) P4M1 &= ~(Pin), P4M0 |= (Pin);
#defineP5_MODE_OUT_PP(Pin) P5M1 &= ~(Pin), P5M0 |= (Pin);
#defineP6_MODE_OUT_PP(Pin) P6M1 &= ~(Pin), P6M0 |= (Pin);
#defineP7_MODE_OUT_PP(Pin) P7M1 &= ~(Pin), P7M0 |= (Pin);
//准双向口
#defineP0_MODE_IO_PU(Pin) P0M1 &= ~(Pin), P0M0 &= ~(Pin);
#defineP1_MODE_IO_PU(Pin) P1M1 &= ~(Pin), P1M0 &= ~(Pin);
#defineP2_MODE_IO_PU(Pin) P2M1 &= ~(Pin), P2M0 &= ~(Pin);
#defineP3_MODE_IO_PU(Pin) P3M1 &= ~(Pin), P3M0 &= ~(Pin);
#defineP4_MODE_IO_PU(Pin) P4M1 &= ~(Pin), P4M0 &= ~(Pin);
#defineP5_MODE_IO_PU(Pin) P5M1 &= ~(Pin), P5M0 &= ~(Pin);
#defineP6_MODE_IO_PU(Pin) P6M1 &= ~(Pin), P6M0 &= ~(Pin);
#defineP7_MODE_IO_PU(Pin) P7M1 &= ~(Pin), P7M0 &= ~(Pin);
sbit PSEG_1 = P1^3;
sbit PSEG_2 = P1^5;
sbit PSEG_3 = P5^4;
sbit PSEG_4 = P1^1;
sbit PSEG_5 = P3^1;
#define PIN1_IN() P1_MODE_IN_HIZ(0x08); //把单片机IO口配置为高阻输入
#define PIN2_IN() P1_MODE_IN_HIZ(0x20);
#define PIN3_IN() P5_MODE_IN_HIZ(0x10);
#define PIN4_IN() P1_MODE_IN_HIZ(0x02);
#define PIN5_IN() P3_MODE_IN_HIZ(0x02);
#define PIN1_OUT_L() P1_MODE_OUT_PP(0x08);PSEG_1 = 0; //配置为推挽输出,且拉低
#define PIN2_OUT_L() P1_MODE_OUT_PP(0x20);PSEG_2 = 0;
#define PIN3_OUT_L() P5_MODE_OUT_PP(0x10);PSEG_3 = 0;
#define PIN4_OUT_L() P1_MODE_OUT_PP(0x02);PSEG_4 = 0;
#define PIN5_OUT_L() P3_MODE_OUT_PP(0x02);PSEG_5 = 0;
#define PIN1_OUT_H() P1_MODE_OUT_PP(0x08);PSEG_1 = 1;//配置为推挽输出,且拉高
#define PIN2_OUT_H() P1_MODE_OUT_PP(0x20);PSEG_2 = 1;
#define PIN3_OUT_H() P5_MODE_OUT_PP(0x10);PSEG_3 = 1;
#define PIN4_OUT_H() P1_MODE_OUT_PP(0x02);PSEG_4 = 1;
#define PIN5_OUT_H() P3_MODE_OUT_PP(0x02);PSEG_5 = 1;
//各个LED灯珠代表的位
//#define A1 0x00000001
#define B1 0x00000002
#define C1 0x00000004
//#define D1 0x00000008
//#define E1 0x00000010
//#define F1 0x00000020
//#define G1 0x00000040
#define A2 0x00000080
#define B2 0x00000100
#define C2 0x00000200
#define D2 0x00000400
#define E2 0x00000800
#define F2 0x00001000
#define G2 0x00002000
#define A3 0x00004000
#define B3 0x00008000
#define C3 0x00010000
#define D3 0x00020000
#define E3 0x00040000
#define F3 0x00080000
#define G3 0x00100000
#define DP1 0x00200000
#define DP2 0x00400000
#define K1 0x00800000
#define K2 0x01000000
u32 xdata display_num;
//第一个7段码从0~9对应的编码
code u32 digit1 =
{
0, //0
B1|C1, //1
0, //2
0, //3
0, //4
0, //5
0, //6
0, //7
0, //8
0, //9
0, //黑 消隐
};
//第二个7段码从0~9对应的编码
code u32 digit2 =
{
A2|B2|C2|D2|E2|F2, //0
B2|C2, //1
A2|B2|D2|E2|G2, //2
A2|B2|C2|D2|G2, //3
B2|C2|F2|G2, //4
A2|C2|D2|F2|G2, //5
A2|C2|D2|E2|F2|G2, //6
A2|B2|C2, //7
A2|B2|C2|D2|E2|F2|G2, //8
A2|B2|C2|D2|F2|G2, //9
0, //黑 消隐
};
//第三个7段码从0~9对应的编码
code u32 digit3 =
{
A3|B3|C3|D3|E3|F3, //0
B3|C3, //1
A3|B3|D3|E3|G3, //2
A3|B3|C3|D3|G3, //3
B3|C3|F3|G3, //4
A3|C3|D3|F3|G3, //5
A3|C3|D3|E3|F3|G3, //6
A3|B3|C3, //7
A3|B3|C3|D3|E3|F3|G3, //8
A3|B3|C3|D3|F3|G3, //9
0, //黑 消隐
};
/************************************************************************************/
void SMG_GPIO_Init(void)//初始化IO口
{
Set_AllPin_INPUT();
}
/********************************熄灭所有数码管***********************************/
void Set_AllPin_INPUT(void)
{
// P11 = 1;
// P13 = 1;
// P15 = 1;
// P31 = 1;
// P54 = 1;
PIN1_IN();//把单片机IO口配置为输入模式
PIN2_IN();
PIN3_IN();
PIN4_IN();
PIN5_IN();
}
void display(u16 num,bit dp_1,bit dp_2,bit KK1,bit KK2)
{
u8 num1,num2,num3;
num1 = num / 100; //拆分出百位
num2 = (num % 100) / 10; //拆分出十位
num3 = num % 10; //拆分出个位
display_num = digit1 | digit2 | digit3;
if(dp_1)display_num |= DP1; //暂未写消隐功能可根据小数点位置和小数点前数字为零处理消隐
if(dp_2)display_num |= DP1;
if(KK1)display_num |= K1;
if(KK2)display_num |= K2;
}
//刷数码管定时器 1000Hz三个数码管平均333Hz
void Timer0_Isr(void) interrupt 1
{
static u8 sta;
Set_AllPin_INPUT(); //关闭数码管
switch (sta)
{
case 1:
PIN1_OUT_L();
if(display_num & B3) PIN2_OUT_H(); //1 B3 D3 F3 G3
if(display_num & D3) PIN3_OUT_H();
if(display_num & F1) PIN4_OUT_H();
if(display_num & G2) PIN5_OUT_H();
sta++;
break;
case 2:
PIN2_OUT_L();
if(display_num & A3) PIN1_OUT_H(); //2 A3 B2 D2 E2
if(display_num & B2) PIN3_OUT_H();
if(display_num & D2) PIN4_OUT_H();
if(display_num & E2) PIN5_OUT_H();
// if(display_num & DP1) PIN1_OUT_H();
sta++;
break;
case 3:
PIN3_OUT_L();
if(display_num & C3) PIN1_OUT_H(); //3 C3 A2 C2 F2
if(display_num & A2) PIN2_OUT_H();
if(display_num & C2) PIN4_OUT_H();
if(display_num & F2) PIN5_OUT_H();
// if(display_num & DP2) PIN1_OUT_H();
sta++;
break;
case 4:
PIN4_OUT_L();
if(display_num & E3) PIN1_OUT_H(); //4 E3 C1 B1 G2
if(display_num & C1) PIN2_OUT_H();
if(display_num & B1) PIN3_OUT_H();
if(display_num & G2) PIN5_OUT_H();
sta++;
break;
case 5:
PIN5_OUT_L();
if(display_num & DP1) PIN1_OUT_H(); //5 DP1 DP2 K1 K2
if(display_num & DP2) PIN4_OUT_H();
if(display_num & K1)PIN3_OUT_H();
if(display_num & K2)PIN2_OUT_H();
sta = 1;
break;
// case 6:
// PIN6_OUT_L();
// if(display_num & E2) PIN3_OUT_H(); //6 E2 D3 F3
// if(display_num & D3) PIN4_OUT_H();
// if(display_num & F3) PIN5_OUT_H();
// sta = 1;
// break;
default:
sta = 1;
break;
}
}
定时器初始化函数:
#include "Timer.h"
void Timer0_Init(void) //1毫秒@24.000MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x40; //设置定时初始值
TH0 = 0xA2; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
}
void Timer1_Init(void) //10毫秒@24.000MHz
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0xE0; //设置定时初始值
TH1 = 0xB1; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1; //使能定时器1中断
}
麻烦您帮我看一下 显示效果:
显示123、11、55、0四种,最后的两种图标显示没问题,但是会出现频闪。 这是我选用的数码管和数码管的连线
页:
[1]
2