碎碎念:这一届的难点我觉得在于PWM输出与其他模块之间的冲突,同时如果不使用PCA的话还有定时器之间的冲突的问题。我最开始做的时候并没有在意这些细节上的问题,然后出了许多问题,比如LED和数码管乱闪,IIC时序异常等,现在虽然解决了一部分,但还是有一些瑕疵。
一.题目要求:
自己的一些见解:
关于NE555:
在测量频率的时候,我发现数码管显示的频率与频率计测出的频率误差较大,排查之后发现问题处在PCA上,因为我时在定时器中调用了超声波,但超声波SendWave的时候会有12*2*8的延时,这段延时对频率测量的影响还是蛮大的,所以我这里新开了一个定时器2用于频率测量.
关于PWM:
PWM实现的时候,出现LED,数码管乱闪的问题,我初步推测是应为PWM中断的频率太高( 100us),导致P0口的值非常复杂,而且一开始的时候, 我是每进一次中断都会给P0口赋值,加重了P0口值的混乱。只有我便采取了几种措施.一是提高定时器的计数周期(100us改到200us),之后不再是每进一次中断对P0口赋值一次,而是在占空比处和计数值为10的时候分别赋值,第三便是在进中断的时候先存好P0口的值,中断结束后将P0原先的值赋值回去.
void Timer1_Service() interrupt 3
{
unsigned char temp;
count_times++;
PWM_times++;
temp=P0;
if(count_times==5000)
{
dat_F=count_F;
count_F=0;
count_times=0;
}
if(LED_Flag==1)
{
if(count_times%500==0)
{
Flash_Flag=~Flash_Flag;
if(Flash_Flag==1)
{
if(SMG_Mode==1)
{
LED_Mode=(LED_Mode|0x07)&0xfe;
SelectHC573(4,LED_Mode);
}
else if(SMG_Mode==2)
{
LED_Mode=(LED_Mode|0x07)&0xfd;
SelectHC573(4,LED_Mode);
}
else if(SMG_Mode==3)
{
LED_Mode=(LED_Mode|0x07)&0xfb;
SelectHC573(4,LED_Mode);
}
}
else if(Flash_Flag==0)
{
LED_Mode|=0x07;
SelectHC573(4,LED_Mode);
}
}
}
if(PWM_times==5)
{
jdq_Mode|=0x20;
PWM_times=0;
}
if(PWM_times==Duty)
{
jdq_Mode&=0xdf;
}
SelectHC573(5,jdq_Mode);
P0=temp;
}
第二便是PWM影响IIC时序问题,之前采用的是在iic中直接关闭总中断的方式,当时表面上没有什么问题,但拿频率计测量发现,pwm的频率降为800khz左右,不符合要求,之后我看题目要求中对ADC没有时间上的要求,所以将ADC刷新的时间延迟,放在定时器中没-.5s调用一次,整体观感和性能还是不错的,但数码管还有偶尔会闪烁.
关于掉电不丢失:
掉电不丢失有一个点就是是否第一次上电,我的解决方法是在一个内存地址内写入一个标志位(随便写,我这里采用的是0xac),上电的时候先读取标志位,如果读取到了说明不是第一次,之间读取即可,如果读取到的数据不对,则对存放内容的地址空间写入0
二.代码部分:
main.c
#include <STC15F2K60S2.H>
#include "intrins.h"
#include "iic.h"
sbit S4=P3^3;
sbit S5=P3^2;
sbit S6=P3^1;
sbit S7=P3^0;
sbit TX=P1^0;
code unsigned char SMG_Nodot[] =
{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
code unsigned char SMG_Dot[] =
{0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
unsigned char SMG_Mode=1;
unsigned char show_Mode=1;
unsigned int dat_F;
unsigned int count_F;
unsigned char shidu;
unsigned char PCA_times;
unsigned char Distance;
unsigned char param_Mode=1;
unsigned char fre_param=90;
unsigned char shidu_param=40;
unsigned char Dis_param=6;
unsigned int count_times;
unsigned char ADC_Value;
unsigned char DAC_Value;
bit PCA_Flag;
unsigned int times;
unsigned char jdq_Mode=0x00;
unsigned char LED_Mode=0xff;
bit LED_Flag;
bit Flash_Flag;
unsigned char Duty;
unsigned char PWM_times;
unsigned char chufa_times;
bit chufa_Flag=0;
unsigned int Key_times;
bit Key_Flag=0;
void Delay_SMG(unsigned int t)
{
while(t--);
}
void Delay12us() //@12.000MHz
{
unsigned char i;
_nop_();
_nop_();
i = 33;
while (--i);
}
void SelectHC573(unsigned char channel,unsigned char dat)
{
P2=(P2&0x1f)|0x00;
P0=dat;
switch(channel)
{
case 4:
P2=(P2&0x1f)|0x80;
break;
case 5:
P2=(P2&0x1f)|0xa0;
break;
case 6:
P2=(P2&0x1f)|0xc0;
break;
case 7:
P2=(P2&0x1f)|0xe0;
break;
case 0:
P2=(P2&0x1f)|0x00;
break;
}
P2=(P2&0x1f)|0x00;
}
void Display_SMG(unsigned char pos,unsigned char dat)
{
SelectHC573(6,0x01<<(pos-1));
SelectHC573(7,dat);
Delay_SMG(500);
SelectHC573(6,0x01<<(pos-1));
SelectHC573(7,0xff);
}
void Display_Dynamic()
{
if(SMG_Mode==1)
{
Display_SMG(1,SMG_Nodot[15]);
Display_SMG(2,SMG_Nodot[chufa_times/10]);
Display_SMG(3,SMG_Nodot[chufa_times%10]);
if(show_Mode==1)
{
if(dat_F>9999)
{
Display_SMG(4,SMG_Nodot[dat_F/10000]);
}
if(dat_F>999)
{
Display_SMG(5,SMG_Nodot[dat_F%10000/1000]);
}
if(dat_F>99)
{
Display_SMG(6,SMG_Nodot[dat_F%1000/100]);
}
if(dat_F>9)
{
Display_SMG(7,SMG_Nodot[dat_F%100/10]);
}
Display_SMG(8,SMG_Nodot[dat_F%10]);
}
if(show_Mode==2)
{
if(dat_F>9999)
{
Display_SMG(6,SMG_Nodot[dat_F/10000]);
}
Display_SMG(7,SMG_Dot[dat_F%10000/1000]);
Display_SMG(8,SMG_Nodot[dat_F%1000/100]);
}
}
if(SMG_Mode==2)
{
Display_SMG(1,0x89);
Display_SMG(7,SMG_Nodot[shidu/10]);
Display_SMG(8,SMG_Nodot[shidu%10]);
}
if(SMG_Mode==3)
{
Display_SMG(1,SMG_Nodot[10]);
if(show_Mode==1)
{
if(Distance>99)
{
Display_SMG(6,SMG_Nodot[Distance/100]);
}
if(Distance>9)
{
Display_SMG(7,SMG_Nodot[Distance%100/10]);
}
Display_SMG(8,SMG_Nodot[Distance%10]);
}
if(show_Mode==2)
{
Display_SMG(6,SMG_Dot[Distance/100]);
Display_SMG(7,SMG_Nodot[Distance%100/10]);
Display_SMG(8,SMG_Nodot[Distance%10]);
}
}
if(SMG_Mode==4)
{
Display_SMG(1,0x8c);
Display_SMG(2,SMG_Nodot[param_Mode]);
if(param_Mode==1)
{
if(fre_param>99)
{
Display_SMG(6,SMG_Nodot[fre_param/100]);
}
Display_SMG(7,SMG_Dot[fre_param%100/10]);
Display_SMG(8,SMG_Nodot[fre_param%10]);
}
if(param_Mode==2)
{
Display_SMG(7,SMG_Nodot[shidu_param/10]);
Display_SMG(8,SMG_Nodot[shidu_param%10]);
}
if(param_Mode==3)
{
Display_SMG(7,SMG_Dot[Dis_param/10]);
Display_SMG(8,SMG_Nodot[Dis_param%10]);
}
}
}
void Timer1Init(void) //200us@12.000MHz
{
AUXR &= 0xBF;
TMOD = 0x06;
TL1 = 0x38;
TH1 = 0xFF;
TF1 = 0;
TR1 = 1;
EA=1;
ET1=1;
}
void Timer2Init(void) //1ms@12.000MHz
{
AUXR &= 0xFB;
T2L = 0x18;
T2H = 0xFC;
AUXR |= 0x10;
IE2=0x04;
}
void Timer0_Init()
{
TH0=0xff;
TL0=0xff;
TR0=1;
ET0=1;
}
void Timer0_Service() interrupt 1
{
count_F++;
}
void PCA_Init()
{
CMOD=0x01;
CCON=0x00;
CCAPM0=0x11;
}
void Send_Wave()
{
unsigned char i;
for(i=0;i<8;i++)
{
TX=0;
Delay12us();
TX=1;
Delay12us();
}
}
void Measure_Distance()
{
CH=CL=0;
Send_Wave();
CR=1;
if(PCA_Flag==0)
{
Distance=255;
}
if(PCA_Flag==1)
{
Distance=times*0.017;
}
}
void PCA_Service() interrupt 7
{
CR=0;
if(CCF0==1)
{
CCF0=0;
PCA_Flag=1;
times=(CCAP0H<<8)|CCAP0L;
}
if(CF==1)
{
CF=0;
PCA_Flag=0;
}
}
void Timer1_Service() interrupt 3
{
unsigned char temp;
count_times++;
PWM_times++;
temp=P0;
if(count_times==5000)
{
dat_F=count_F;
count_F=0;
count_times=0;
}
if(LED_Flag==1)
{
if(count_times%500==0)
{
Flash_Flag=~Flash_Flag;
if(Flash_Flag==1)
{
if(SMG_Mode==1)
{
LED_Mode=(LED_Mode|0x07)&0xfe;
SelectHC573(4,LED_Mode);
}
else if(SMG_Mode==2)
{
LED_Mode=(LED_Mode|0x07)&0xfd;
SelectHC573(4,LED_Mode);
}
else if(SMG_Mode==3)
{
LED_Mode=(LED_Mode|0x07)&0xfb;
SelectHC573(4,LED_Mode);
}
}
else if(Flash_Flag==0)
{
LED_Mode|=0x07;
SelectHC573(4,LED_Mode);
}
}
}
if(PWM_times==5)
{
jdq_Mode|=0x20;
PWM_times=0;
}
if(PWM_times==Duty)
{
jdq_Mode&=0xdf;
}
SelectHC573(5,jdq_Mode);
P0=temp;
}
void Timer2_Service() interrupt 12
{
PCA_times++;
if(PCA_times==125)
{
PCA_times=0;
Measure_Distance();
}
if(Key_Flag==1)
{
Key_times++;
}
}
void ADC_Read()
{
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(0x43);
I2CWaitAck();
I2CStop();
EA=0;
I2CStart();
I2CSendByte(0x91);
I2CWaitAck();
ADC_Value=I2CReceiveByte();
EA=1;
I2CSendAck(1);
I2CStop();
shidu=ADC_Value/255.0*99;
}
void DAC_Caculate()
{
float k;
k=204.0/(80-shidu_param);
if(shidu>80)
{
DAC_Value=255;
}
if(shidu<shidu_param)
{
DAC_Value=51;
}
if(shidu<80&&shidu>shidu_param)
{
DAC_Value=k*(shidu-shidu_param)+51;
}
}
void DAC_Write()
{
DAC_Caculate();
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(0x43);
I2CWaitAck();
I2CSendByte(DAC_Value);
I2CWaitAck();
I2CStop();
}
unsigned char AT24C02_Read(unsigned char address)
{
unsigned char temp;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
temp=I2CReceiveByte();
I2CSendAck(1);
I2CStop();
return temp;
}
void AT24C02_Write(unsigned char dat)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(0x00);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CSendByte(0xac);
I2CWaitAck();
I2CStop();
}
void Scan_Key()
{
if(S4==0)
{
Delay_SMG(500);
if(S4==0)
{
switch(SMG_Mode)
{
case 1:
SMG_Mode=2;
break;
case 2:
SMG_Mode=3;
show_Mode=1;
break;
case 3:
SMG_Mode=4;
param_Mode=1;
break;
case 4:
SMG_Mode=1;
show_Mode=1;
break;
}
}
while(S4==0)
{
Display_Dynamic();
ADC_Read();
}
}
if(S5==0)
{
Delay_SMG(500);
if(S5==0)
{
if(SMG_Mode==4)
{
switch(param_Mode)
{
case 1:
param_Mode=2;
break;
case 2:
param_Mode=3;
break;
case 3:
param_Mode=1;
break;
}
}
}
while(S5==0)
{
Display_Dynamic();
ADC_Read();
}
}
if(S6==0)
{
Delay_SMG(500);
if(S6==0)
{
if(SMG_Mode==3)
{
switch(show_Mode)
{
case 1:
show_Mode=2;
break;
case 2:
show_Mode=1;
break;
}
}
if(SMG_Mode==4)
{
if(param_Mode==1)
{
fre_param+=5;
if(fre_param>120)
{
fre_param=10;
}
}
if(param_Mode==2)
{
shidu_param+=10;
if(shidu_param>60)
{
shidu_param=10;
}
}
if(param_Mode==3)
{
Dis_param+=1;
if(Dis_param>12)
{
Dis_param=1;
}
}
}
}
while(S6==0)
{
Display_Dynamic();
ADC_Read();
}
}
if(S7==0)
{
Delay_SMG(500);
if(S7==0)
{
while(S7==0)
{
Key_Flag=1;
Display_Dynamic();
ADC_Read();
}
Key_Flag=0;
if(Key_times>1000)
{
if(SMG_Mode==2)
{
chufa_times=0;
AT24C02_Write(chufa_times);
}
}
if(Key_times<=1000)
{
if(SMG_Mode==1)
{
switch(show_Mode)
{
case 1:
show_Mode=2;
break;
case 2:
show_Mode=1;
break;
}
}
if(SMG_Mode==4)
{
if(param_Mode==1)
{
fre_param-=5;
if(fre_param<10)
{
fre_param=120;
}
}
if(param_Mode==2)
{
shidu_param-=10;
if(shidu_param<10)
{
shidu_param=60;
}
}
if(param_Mode==3)
{
Dis_param-=1;
if(Dis_param<1)
{
Dis_param=12;
}
}
}
}
Key_times=0;
}
}
}
void PWM_Config()
{
if(dat_F>fre_param*100)
{
Duty=4;
}
if(dat_F<fre_param*100)
{
Duty=1;
}
}
void jdq_Control()
{
if(Distance>Dis_param*10)
{
jdq_Mode|=0x10;
SelectHC573(5,jdq_Mode);
if(chufa_Flag==1)
{
chufa_Flag=0;
chufa_times++;
AT24C02_Write(chufa_times);
}
}
if(Distance<Dis_param*10)
{
jdq_Mode&=0xef;
SelectHC573(5,jdq_Mode);
chufa_Flag=1;
}
}
void LED_control()
{
if(SMG_Mode==1||SMG_Mode==2||SMG_Mode==3)
{
LED_Flag=1;
}
if(SMG_Mode==4)
{
LED_Flag=0;
LED_Mode|=0x07;
}
if(dat_F>fre_param)
{
LED_Mode&=0xf7;
SelectHC573(4,LED_Mode);
}
if(dat_F<fre_param)
{
LED_Mode|=0x08;
SelectHC573(4,LED_Mode);
}
if(shidu>shidu_param)
{
LED_Mode&=0xef;
SelectHC573(4,LED_Mode);
}
if(shidu<shidu_param)
{
LED_Mode|=0x10;
SelectHC573(4,LED_Mode);
}
if(Distance>Dis_param*10)
{
LED_Mode&=0xdf;
SelectHC573(4,LED_Mode);
}
if(Distance<Dis_param*10)
{
LED_Mode|=0x20;
SelectHC573(4,LED_Mode);
}
}
void Sys_Init()
{
SelectHC573(4,0xff);
SelectHC573(5,0x00);
Timer1Init();
EA=0;
Timer0_Init();
Timer2Init();
PCA_Init();
if(AT24C02_Read(0x01)!=0xac)
{
AT24C02_Write(0);
}
if(AT24C02_Read(0x01)==0xac)
{
chufa_times=AT24C02_Read(0x00);
}
EA=1;
}
void main()
{
Sys_Init();
while(1)
{
Display_Dynamic();
Scan_Key();
ADC_Read();
DAC_Write();
jdq_Control();
PWM_Config();
LED_control();
}
}
iic.h
/* # I2C代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include <STC15F2K60S2.H>
#include "intrins.h"
sbit scl=P2^0;
sbit sda=P2^1;
#define DELAY_TIME 10
//
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);
}