找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 387|回复: 13
打印 上一主题 下一主题
收起左侧

7位9脚数码管驱动错误,不能正常显示

[复制链接]
跳转到指定楼层
楼主
ID:611626 发表于 2025-8-26 11:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
7位9脚数码管驱动错误,不能正常显示,请指教问题所在位置
代码如下:
#include "STC8G.h"
#include "intrins.h"

// 2921数码管共9个引脚定义
sbit LED1 = P3^4;  // LED1脚(位选信号)
sbit LED2 = P3^5;  // LED2脚(位选信号)
sbit LED3 = P3^6;  // LED3脚(位选信号)
sbit LED4 = P3^7;  // LED4脚(位选信号)
sbit LED5 = P1^5;  // LED5脚(位选信号)
sbit LED6 = P1^6;  // LED6脚(位选信号)
sbit LED7 = P1^7;  // LED7脚(位选信号)
sbit LED8 = P5^4;  // 段选信号
sbit LED9 = P3^3;  // 段选信号

// 共阴数码管段码表 (0-9, A-F, 熄灭)
unsigned char code SEG_TABLE[17] = {
    0x3F, // 0
    0x06, // 1
    0x5B, // 2
    0x4F, // 3
    0x66, // 4
    0x6D, // 5
    0x7D, // 6
    0x07, // 7
    0x7F, // 8
    0x6F, // 9
    0x77, // A
    0x7C, // B
    0x39, // C
    0x5E, // D
    0x79, // E
    0x71, // F
    0x00  // 熄灭
};

// ADC相关定义
#define ADC_POWER   0x80    // ADC电源控制位
#define ADC_FLAG    0x10    // ADC完成标志
#define ADC_START   0x08    // ADC开始控制位

// 函数声明
void closeAllDigits();
void delay_ms(unsigned int ms);
void delay_us(unsigned int us);
void setSegments(unsigned char digit, unsigned char segCode);
void displayDigit(unsigned char digit, unsigned char num, bit dot);
void init();
void InitADC();
unsigned int ReadADC(unsigned char ch);
unsigned int GetAverageADC(unsigned char ch, unsigned char times);
float CalculateVoltage(unsigned int adcValue);
float CalculateCurrent(unsigned int adcValue);
void DisplayVoltage(float voltage);
void DisplayCurrent(float current);

// 关闭所有数码管位选
void closeAllDigits() {
    LED1 = 1;  
    LED2 = 1;  
    LED3 = 1;  
    LED4 = 1;  
    LED5 = 1;  
    LED6 = 1;  
    LED7 = 1;  
}

// 延时函数
void delay_ms(unsigned int ms) {
    unsigned int i, j;
    for(i = 0; i < ms; i++)
        for(j = 0; j < 120; j++);
}

// 短延时函数
void delay_us(unsigned int us) {
    while(us--) {
        _nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();
    }
}
//关闭相应段选
void closeAllseg(unsigned char digit, unsigned char segCode)
{
switch(digit) {
        case 1:  // LED1位选
            LED2 = 0;  // a段
            LED3 =  0;  // b段
            LED4 =  0;  // c段
            LED5 =  0;  // d段
            LED6 =  0;  // e段
            LED7 =  0;  // f段
            LED8 =  0;  // g段
            LED9 = 0;  // dp段
            break;

        case 2:  // LED2位选
            LED1 =  0;  // a段
            LED3 =  0;  // b段
            LED4 = 0;  // c段
            LED5 =  0;  // d段
            LED6 =  0;  // e段
            LED7 =  0;  // f段
            LED8 =  0;  // g段
            LED9 =  0;  // dp段
            break;

        case 3:  // LED3位选
            LED1 =  0;  // a段
            LED2 = 0;  // b段
            LED4 =  0;  // c段
            LED5 =  0;  // d段
            LED6 =  0;  // e段
            LED7 = 0;  // f段
            LED8 =  0;  // g段
            LED9 =  0;  // dp段
            break;

        case 4:  // LED4位选
            LED1 = 0;  // a段
            LED2 =  0;  // b段
            LED3 =  0;  // c段
            LED5 = 0;  // d段
            LED6 = 0;  // e段
            LED7 =  0;  // f段
            LED8 =  0;  // g段
            LED9 =  0;  // dp段
            break;

        case 5:  // LED5位选
            LED1 = 0;  // a段
            LED2 =  0;  // b段
            LED3 =  0;  // c段
            LED4 =  0;  // d段
            LED6 =  0;  // e段
            LED7 =  0;  // f段
            LED8 =  0;  // g段
            LED9 =  0;  // dp段
            break;

        case 6:  // LED6位选
            LED1 =  0;  // a段
            LED2 =  0;  // b段
            LED3 =  0;  // c段
            LED4 =  0;  // d段
            LED5 =  0;  // e段
            LED7 =  0;  // f段
            LED8 =  0;  // g段
            LED9 =  0;  // dp段
            break;
                        }
//delay_ms(10);
}

// 设置段码,赋值段码到相应引脚
void setSegments(unsigned char digit, unsigned char segCode) {
    // 先关闭所有LED段码引脚
        /*
    LED1 = 0;
    LED2 = 0;
    LED3 = 0;
    LED4 = 0;
    LED5 = 0;
    LED6 = 0;
    LED7 = 0;
    LED8 = 0;
    LED9 = 0;
   */
        closeAllseg(); //先关闭所有段选
    // 根据不同数码管设置相应的段码
    switch(digit) {
        case 1:  // LED1位选
            LED2 = (segCode & 0x01) ? 1 : 0;  // a段
            LED3 = (segCode & 0x02) ? 1 : 0;  // b段
            LED4 = (segCode & 0x04) ? 1 : 0;  // c段
            LED5 = (segCode & 0x08) ? 1 : 0;  // d段
            LED6 = (segCode & 0x10) ? 1 : 0;  // e段
            LED7 = (segCode & 0x20) ? 1 : 0;  // f段
            LED8 = (segCode & 0x40) ? 1 : 0;  // g段
            LED9 = (segCode & 0x80) ? 1 : 0;  // dp段
            break;

        case 2:  // LED2位选
            LED1 = (segCode & 0x01) ? 1 : 0;  // a段
            LED3 = (segCode & 0x02) ? 1 : 0;  // b段
            LED4 = (segCode & 0x04) ? 1 : 0;  // c段
            LED5 = (segCode & 0x08) ? 1 : 0;  // d段
            LED6 = (segCode & 0x10) ? 1 : 0;  // e段
            LED7 = (segCode & 0x20) ? 1 : 0;  // f段
            LED8 = (segCode & 0x40) ? 1 : 0;  // g段
            LED9 = (segCode & 0x80) ? 1 : 0;  // dp段
            break;

        case 3:  // LED3位选
            LED1 = (segCode & 0x01) ? 1 : 0;  // a段
            LED2 = (segCode & 0x02) ? 1 : 0;  // b段
            LED4 = (segCode & 0x04) ? 1 : 0;  // c段
            LED5 = (segCode & 0x08) ? 1 : 0;  // d段
            LED6 = (segCode & 0x10) ? 1 : 0;  // e段
            LED7 = (segCode & 0x20) ? 1 : 0;  // f段
            LED8 = (segCode & 0x40) ? 1 : 0;  // g段
            LED9 = (segCode & 0x80) ? 1 : 0;  // dp段
            break;

        case 4:  // LED4位选
            LED1 = (segCode & 0x01) ? 1 : 0;  // a段
            LED2 = (segCode & 0x02) ? 1 : 0;  // b段
            LED3 = (segCode & 0x04) ? 1 : 0;  // c段
            LED5 = (segCode & 0x08) ? 1 : 0;  // d段
            LED6 = (segCode & 0x10) ? 1 : 0;  // e段
            LED7 = (segCode & 0x20) ? 1 : 0;  // f段
            LED8 = (segCode & 0x40) ? 1 : 0;  // g段
            LED9 = (segCode & 0x80) ? 1 : 0;  // dp段
            break;

        case 5:  // LED5位选
            LED1 = (segCode & 0x01) ? 1 : 0;  // a段
            LED2 = (segCode & 0x02) ? 1 : 0;  // b段
            LED3 = (segCode & 0x04) ? 1 : 0;  // c段
            LED4 = (segCode & 0x08) ? 1 : 0;  // d段
            LED6 = (segCode & 0x10) ? 1 : 0;  // e段
            LED7 = (segCode & 0x20) ? 1 : 0;  // f段
            LED8 = (segCode & 0x40) ? 1 : 0;  // g段
            LED9 = (segCode & 0x80) ? 1 : 0;  // dp段
            break;

        case 6:  // LED6位选
            LED1 = (segCode & 0x01) ? 1 : 0;  // a段
            LED2 = (segCode & 0x02) ? 1 : 0;  // b段
            LED3 = (segCode & 0x04) ? 1 : 0;  // c段
            LED4 = (segCode & 0x08) ? 1 : 0;  // d段
            LED5 = (segCode & 0x10) ? 1 : 0;  // e段
            LED7 = (segCode & 0x20) ? 1 : 0;  // f段
            LED8 = (segCode & 0x40) ? 1 : 0;  // g段
            LED9 = (segCode & 0x80) ? 1 : 0;  // dp段
            break;
    }
}

// 显示单个数码管
void displayDigit(unsigned char digit, unsigned char num, bit dot) {
    unsigned char segCode;

    // 确保num在有效范围内
    if (num > 9) num = 16;  // 只允许0-9的数字显示 if (num > 9) num = 16;  

    // 关闭所有数码管位选,防止串扰
    closeAllDigits();

    // 获取段码并设置小数点:segCode缓存=段码表
   segCode = SEG_TABLE[num];
    if(dot) segCode |= 0x80;  // 设置小数点

    // 设置段码
    setSegments(digit, segCode);

    // 打开对应的数码管位选(共阴,低电平有效)
    switch(digit) {
        case 1: LED1 = 0; break;
        case 2: LED2 = 0; break;
        case 3: LED3 = 0; break;
        case 4: LED4 = 0; break;
        case 5: LED5 = 0; break;
        case 6: LED6 = 0; break;
    }

    // 短暂延时,确保显示可见
    delay_ms(1);
}

// 初始化ADC
void InitADC() {
    P_SW2 |= 0x80;  // 扩展寄存器访问使能
    ADC_CONTR = ADC_POWER | 0x08;  // 开启ADC电源,使用内部参考电压
    P_SW2 &= 0x7F;  // 关闭扩展寄存器访问
    delay_ms(1);  // 等待ADC电源稳定
}

// 读取单次ADC值
unsigned int ReadADC(unsigned char ch) {
    unsigned int adcValue;

    P_SW2 |= 0x80;  // 扩展寄存器访问使能
    ADC_CONTR = ADC_POWER | ch | ADC_START;
    delay_us(20);  // 等待转换开始

    while (!(ADC_CONTR & ADC_FLAG));  // 等待转换完成
    ADC_CONTR &= ~ADC_FLAG;  // 清除转换完成标志

    // 读取ADC结果
    adcValue = (unsigned int)ADC_RES << 8;
    adcValue |= ADC_RESL;

    P_SW2 &= 0x7F;  // 关闭扩展寄存器访问
    return adcValue;
}

// 读取多次ADC并取平均值
unsigned int GetAverageADC(unsigned char ch, unsigned char times) {
    unsigned long sum = 0;
    unsigned char i;

    for(i = 0; i < times; i++) {
        sum += ReadADC(ch);
        delay_ms(1);
    }

    return (unsigned int)(sum / times);
}

// 计算电压值
float CalculateVoltage(unsigned int adcValue) {
    float refVoltage = 3.3;
    float voltage = (adcValue * refVoltage) / 1023.0 * 10.0;

    if(voltage > 30.0) voltage = 30.0;
    return voltage;
}

// 计算电流值
float CalculateCurrent(unsigned int adcValue) {
    float refVoltage = 3.3;
    float current = (adcValue * refVoltage) / 1023.0 * 303.0;

    if(current > 999.0) current = 999.0;
    return current;
}

// 显示电压值 (LED1-3)
void DisplayVoltage(float voltage) {
    unsigned int integerPart;
    unsigned int decimalPart;

    // 确保电压值在有效范围内
    if(voltage < 0) voltage = 0;
    if(voltage > 30.0) voltage = 30.0;

    // 分离整数和小数部分
    integerPart = (unsigned int)voltage;
    decimalPart = (unsigned int)((voltage - integerPart) * 100);

    // 显示12.3V的例子:
    // LED1显示1,LED2显示2(带小数点),LED3显示3
    if(integerPart >= 10) {
        // 两位数电压: XX.X
        displayDigit(1, integerPart / 10, 0);       // 十位
        displayDigit(2, integerPart % 10, 1);       // 个位(带小数点)
        displayDigit(3, decimalPart / 10, 0);       // 小数第一位
    } else {
        // 一位数电压: X.XX
        displayDigit(1, integerPart, 0);            // 个位
        displayDigit(2, decimalPart / 10, 1);       // 小数第一位(带小数点)
        displayDigit(3, decimalPart % 10, 0);       // 小数第二位
    }
}

// 显示电流值 (LED4-6)
void DisplayCurrent(float current) {
    unsigned int currInt;
    unsigned int integerPart;
    unsigned int decimalPart;

    // 确保电流值在有效范围内
    if(current < 0) current = 0;
    if(current > 999.0) current = 999.0;

    // 显示45.6mA的例子:
    // LED4显示4,LED5显示5(带小数点),LED6显示6
    if(current >= 100) {
        // 三位数电流: XXX
        currInt = (unsigned int)current;
        displayDigit(4, currInt / 100, 0);          // 百位
        displayDigit(5, (currInt / 10) % 10, 0);    // 十位
        displayDigit(6, currInt % 10, 0);           // 个位
    } else {
        // 带小数的电流: X.XX
        integerPart = (unsigned int)current;
        decimalPart = (unsigned int)((current - integerPart) * 100);
        displayDigit(4, integerPart, 0);            // 个位2D
        displayDigit(5, decimalPart / 10, 1);       // 小数第一位(带小数点)3B
        displayDigit(6, decimalPart % 10, 0);       // 小数第二位
    }
}

// 初始化函数
void init() {
    // 设置IO口为推挽输出
    P3M0 = 0xF8;  // P3.3-P3.7推挽输出
    P3M1 = 0x00;
    P1M0 = 0xE0;  // P1.5-P1.7推挽输出
    P1M1 = 0x00;
    P5M0 = 0x10;  // P5.4推挽输出
    P5M1 = 0x00;

    // 初始关闭所有数码管
    closeAllDigits();

    // 初始化ADC
    InitADC();
}

// 主函数
void main() {
    unsigned int adcVoltage, adcCurrent;
    float voltage, current;
    int i;  // 声明在循环外,兼容C89标准

    init();

    while(1) {
        // 使用测试值
      //  voltage = 22.8;  // 应该显示在LED1-3: 1, 2., 3
        current = 45.6;  // 应该显示在LED4-6: 4, 5., 6

        // 循环显示电压和电流,增加刷新频率

         //   DisplayVoltage(voltage);
            DisplayCurrent(current); //显示电流
                       
         delay_ms(1);
    }
}


数码管.jpg (22.7 KB, 下载次数: 0)

数码管.jpg
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:69038 发表于 2025-8-26 13:52 | 只看该作者
感觉你这样的驱动方法不对!
你搜一下本坛的关键词:“查理复用”
回复

使用道具 举报

板凳
ID:611626 发表于 2025-8-26 18:04 | 只看该作者
#include "STC8G.h"
#include "intrins.h"

// 引脚定义
sbit LED1 = P3^4;  // 位选1
sbit LED2 = P3^5;  // 位选2
sbit LED3 = P3^6;  // 位选3
sbit LED4 = P3^7;  // 位选4
sbit LED5 = P1^5;  // 位选5
sbit LED6 = P1^6;  // 位选6
sbit LED7 = P1^7;  // 位选7(指示灯)
sbit LED8 = P5^4;  // 段选G
sbit LED9 = P3^3;  // 段选DP

// 共阴数码管段码表(0-9) - 修正版
// 位定义: bit0=A, bit1=B, bit2=C, bit3=D, bit4=E, bit5=F, bit6=G, bit7=DP
unsigned char code SEG_TABLE[10] = {
    0x3F, // 0
    0x06, // 1
    0x5B, // 2
    0x4F, // 3
    0x66, // 4
    0x6D, // 5
    0x7D, // 6
    0x07, // 7
    0x7F, // 8
    0x6F  // 9
};

// 显示缓冲区 - 上排固定381,下排4显示7,5和6不显示
unsigned char dispBuffer[6] = {3, 8, 1, 7, 0xFF, 0xFF}; // 0xFF表示不显示
bit indicatorState = 1;
unsigned char slot = 0;
unsigned int scanCounter = 0;

// 延时函数(约150us@24MHz) - 缩短延时减少闪烁
void Delay150us(void) {
    unsigned int i;
    for(i = 0; i < 360; i++);
}

// 所有引脚设置为高阻
void SetAllHighZ(void) {
    P3M0 = 0x00; P3M1 = 0x00;
    P1M0 = 0x00; P1M1 = 0x00;
    P5M0 = 0x00; P5M1 = 0x00;
   
    LED1 = 1; LED2 = 1; LED3 = 1; LED4 = 1; LED5 = 1;
    LED6 = 1; LED7 = 1; LED8 = 1; LED9 = 1;
}

// 配置引脚为推挽输出
void SetPushPull(unsigned char pin) {
    switch(pin) {
        case 1: P3M0 |= 0x10; P3M1 &= ~0x10; break;
        case 2: P3M0 |= 0x20; P3M1 &= ~0x20; break;
        case 3: P3M0 |= 0x40; P3M1 &= ~0x40; break;
        case 4: P3M0 |= 0x80; P3M1 &= ~0x80; break;
        case 5: P1M0 |= 0x20; P1M1 &= ~0x20; break;
        case 6: P1M0 |= 0x40; P1M1 &= ~0x40; break;
        case 7: P1M0 |= 0x80; P1M1 &= ~0x80; break;
        case 8: P5M0 |= 0x10; P5M1 &= ~0x10; break;
        case 9: P3M0 |= 0x08; P3M1 &= ~0x08; break;
    }
}

// 驱动时隙0: LED1作为COM (上排第1位显示3)
void DriveSlot0(void) {
    unsigned char seg = SEG_TABLE[dispBuffer[0]];
   
    SetAllHighZ();
   
    // 配置COM为推挽低电平
    SetPushPull(1);
    LED1 = 0;
   
    // 配置段选 - 修正映射关系
    SetPushPull(2); LED2 = seg & 0x01;     // A1
    SetPushPull(3); LED3 = (seg >> 1) & 0x01; // B1
    SetPushPull(4); LED4 = (seg >> 2) & 0x01; // C1
    SetPushPull(5); LED5 = (seg >> 3) & 0x01; // D1
    SetPushPull(6); LED6 = (seg >> 4) & 0x01; // E1
    SetPushPull(7); LED7 = (seg >> 5) & 0x01; // F1
    SetPushPull(8); LED8 = (seg >> 6) & 0x01; // G1
    SetPushPull(9); LED9 = 0; // 关闭小数点
   
    Delay150us();
}

// 驱动时隙1: LED2作为COM (上排第2位显示8)
void DriveSlot1(void) {
    unsigned char seg = SEG_TABLE[dispBuffer[1]];
   
    SetAllHighZ();
   
    SetPushPull(2);
    LED2 = 0;
   
    SetPushPull(1); LED1 = seg & 0x01;     // A2
    SetPushPull(3); LED3 = (seg >> 1) & 0x01; // B2
    SetPushPull(4); LED4 = (seg >> 2) & 0x01; // C2
    SetPushPull(5); LED5 = (seg >> 3) & 0x01; // D2
    SetPushPull(6); LED6 = (seg >> 4) & 0x01; // E2
    SetPushPull(7); LED7 = (seg >> 5) & 0x01; // F2
    SetPushPull(8); LED8 = (seg >> 6) & 0x01; // G2
    SetPushPull(9); LED9 = 0;
   
    Delay150us();
}

// 驱动时隙2: LED3作为COM (上排第3位显示1)
void DriveSlot2(void) {
    unsigned char seg = SEG_TABLE[dispBuffer[2]];
   
    SetAllHighZ();
   
    SetPushPull(3);
    LED3 = 0;
   
    SetPushPull(1); LED1 = seg & 0x01;     // A3
    SetPushPull(2); LED2 = (seg >> 1) & 0x01; // B3
    SetPushPull(4); LED4 = (seg >> 2) & 0x01; // C3
    SetPushPull(5); LED5 = (seg >> 3) & 0x01; // D3
    SetPushPull(6); LED6 = (seg >> 4) & 0x01; // E3
    SetPushPull(7); LED7 = (seg >> 5) & 0x01; // F3
    SetPushPull(8); LED8 = (seg >> 6) & 0x01; // G3
    SetPushPull(9); LED9 = 0;
   
    Delay150us();
}

// 驱动时隙3: LED4作为COM (下排第4位显示7)
void DriveSlot3(void) {
    unsigned char seg = SEG_TABLE[dispBuffer[3]];
   
    SetAllHighZ();
   
    SetPushPull(4);
    LED4 = 0;
   
    SetPushPull(1); LED1 = seg & 0x01;     // A4
    SetPushPull(2); LED2 = (seg >> 1) & 0x01; // B4
    SetPushPull(3); LED3 = (seg >> 2) & 0x01; // C4
    SetPushPull(5); LED5 = (seg >> 3) & 0x01; // D4
    SetPushPull(6); LED6 = (seg >> 4) & 0x01; // E4
    SetPushPull(7); LED7 = (seg >> 5) & 0x01; // F4
    SetPushPull(8); LED8 = (seg >> 6) & 0x01; // G4
    SetPushPull(9); LED9 = 0;
   
    Delay150us();
}

// 驱动时隙4: LED5作为COM (下排第5位不显示)
void DriveSlot4(void) {
    SetAllHighZ();
    // 仅关闭COM,不设置任何段选
    SetPushPull(5);
    LED5 = 1; // 不激活位选
    Delay150us();
}

// 驱动时隙5: LED6作为COM (下排第6位不显示)
void DriveSlot5(void) {
    SetAllHighZ();
    // 仅关闭COM,不设置任何段选
    SetPushPull(6);
    LED6 = 1; // 不激活位选
    Delay150us();
}

// 驱动时隙6: LED7作为指示灯
void DriveSlot6(void) {
    SetAllHighZ();
   
    SetPushPull(7);
    LED7 = 0; // 激活指示灯
   
    SetPushPull(1); LED1 = indicatorState;
    SetPushPull(2); LED2 = indicatorState;
   
    Delay150us();
}

// 扫描所有时隙
void ScanSlots(void) {
    switch(slot) {
        case 0: DriveSlot0(); break;
        case 1: DriveSlot1(); break;
        case 2: DriveSlot2(); break;
        case 3: DriveSlot3(); break;
        case 4: DriveSlot4(); break;
        case 5: DriveSlot5(); break;
        case 6: DriveSlot6(); break;
    }
   
    slot++;
    if(slot >= 7) slot = 0;
   
    // 降低指示灯闪烁频率
    if(++scanCounter >= 4000) {
        scanCounter = 0;
        indicatorState = !indicatorState;
    }
}

// 主函数
void main(void) {
    SetAllHighZ();
   
    while(1) {
        // 高频扫描确保显示稳定
        ScanSlots();
    }
}

LED.jpg (52.38 KB, 下载次数: 0)

LED.jpg
回复

使用道具 举报

地板
ID:1133081 发表于 2025-8-26 20:33 | 只看该作者
zhuls 发表于 2025-8-26 13:52
感觉你这样的驱动方法不对!
你搜一下本坛的关键词:“查理复用”

这种数码管不适用“查理复用”方式,9个脚有7个是段位轮换共用。可以把位bit插入段码编一个int型2维数组,也就是7位8段。
回复

使用道具 举报

5#
ID:1034262 发表于 2025-8-26 22:52 | 只看该作者
驱动这种数码管,N个IO最多可以驱动N(N-1)个LED,9个IO最多可以驱动9*8=72段,即9个带小数点的数码管。
驱动原则是:
分N个时隙驱动,每次驱动时一个IO做COM驱动,另外(N-1)个IO做SEG驱动。
先把所有IO设置为高阻。
对于共阴,不显示的SEG为高阻,显示的SEG推挽输出1, COM推挽输出0。
对于共阳,不显示的SEG为高阻,显示的SEG推挽输出0, COM推挽输出1。
回复

使用道具 举报

6#
ID:384109 发表于 2025-8-26 22:52 | 只看该作者
查理复用好像需要引进有硬件高阻功能才行
回复

使用道具 举报

7#
ID:69038 发表于 2025-8-27 00:01 | 只看该作者
WL0123 发表于 2025-8-26 20:33
这种数码管不适用“查理复用”方式,9个脚有7个是段位轮换共用。可以把位bit插入段码编一个int型2维数组 ...

你在主楼“数码管.jpg "图中所展示的逻辑,就是要用“查理复用”的方式来驱动。。
9个脚最多可驱动9*8=72个LED。也就是最多可驱动9位8段(7段+小数点),
所以你才7位,算是富余了。
回复

使用道具 举报

8#
ID:69038 发表于 2025-8-27 00:43 | 只看该作者
你要有两个数组做缓存,一个是显示内容,另一个是段码映射表,
比如你要显示“0123456”7个数字,就要有段表buf[7];//7位屏
再来个输出映射表,比如dis[9];//共9个扫描线
当你buf[7]中7个要显示数字有改变时,要根据图中所示逻辑表映射到dis[9]中:
如我这个是6线驱动4位时钟屏,刚好30个LED(6*5=30)
这是映射关系:
  1. // void trans4_6(unsigned char sec_point)   
  2. //{
  3. //   char i;
  4. //        for(i=0;i<6;i++) dis[i]=0;             // 清显示缓存
  5. //        dis[0] |= (buf[0] & 0x1F) << 1;           // dis0的bit[5:1]=buf0的bit[4:0]
  6. //        dis[1] |= (buf[0] & 0x20) >> 5;           // dis1的bit[0]=buf0的bit[5]
  7. //        dis[1] |= (buf[0] & 0x40) >> 4;           // dis1的bit[2]=buf0的bit[6]
  8. //        dis[1] |= (buf[1] & 0x07) << 3;           // dis1的bit[5:3]=buf1的bit[2:0]
  9. //        dis[2] |= (buf[1] & 0x18) >> 3;           // dis2的bit[1:0]=buf1的bit[4:3]
  10. //        dis[2] |= (buf[1] & 0x60) >> 2;           // dis2的bit[4:3]=buf1的bit[6:5]
  11. //        dis[2] |= (buf[2] & 0x01) << 5;           // dis2的bit[5]=buf2的bit[0]
  12. //        dis[3] |= (buf[2] & 0x0E) >> 1;           // dis3的bit[2:0]=buf2的bit[3:1]
  13. //        dis[3] |= (buf[2] & 0x30) ;               // dis3的bit[5:4]=buf2的bit[5:4]
  14. //        dis[4] |= (buf[2] & 0x40) >> 6;           // dis4的bit[0]=buf2的bit[6]
  15. //        dis[4] |= (buf[3] & 0x07) << 1;           // dis4的bit[3:1]=buf3的bit[2:0]
  16. //        dis[4] |= (buf[3] & 0x08) << 2;           // dis4的bit[5]=buf3的bit[3]
  17. //        dis[5] |= (buf[3] & 0x70) >> 4;           // dis5的bit[2:0]=buf3的bit[6:4]
  18. //        if(sec_point & 0x01) dis[5] |= 0x08; //显示上秒点
  19. //        if(sec_point & 0x02) dis[5] |= 0x10; //显示下秒点
  20. //}
复制代码
然后再在中断中扫描dis[9]:
比如:
  1. // void scan_led_io(unsigned char line)
  2. //{
  3. //  unsigned char i;
  4. //  unsigned char io;
  5. //  unsigned char tdat;
  6. //
  7. //   io=scan_io_tbl[line];   //扫描线转IO口bit[x]  ;//因为扫描线不是连续的,才要有此动作。
  8. //   dat=dis[line];                   //当前扫描线对应的数值
  9. //
  10. //   led_input();                       //所有扫描线均为输入高阻态
  11. //   led_pp_out(io);                   //当前扫描线为PP输出,(且为低--代码共用,不想改了)
  12. //   P1 |= check_tbl[line];  //当前扫描线输出高
  13. //
  14. //   for(i=0;i<6;i++)                   //共6条线
  15. //   {
  16. //            if(i==io)  continue;            //是当扫描线,跳过
  17. //            if(dat & check_tbl[i])//负极线,且有效
  18. //         led_pp_out(i);               //输出低
  19. //   }
  20. //}
复制代码
以上是以IO线为扫描基准,当某些IO
输出能力不足时,会LED显示亮度不均!
还有一种方法是,以单个LED为基准,一次扫描一个LED,可以解决亮度问题,但扫描代码要更改。。
个人更喜欢用单点扫显方式,省去 void trans4_6(unsigned char sec_point) 映射动作,不过要多做一个表,
如(这个是8线56灯):
  1. unsigned int code led_map[led_num]={
  2.                         0x0001,        //1A 第一个[0]是buf[0],第二个[0]是bit[0],第3个[0]是正极P1[0],第4个[1]是负极P1[1],下同,略;
  3.                         0x0102,        //1B
  4.                         0x0203,        //1C
  5.                         0x0304,        //1D
  6.                         0x0405,        //1E
  7.                         0x0506,        //1F
  8.                         0x0607,        //1G
  9.                         0x0763,        //1H



复制代码
然后,在中断扫描:
  1. //tim0中断
  2. //每进中断扫显一个LED,亮度均匀,但整体亮度略低。。。
  3. //占用0.5ms时视频不闪,1ms时视频微闪,2ms时视频明显见闪;
  4. //以祼眼视觉为准  。
  5. void tim0_Isr() interrupt 1           //
  6. {
  7.         tms++;
  8.     buf_index = led_map[tim_count]>>12 & 0x0f;
  9.         bit_index = led_map[tim_count]>>8 & 0x0f;
  10.         led_p   = led_map[tim_count]>>4 & 0x0f;
  11.         led_n   = led_map[tim_count]& 0x0f;
  12.        
  13.         led_input();//所有LED相关的IO均置输入(高阻,灭所有LED)
  14.         //检测buf[0-6]中[bit0:bit7]的值,为“1”需点亮,为“0”不点亮
  15.         if( buf[buf_index] & 1 << bit_index )
  16.         {
  17.                 led_pp_out(led_p,1);           //当前正极线为PP输出,且置高
  18.                 led_pp_out(led_n,0);       //对应LED输出低
  19.         }
  20.         tim_count++;        //下一次要扫描的IO
  21.     tim_count%=led_num;   //全屏共8个IO复用
  22. }


复制代码
说了这么多, 以上内容希望能帮到你。。。



回复

使用道具 举报

9#
ID:1133081 发表于 2025-8-27 07:11 | 只看该作者
zhuls 发表于 2025-8-27 00:01
你在主楼“数码管.jpg "图中所展示的逻辑,就是要用“查理复用”的方式来驱动。。
9个脚最多可驱动9*8=7 ...

你的观点是对的,我在4楼的方法不成熟,行不通。
回复

使用道具 举报

10#
ID:611626 发表于 2025-8-27 08:56 | 只看该作者
zhuls 发表于 2025-8-27 00:01
你在主楼“数码管.jpg "图中所展示的逻辑,就是要用“查理复用”的方式来驱动。。
9个脚最多可驱动9*8=7 ...

现在测试中感觉是时序不正确,出现乱码,有的位不显示现象
回复

使用道具 举报

11#
ID:69038 发表于 2025-8-27 13:53 | 只看该作者
宏达工控 发表于 2025-8-27 08:56
现在测试中感觉是时序不正确,出现乱码,有的位不显示现象

你可以单独测试,只显示一个数字,比如第一位显示“1”,234567位不显,再第二位显示“2”,134567位不显。。。
看看能不能正常?
回复

使用道具 举报

12#
ID:584814 发表于 2025-8-27 18:12 | 只看该作者
7位9脚是啥意思 ?
1、通常一位数码管有8只脚(不要点的7只脚),加上7位引脚至少是15脚;
2、如果是7位数码管共只有9只引脚,是查理利用方式驱动,这个没专用芯片是单片机直驱。
如果是1,建议买个成品的驱动芯片只要几毛钱;如果是2,就找查理复用驱动法。
回复

使用道具 举报

13#
ID:774370 发表于 2025-8-28 15:12 | 只看该作者
看图片确实为查理复用的数码管
回复

使用道具 举报

14#
ID:611626 发表于 2025-8-29 17:47 | 只看该作者
void Io_init (void)// 模式初值设置
{
    P1M0 &= ~(0xE0); P1M1 |= 0xE0;   // 设置P1.5, P1.6, P1.7为高阻: 11100000 -> M0=0, M1=1: 高阻
    P3M0 &= ~(0xF8); P3M1 |= 0xF8;   // 设置P3.3~P3.7为高阻: 11111000 -> 0xF8
    P5M0 &= ~(0x10); P5M1 |= 0x10;   // P5.4设置P5.4为高阻: 00010000
}
void DG1(int a)
{
   Io_init ();
         switch(a) //2A3B4=P3.3dp9-3.5-9.7 C5D6E7F=P1.5-1.7 P3.4配置双向口  9DP
                {  //显示0=abcdef 234 567 P35-P37 P15-P17
            //P3M1 =0000 0111=07        P3M0 =1111 1000=F8        设置为推挽        P3=11101000=E8
                        case 0:{
                                                        P3M1 = 0x07;  P3M0 = 0xF8;  P3 = 0xE8;   delay(x);    //1ABC   //0.                               
                    P1M1 = 0x1F;  P1M0 = 0xE0;  P1 = 0xE0;   delay(x);    //1DEF
                                                        P5M1 = 0xFF;  P5M0 = 0x00;  P5 = 0x00;   delay(x);    //1G
                               
                                                        break;}
      //显示1=bc=34 =1  1=0    错误 同时点亮第二位1第五第六位CD段//DP        11111000=F8  P3M0 &= ~(0xF8)
//                        P3M1 =0010 1111=2F0x27 P3M0 =1101 0000=D0        0xC8;        P3=1100 0000=C0
                        case 1:{
                                        /*                        P3M1 |= 0x2F;  P3M0 |= 0XD8;  P3 = 0xC0;   delay(x);    //1BC  0xC8 //1.               
                                                        P1M1 |= 0xFF;  P1M0 |= 0x00;  P1 = 0x00;   delay(x);    //1DEF
                                                        P5M1 |= 0xFF;  P5M0 |= 0x00;  P5 = 0x00;   delay(x);    //1G   */
                                P3M1 &= 0x20;  P3M0 |= 0xD8;  P3 = 0xC0;   delay(x);
                                P1M0 &= ~(0xE0); P1M1 |= 0xE0; P1 = 0x00;   delay(x); //
                                P5M0 &= ~(0x10); P5M1 |= 0x10; P5 = 0x00; delay(x); //
                                                        break;}
}
请解释:当前显示1,为啥显示成这样

LED.jpg (144.32 KB, 下载次数: 0)

LED.jpg
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表