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);
}
}
|