今天,就在今天,终于调通了ZLG7289的实验四代码,满足,又有点虚脱,趁着热情还在,赶快记录下来。
申明一点:在这篇文章中,我不会面面俱到的将代码写得每句话解释清楚。只想将碰到的问题按照时间顺序记录,代码不够简洁,但是纯手工打造(自己写的),还是很有成就感的。
问题一:头文件的引用。
风风火火写完代码,编译爆出长长以列表的错误,undifine,undifine ...我就纳了个闷,P3这种引脚为什么没有定义,原因就在于。这次用到的文件除了配置文件c8051f020.外还有'ZLG7289.H','ZLG7089.C' P3的undifine指的是ZLG7289F020.C中未定义,因为在这个源文件中要加上头文件‘#include ‘c8051f020.h'
紧接着就是编译报错redifine。。。EXCUSES ME???刚才爆没定义,现在重复定义这其中怕是有什么误会。寻访高人后才知道,因为在main.c函数声明了#include'c8051f020.h',定义一次,在ZLG7289.C中,我又包含了头文件,造成两次定义,
解决办法是在c8051f020.h中加入#ifndef__C8051f020_H__
#define C8051f020_H
…
#endif
这句话的意思 是如果没定义,那就定义,否则不定义。
问题二:中断函数中语句的使用。
在中断中,最好做一些简单的事情,不要把封装的函数,用在里面,尤其是ZLG的Download函数,每进入这个函数,都会先关闭中断,执行命令,在开启中断,弹出函数,另外在定时器中断中,也不要有这种操作,本来定时器中断使用目的就是为了让程序每隔一段准确时间来做一些事情,如果定时器中断函数中加入多余操作会打乱定时器计时节奏,简直是沙雕行为(假装我没犯)。。。。
问题三:main()函数和中断的配合
这次实验里单片机和ZLG完成的任务是读键值,数码管显示,中断要做的就是判断有没有键被按下,是,更新标志位,是不是到了该显示的扫描时间,是,更新标志位。主函数里要做的就是判断(查询),标志位有没有改变,如果改变了,单片机该做什么。
问题四:C51单片机和ZLG芯片的通讯频率匹配问题。(灯不亮,debug时中断函数进不去,最头秃的问题)
周立功晶振4M,我选的单片机频率是外部时钟24M二分频也就是12M,在ZLG7289_Init(t)中t>5*12/4,函数注释说t值超过40可能会出错。这个t是什么意思呢?,他其实跟ZLG的输入时钟有关,ZLG通过P3^4引脚置高低电平,产生时钟,脉冲宽度就与t有关,t值越大,时钟周期越长,越与ZLG芯片匹配(速度相对于单片机是很慢的),就如同一个人(ZLG)只能每分钟挥臂30次,(单片机)非要让他每分钟挥90次,那他只能累死(ZLG跑死),ZLG可以执行动作很快,但是不能长时间以高速行驶,否则,跑死。我写的代码!
开始没有&&后面的那句,因为初始count_T=0,故会一直进入函数,函数里连续4次ZLG_Download,会让单片机跑死。真的是头一次碰到这种问题,记忆深刻。
上面的内容都是我自己瞎琢磨出来的,如有错误欢迎指正!也欢迎讨论。最后,特别感谢某郑姓男子,帮我debug。
背靠大佬就是好,就是好!
说了这么多,附上low眉low眼代码。
#include <C8051F020.H>
#include <ZLG7289.h>
char key_data;
unsigned char ss;
unsigned char sc;
unsigned char mins;
unsigned char minc;
unsigned char mss;
unsigned char msc;
unsigned int input_T;
unsigned int count_T;
unsigned char n;
unsigned char T_end;
unsigned char T_wei;
unsigned char count;
unsigned char dat;
bit flag_key;
void Delay(unsigned int t) //1ms级延时,定时器0实现
{
do
{
TH0 = 0x0FC;
TL0 = 0x18;
TR0 = 1;
while ( !TF0 );
TF0 = 0;
TR0 = 0;
} while (--t);
}
void display_end() //闪烁函数
{
TR1 = 0;
key_data = 0xFE;
for ( n=0; n<8; n++ ) //逐位闪烁
{
ZLG7289_Flash(key_data);
key_data <<= 1; key_data++; //数据 0xFE 循环左移
Delay(150);
}
ZLG7289_Flash(0x5A);
}
void display_set() //数码管前四位显示设置的时钟值
{
ZLG7289_Download(1,0,1,mins);
ZLG7289_Download(1,1,0,ss/10);
ZLG7289_Download(1,2,1,ss%10);
ZLG7289_Download(1,3,0,mss);
input_T = mss+ss*10+mins*60*10; //定时时间的总数,以100ms为单位
}
void display_jishi()
{
unsigned char scs;
unsigned char scg;
minc = count_T/600;
scg = count_T%600/10%10;
scs = count_T%600/10/10;
msc = count_T%600%100%10;
ZLG7289_Download(1,4,1,minc);
Delay(20);
ZLG7289_Download(1,5,0,scs);
Delay(20);
ZLG7289_Download(1,6,1,scg);
Delay(20);
ZLG7289_Download(1,7,0,msc);
Delay(20);
}
void function_key()
{
unsigned char n;
bit dp=1;
if(key_data == 13)
{
input_T = 0;
count_T = 0;
T_end = 0;
T_wei = 0;
TR1 = 0;
mins = input_T/600;
ss = input_T %600;
mss = input_T %600%10;
display_set();
for(n=4;n<8;n++)
{
ZLG7289_Download(1,n,dp,0);
dp=~dp;
}
}
if(key_data == 14)
TR1 = 1;
if(key_data == 15)
TR1 = ~TR1;
}
void main()
{
EA=0;
WDTCN = 0xDE;
WDTCN = 0xAD;
EA=1;
OSCXCN = 0X77; //外部时钟二分频12MHz
Delay(2);
while (!OSCXCN & 0X80);
OSCICN = 0X08;
EIE2 = 0X20; //使能外部中断7,默认下降沿触发
P3IF =0X00; //下降沿触发,清零标志位
EA = 1;
P3MDOUT = 0x0FF;
//XBR1|= 0X08;
XBR2|=0X40;
TMOD|= 0X01; //定时器0,工作1,16位
CKCON = 0X60; //定时器0、1系统时钟12分频
TMOD |= 0X10; //定时器1,工作1,16位
ET1 = 1 ; //定时器1中断使能,定时器1的优先级高于外部中断P3^7,
ZLG7289_Init(40);
Delay(100);
count = 100;
while(1)
{
if(flag_key == 1)
{
flag_key = 0;
key_data = ZLG7289_Key();
if(key_data > 9)
function_key();
else
{
T_wei++;
if(T_wei == 1)
mins = key_data;
else if(T_wei == 2)
ss = key_data;
else if (T_wei ==3)
ss = ss*10+key_data;
else if(T_wei == 4)
mss = key_data;
else
T_wei = 0;
display_set();
}
}
if (count_T%2==0&&count_T!=0)
display_jishi(); //每200ms,显示刷新
if(count_T == input_T&&count_T!=0)
end_display(); //定时时间到,闪烁函数
}
}
void Key_scan() interrupt 19
{
flag_key = 1;
P3IF= 0;
}
void timer1() interrupt 3
{
TH1 = 0x0FC;
TL1 = 0x18;
count--;
if(count == 0)
{
count =100;
count_T++;
}
}