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