1. 为什么会在第 5 位显示出 8?
freq_jiao=freq+seg_jiao;//频率数据的最终结果
if(freq_jiao<0)
{
wrong=1;//频率界面数码管显示LL,表示此状态错误
}
else wrong=0;
而在 serviceT1 的中断里,每 1000ms 更新一次 freq:
当测试系统改变输入频率(比如变为 100)或你通过按键改变校准值(比如变为 -300)时,这两个动作之间存在时间差。
但是,最重要的一个逻辑漏洞出现在这里: 当 freq_jiao < 0 时,你的确设置了 wrong = 1,并给 seg_buf[3]~seg_buf[5] 赋了值 10。 但是,注意看 wrong == 0 的分支(正常显示分支):
测试平台的提示:"(同时,之前频率值不为LL)"。也就是说,它之前显示了一个正常的频率,比如 freq_jiao = 800。 此时 seg_buf[5] = 800 % 1000 / 100 = 8。
然后你把校准值调成了 -300,freq_jiao 变成了负数,wrong = 1。你设置了 seg_buf[5] = 10。
为什么还会显示 8 呢? 因为你在 seg_proc() 中的这个逻辑:
void seg_proc()
{
if(seg_slow_down<80)return; // <--- 注意这里!!!
seg_slow_down=0;
// ...
你的数码管数据更新是每 80ms 更新一次 。 但是在你的中断扫描函数 serviceT1 中,数码管是 1ms 扫一位的:
if(++seg_pos==8)seg_pos=0;
seg_disp(seg_pos,seg_buf[seg_pos],seg_point[seg_pos]);
如果测试系统对你的程序进行了非常严格的时序捕捉 ,它在你在 80ms 的间隔内改变了按键或者频率,导致状态被置为错误(wrong=1),但是由于这 80ms 的延时,seg_buf 还没有来得及把 seg_buf[5] 从 8 刷新成 10(熄灭)。
为了彻底解决"残影"或者未完全覆盖的问题,我建议你修改 case 0 的写法。直接在进入 case 0 时,无条件先清空所有显示位,然后再根据状态进行覆盖。
请将你的 seg_proc 函数的 case 0 修改为:
case 0://频率界面
// 先把所有位置为熄灭,确保不会有残影
seg_buf[0]=12;
seg_buf[1]=10;
seg_buf[2]=10;
seg_buf[3]=10;
seg_buf[4]=10;
seg_buf[5]=10;
seg_buf[6]=10;
seg_buf[7]=10;
if(wrong==0)
{
seg_buf[3]=(freq_jiao>=10000)?freq_jiao/10000:10;
seg_buf[4]=(freq_jiao>=1000)?(freq_jiao%10000)/1000:10;
seg_buf[5]=(freq_jiao>=100)?(freq_jiao%1000)/100:10;
seg_buf[6]=(freq_jiao>=10)?(freq_jiao%100)/10:10;
seg_buf[7]=(freq_jiao>=0)?(freq_jiao%10)/1:10;
}
else
{
// 错误状态显示 LL
seg_buf[6]=16;
seg_buf[7]=16;
}
break;
main.c
#include <STC15F2K60S2.H>
#include <seg.h>
#include <intrins.h>
#include <ds1302.h>
#include <key.h>
#include <pcf8591.h>
#include <led.h>
#include <init.h>
unsigned int seg_slow_down;
unsigned char segmode;
idata unsigned char seg_buf[8]={10,10,10,10,10,10,10,10};
unsigned char seg_pos;
idata unsigned char seg_point[8]={0,0,0,0,0,0,0,0};
idata unsigned char ucled[8]={0,0,0,0,0,0,0,0};
unsigned char ad_slow_down;
idata unsigned char time[7]={0,0,0};//秒分时
idata unsigned char time_max[7]={0,0,0};
unsigned int t1000ms;
unsigned char t200ms;
bit liang;
idata long int freq;
idata long int freq_jiao;
idata long int freq_max;
bit s1;
bit s2;
unsigned char key_slow_down;
unsigned char key_val,key_down,key_old;
unsigned int seg_pp=2000;
unsigned int sta_pp=2000;
int seg_jiao;
idata bit wrong;
float v;
unsigned char v_out;
void serviceT1() interrupt 3//1ms进来一次
{
seg_slow_down++;
key_slow_down++;
ad_slow_down++;
if(++seg_pos==8)seg_pos=0;
seg_disp(seg_pos,seg_buf[seg_pos],seg_point[seg_pos]);
Led_Disp(ucled);
if(++t1000ms==1000)//1s
{
t1000ms=0;
TR0 = 0;//计数器T0停止计数
freq=(TH0<<8)|TL0;
TH0=0X00;
TL0=0X00;
TR0=1;
}
if(++t200ms==200)
{
t200ms=0;
liang^=1;
}
}
void working_proc()
{
if(ad_slow_down<70) return ;
ad_slow_down=0;
ucled[0]=(segmode==0)?liang:0;
ucled[1]=(freq_jiao>sta_pp)?liang:0;
//DAC输出功能
if(freq_jiao<0)//校准后为负
{
v=0;
ucled[1]=1;
}//DAC输出与测量频率关系
else if(freq_jiao>=0&&freq_jiao<=500)
{
v=1.0;
}
else if(freq_jiao>=sta_pp)
{
v=5.0;
}
else
{
v=1.0+(4.0/(sta_pp-500))*(freq_jiao-500);
}
v_out=(unsigned char )(v*51.0);
DA_zhuanhuan(v_out);
}
void seg_proc()
{
int x;
if(seg_slow_down<80)return;
seg_slow_down=0;
read_rtc(time);
freq_jiao=freq+seg_jiao;//频率数据的最终结果
if(freq_jiao<0)
{
wrong=1;//频率界面数码管显示LL,表示此状态错误
}
else wrong=0;
if(freq_jiao>freq_max)
{
freq_max=freq_jiao;
time_max[0]=time[0];
time_max[1]=time[1];
time_max[2]=time[2];
}
switch(segmode)
{
case 0://频率界面
seg_buf[0]=12;
seg_buf[1]=10;
seg_buf[2]=10;
seg_buf[3]=10;
seg_buf[4]=10;
seg_buf[5]=10;
seg_buf[6]=10;
seg_buf[7]=10;
if(wrong==0)//没有错误
{
seg_buf[3]=(freq_jiao>=10000)?freq_jiao/10000:10;
seg_buf[4]=(freq_jiao>=1000)?freq_jiao%10000/1000:10;
seg_buf[5]=(freq_jiao>=100)?freq_jiao%1000/100:10;
seg_buf[6]=(freq_jiao>=10)?freq_jiao%100/10:10;
seg_buf[7]=(freq_jiao>=0)?freq_jiao%10/1:10;
}
else//存在错误
{
seg_buf[3]=10;
seg_buf[4]=10;
seg_buf[5]=10;
seg_buf[6]=16;
seg_buf[7]=16;
}
break;
case 1://参数界面
if(s1==0)//超限参数
{
seg_buf[0]=13;
seg_buf[1]=1;
seg_buf[2]=10;
seg_buf[3]=10;
seg_buf[4]=seg_pp/1000;
seg_buf[5]=0;
seg_buf[6]=0;
seg_buf[7]=0;
}
else
{
seg_buf[0]=13;
seg_buf[1]=2;
seg_buf[2]=10;
seg_buf[3]=10;
if(seg_jiao==0)
{
seg_buf[4]=10;
seg_buf[5]=10;
seg_buf[6]=10;
seg_buf[7]=0;
}
else if(seg_jiao>0)
{
seg_buf[4]=10;
seg_buf[5]=seg_jiao/100;
seg_buf[6]=0;
seg_buf[7]=0;
}
else
{
x=-1*seg_jiao;
seg_buf[4]=11;
seg_buf[5]=x/100;
seg_buf[6]=0;
seg_buf[7]=0;
}
}
break;
case 2://时间界面
seg_buf[0]=time[2]/16;
seg_buf[1]=time[2]%16;
seg_buf[2]=11;
seg_buf[3]=time[1]/16;
seg_buf[4]=time[1]%16;
seg_buf[5]=11;
seg_buf[6]=time[0]/16;
seg_buf[7]=time[0]%16;
break;
case 3://回显界面
seg_buf[0]=14;
if(s2==0)//频率回显界面
{
seg_buf[1]=12;
seg_buf[2]=10;
seg_buf[3]=(freq_max>=10000)?freq_max/10000:10;
seg_buf[4]=(freq_max>=1000)?freq_max%10000/1000:10;
seg_buf[5]=(freq_max>=100)?freq_max%1000/100:10;
seg_buf[6]=(freq_max>=10)?freq_max%100/10:10;
seg_buf[7]=(freq_max>=0)?freq_max%10/1:10;
}
else//时间回显界面
{
seg_buf[1]=15;
seg_buf[2]=time_max[2]/16;
seg_buf[3]=time_max[2]%16;
seg_buf[4]=time_max[1]/16;
seg_buf[5]=time_max[1]%16;
seg_buf[6]=time_max[0]/16;
seg_buf[7]=time_max[0]%16;
}
break;
}
}
void key_proc()
{
if(key_slow_down<10)return ;
key_slow_down=0;
key_val = key_read();
key_down = key_val & (key_old ^ key_val);
key_old = key_val;
switch(key_down)
{
case 4:
if(++segmode==4)segmode=0;
if(segmode==1)//进入参数界面
{
seg_pp=sta_pp;
// seg_jiao=sta_jiao;
s1=0;//超限参数界面
}
if(segmode==2)//进入时间界面
{
sta_pp=seg_pp;
// sta_jiao=seg_jiao;
}
if(segmode==3)//进入回显界面
{
s2=0;//频率回显界面
}
break;
case 5:
if(segmode==1)
s1^=1;
if(segmode==3)
s2^=1;
break;
case 8:
if(segmode==1)
{
if(s1==0)//超限参数界面
{
seg_pp+=1000;
if(seg_pp>9000)seg_pp=9000;
}
else//校准值参数界面
{
seg_jiao+=100;
if(seg_jiao>900)seg_jiao=900;
}
}
break;
case 9:
if(segmode==1)
{
if(s1==0)//超限参数界面
{
seg_pp-=1000;
if(seg_pp<1000)seg_pp=1000;
}
else//校准值参数界面
{
seg_jiao-=100;
if(seg_jiao<-900)seg_jiao=-900;
}
}
break;
}
}
void main()
{
Timer1_Init();
Timer0_Init();
sys_init();
set_rtc(time);
while(1)
{
seg_proc();
working_proc();
key_proc();
}
}
seg.c
#include <seg.h>
unsigned char code seg_wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
unsigned char code seg_duan[]={0xC0,0xF9,0xA4,0xB0,0x99,
0x92,0x82,0xF8,0x80,0x90,
0xff,0xbf,0x8e,0x8c,0x89,0x88,0xc7};
void seg_disp(unsigned char wei,duan,point)
{
P0=0XFF;
P2=P2&0X1F|0XE0;
P2&=0X1F;
P0= seg_wei[wei];
P2=P2&0X1F|0Xc0;
P2&=0X1F;
P0=seg_duan[duan];
if(point==1)P0&=0x7f;
P2=P2&0X1F|0XE0;
P2&=0X1F;
}
ds1302.c
#include <ds1302.h>
#include <intrins.h>
sbit SDA=P2^3;
sbit RST=P1^3;
sbit SCK=P1^7;
unsigned char code write_rtc_addr[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
unsigned char code read_rtc_addr[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
//
void Write_Ds1302(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++)
{
SCK = 0;
SDA = temp&0x01;
temp>>=1;
SCK=1;
}
}
//
void Write_Ds1302_Byte( unsigned char address,unsigned char dat )
{
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
Write_Ds1302(dat);
RST=0;
}
//
unsigned char Read_Ds1302_Byte ( unsigned char address )
{
unsigned char i,temp=0x00;
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
for (i=0;i<8;i++)
{
SCK=0;
temp>>=1;
if(SDA)
temp|=0x80;
SCK=1;
}
RST=0; _nop_();
SCK=0; _nop_();
SCK=1; _nop_();
SDA=0; _nop_();
SDA=1; _nop_();
return (temp);
}
void set_rtc(unsigned char *time)
{
unsigned char i;
EA=0;
Write_Ds1302_Byte(0x8e,0x00);
for(i=0;i<7;i++)
{
Write_Ds1302_Byte(write_rtc_addr[i],time[i]);
}
Write_Ds1302_Byte(0x8e,0x80);
EA=1;
}
void read_rtc(unsigned char *time)
{
unsigned char i;
EA=0;
for(i=0;i<7;i++)
{
time[i]=Read_Ds1302_Byte (read_rtc_addr[i]);
}
EA=1;
}
key.c
#include <key.h>
unsigned char key_read(void)
{
unsigned char temp=0;
AUXR &= ~0x10;
P44=0;P42=1;P35=1;
//P34=1;
if(P30==0)temp=7;
if(P31==0)temp=6;
if(P32==0)temp=5;
if(P33==0)temp=4;
P44=1;P42=0;P35=1;
//P34=1;
if(P30==0)temp=11;
if(P31==0)temp=10;
if(P32==0)temp=9;
if(P33==0)temp=8;
P44=1;P42=1;P35=0;
//P34=1;
if(P30==0)temp=15;
if(P31==0)temp=14;
if(P32==0)temp=13;
if(P33==0)temp=12;
AUXR|=0X10;
return temp;
}
pcf8591.c
#include <pcf8591.h>
#include <intrins.h>
sbit sda=P2^1;
sbit scl=P2^0;
#define DELAY_TIME 1
//
static void I2C_Delay(unsigned char n)
{
do
{
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
}
while(n--);
}
//
void I2CStart(void)
{
sda = 1;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 0;
I2C_Delay(DELAY_TIME);
scl = 0;
}
//
void I2CStop(void)
{
sda = 0;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 1;
I2C_Delay(DELAY_TIME);
}
//
void I2CSendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++){
scl = 0;
I2C_Delay(DELAY_TIME);
if(byt & 0x80){
sda = 1;
}
else{
sda = 0;
}
I2C_Delay(DELAY_TIME);
scl = 1;
byt <<= 1;
I2C_Delay(DELAY_TIME);
}
scl = 0;
}
////
//unsigned char I2CReceiveByte(void)
//{
// unsigned char da;
// unsigned char i;
// for(i=0;i<8;i++){
// scl = 1;
// I2C_Delay(DELAY_TIME);
// da <<= 1;
// if(sda)
// da |= 0x01;
// scl = 0;
// I2C_Delay(DELAY_TIME);
// }
// return da;
//}
//
unsigned char I2CWaitAck(void)
{
unsigned char ackbit;
scl = 1;
I2C_Delay(DELAY_TIME);
ackbit = sda;
scl = 0;
I2C_Delay(DELAY_TIME);
return ackbit;
}
////
//void I2CSendAck(unsigned char ackbit)
//{
// scl = 0;
// sda = ackbit;
// I2C_Delay(DELAY_TIME);
// scl = 1;
// I2C_Delay(DELAY_TIME);
// scl = 0;
// sda = 1;
// I2C_Delay(DELAY_TIME);
//}
void DA_zhuanhuan(unsigned char dat)
{
EA=0;
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(0x41);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CStop();
EA=1;
}
//unsigned char AD_zhuanhuan(unsigned char addr)
//{
// unsigned char temp;
//
// I2CStart();
// I2CSendByte(0x90);
// I2CWaitAck();
// I2CSendByte(addr);
// I2CWaitAck();
//
//
// I2CStart();
// I2CSendByte(0x91);
// I2CWaitAck();
//
// temp=I2CReceiveByte();
// I2CSendAck(1);
// I2CStop();
// return temp;
//
//
//
//
//
//}
led.c
#include <led.h>
idata unsigned char temp_1 = 0x00;
idata unsigned char temp_old_1 = 0xff;
void Led_Disp(unsigned char *ucLed)
{
unsigned char temp;
temp_1=0x00;
temp_1 = (ucLed[0] << 0) | (ucLed[1] << 1) | (ucLed[2] << 2) | (ucLed[3] << 3) |
(ucLed[4] << 4) | (ucLed[5] << 5) | (ucLed[6] << 6) | (ucLed[7] << 7);
if (temp_1 != temp_old_1)
{
P0 = ~temp_1;
// 操作P2锁存器
temp = P2 & 0x1f; // 保留P2的低5位
temp = temp | 0x80; // 与0x80进行或操作
P2 = temp; // 写入P2
temp = P2 & 0x1f; // 保留P2的低5位
P2 = temp; // 写入P2,关闭锁存器
temp_old_1 = temp_1;
}
}
init.c
#include <init.h>
void Timer1_Init(void) //1毫秒@12.000MHz
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x18; //设置定时初始值
TH1 = 0xFC; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1=1;
EA=1;
}
void Timer0_Init(void) //1毫秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TMOD |=0X05;
TL0 = 0X00; //设置定时初始值
TH0 = 0x00; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
void sys_init()
{
P0=0x00;//蜂鸣器
P2=P2&0x1f|0xa0;
P2&=0x1f;
P0=0xff;//led
P2=P2&0x1f|0x80;
P2&=0x1f;
}
