亚洲春色中文字幕久久久-三上亚,91精品国产亚一区二区三区,久久久九色综合亚洲成色777,涩涩视频下载,国产午夜亚洲精品午夜鲁丝片,国产精品A一区二区三区腾讯导航,影音先锋色情AV在线看片,蜜臀国产在线视频,极品少妇高潮啪啪无码吴梦梦 ,精品人妻无码一区二区三区手机版

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 3813|回復: 16
打印 上一主題 下一主題
收起左側

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空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏3 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
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
回復

使用道具 舉報

15#
ID:69038 發表于 2025-8-29 21:25 | 只看該作者
宏達工控 發表于 2025-8-29 17:47
void Io_init (void)// 模式初值設置
{
    P1M0 &= ~(0xE0); P1M1 |= 0xE0;   // 設置P1.5, P1.6, P1.7 ...

看你這圖中的LED的管腳,不是高(紅)就是低(藍)。。高阻或辦入態的應該是灰色才對
不知道是不是沒有開高阻,或是Proteus中的51模型不能正確設為高阻?
回復

使用道具 舉報

16#
ID:1133081 發表于 2025-8-29 22:12 | 只看該作者
宏達工控 發表于 2025-8-29 17:47
void Io_init (void)// 模式初值設置
{
    P1M0 &= ~(0xE0); P1M1 |= 0xE0;   // 設置P1.5, P1.6, P1.7 ...

樓主想多了,Proteus根本不能正常仿真查理復用驅動LED,更無法仿真查理復用驅動數碼管。不信你仿真PWM調LED亮度試試。
回復

使用道具 舉報

17#
ID:611626 發表于 2025-8-30 08:41 | 只看該作者
WL0123 發表于 2025-8-29 22:12
樓主想多了,Proteus根本不能正常仿真查理復用驅動LED,更無法仿真查理復用驅動數碼管。不信你仿真PWM調L ...

我說哪,瞎忙活 了幾天,邏輯怎么修改都不行
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表