本次使用到的模块大概有:超声波测距、EEPROM读和写、时钟DS1302、矩阵键盘、数码管显示
这一届国赛感觉不是特别难,但是还是有几点需要注意:
1.不要把超声波程序写在中断里面。如果把超声波程序写在中断里面的话,可能就不会及时的检测到溢出标志,在我开始验证代码的时候出现的现象是最后一个数码管闪烁,然后把超声波写在主函数里面就解决了问题。
2.程序里面经常调用的代码,写在函数里面,会大大减少代码量和重复代码,并且利于检查以及代码美观。如写EEPROM和读EEPROM可以专门写在函数里面,在我们要修改的时候直接调用函数传递一个参数进去就行了,也比如我们在输入密码的时候,计算密码这一重复的工作,可以直接写在函数里面,这样我们在检测到按键的时候,就可以直接调用函数,不需要每一次都在里面计算。
本次用到的模块:
超声波测距:
超声波测距发射8个脉冲函数以及延时13us函数
void Delay13us() //@11.0592MHz
{
unsigned char i;
_nop_();
_nop_();
i = 33;
while (--i);
}
void sonic_send(void)
{
u8 i = 8;
while( i-- )
{
TX = 1;
Delay13us();
TX = 0;
Delay13us();
}
}
超声波函数:
TR0 = 0;
sonic_send();
TR0 = 1;
while(RX == 1 && TF0 == 0 );
TR0 = 0;
if(TF0 == 1)
{
TF0 = 0;
distance = 999;
}
else
{
distance = TH0;
distance = (distance<<8)|TL0;
distance = (u16)(distance*0.00153718);
}
TH0 = 0;
TL0 = 0;
DS1302初始化时间以及读取时间函数:
void DS1302_INIT(void)
{
unsigned char i,add = 0x80;
Write_Ds1302_Byte(0x8e,0x00);
for(i = 0;i < 7 ; i++)
{
Write_Ds1302_Byte(add,Time[i]);
add += 2;
}
Write_Ds1302_Byte(0x8e,0x80);
}
void DS1302_GET(void)
{
unsigned char i,add = 0x81;
Write_Ds1302_Byte(0x8e,0x00);
for(i = 0;i < 7 ; i++)
{
Time[i] = Read_Ds1302_Byte(add);
add += 2;
}
Write_Ds1302_Byte(0x8e,0x80);
}
写EEPROM函数和读EEPROM函数
void Write_AT24C02(unsigned char add,unsigned char dat)
{
IIC_Start();
IIC_SendByte(0XA0);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
unsigned char Read_AT24C02(unsigned char add)
{
unsigned char temp;
IIC_Start();
IIC_SendByte(0XA0);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0XA1);
IIC_WaitAck();
temp = IIC_RecByte();
IIC_WaitAck();
return temp;
}
完整代码:
#include <STC15F2K60S2.h>
#include <intrins.h>
#include "iic.h"
#include "ds1302.h"
#define u8 unsigned char
#define u16 unsigned int
u8 code LED[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff};
u8 KEY_TEMP,KEY = 0XFF;
u8 Digcom = 0, Digbuf[] = {1,2,3,4,10,10,10,10};
sbit RX = P1^1;
sbit TX = P1^0;
u16 distance = 999,T = 0,T_GATE = 0,password = 0;
u8 Tmeasure = 0,intr = 0,shezhi = 0,error = 0;
bit flag = 0,KEY_FLAG = 0,GATE_FLAG = 0;
bit flag1 = 0,flag2 = 0,flag3 = 0,flag4 = 0,zidong = 1;
u8 yi = 10,er = 10,san = 11,si = 11,wu = 11,liu = 11,qi = 11,ba = 11;
u16 DELAY_TIME;
extern u8 Time[];
void Delay13us() //@11.0592MHz
{
unsigned char i;
_nop_();
_nop_();
i = 33;
while (--i);
}
void delay_ms(u16 ms)
{
u16 i,j;
for(i = ms; i>0 ; i--)
for(j = 845; j > 0 ; j--);
}
void INIT(void)
{
P2 |= 0X80;
P2 &= 0X9F;
P0 = 0XFF;
P2 |= 0XA0;
P2 &= 0XBF;
P0 = 0X00;
P2 |= 0XC0;
P2 &= 0XDF;
P0 = 0XFF;
P2 |= 0XE0;
P2 &= 0XFF;
P0 = 0XFF;
}
void Relay_ON(void)
{
P2 |= 0XA0;
P2 &= 0XBF;
P0 = 0X10;
}
void OFF(void) //关掉蜂鸣器和继电器
{
P2 |= 0XA0;
P2 &= 0XBF;
P0 = 0X00;
}
void Buzz_ON(void)
{
P2 |= 0XA0;
P2 &= 0XBF;
P0 = 0X40;
}
void Get_Password(u8 temp)
{
if(intr <= 6)password = password*10 + temp;
if(intr == 1) san = temp;
else if(intr == 2) si = temp;
else if(intr == 3) wu = temp;
else if(intr == 4) liu = temp;
else if(intr == 5) qi = temp;
else if(intr == 6) ba = temp;
}
u16 Read_Password()
{
u16 temp;
temp = Read_AT24C02(0XA0);
temp = temp*100;
temp += Read_AT24C02(0XA1);
temp = temp*100;
temp += Read_AT24C02(0XA2);
return temp;
}
void Write_Password(u16 temp)
{
Write_AT24C02(0XA0,temp/10000);delay_ms(5);
Write_AT24C02(0XA1,temp/100%100);delay_ms(5);
Write_AT24C02(0XA2,temp%100);delay_ms(5);
}
void KEY_KBD(void)
{
u16 temp; //暂时存储当前的密码
bit zhengque = 0;
P3 = 0X7F;P44 = 0;P42 = 1;
KEY_TEMP = P3 & 0X0F;
if(KEY_TEMP != 0x0f && flag1 == 0 && zidong == 0)
{
delay_ms(5);
KEY_TEMP = P3&0X0F;
if(KEY_TEMP != 0x0f)
{
flag1 = 1;
KEY_TEMP = P3;
switch(KEY_TEMP)
{
case 0x7E:intr++;Get_Password(0);break;
case 0x7D:intr++;Get_Password(4);break;
case 0x7B:intr++;Get_Password(8);break;
// case 0x77:intr++; qi = 0;ba = 4;break;
}
}
}
else if(KEY_TEMP == 0x0f && flag1)
{
delay_ms(5);
KEY_TEMP = P3 & 0X0F;
if(KEY_TEMP == 0x0f)
{
flag1 = 0;
}
}
P3 = 0XbF;P44 = 1;P42 = 0;
KEY_TEMP = P3 & 0X0F;
if(KEY_TEMP != 0x0f && flag2 == 0 && zidong == 0)
{
delay_ms(5);
KEY_TEMP = P3&0X0F;
if(KEY_TEMP != 0x0f)
{
flag2 = 1;
KEY_TEMP = P3;
switch(KEY_TEMP)
{
case 0xbE:intr++;Get_Password(1);break;
case 0xbD:intr++;Get_Password(5);break;
case 0xbB:intr++;Get_Password(9);break;
// case 0xb7:qi = 0;ba = 8;break;
}
}
}
else if(KEY_TEMP == 0x0f && flag2)
{
delay_ms(5);
KEY_TEMP = P3 & 0X0F;
if(KEY_TEMP == 0x0f)
{
flag2 = 0;
}
}
P3 = 0XdF;P42 = 1;P44 = 1;
KEY_TEMP = P3 & 0X0F;
if(KEY_TEMP != 0x0f && flag3 == 0 && zidong == 0)
{
delay_ms(5);
KEY_TEMP = P3&0X0F;
if(KEY_TEMP != 0x0f)
{
flag3 = 1;
KEY_TEMP = P3;
switch(KEY_TEMP)
{
case 0xDE:intr++;Get_Password(2);break;
case 0xDD:intr++;Get_Password(6);break;
case 0xDB: //设置按键
if(shezhi == 0)shezhi = 1;
yi = 11;er = 10;san = 11;si = 11;
wu = 11;liu = 11;qi = 11;ba = 11;
break;
case 0xD7: //确认按键
if(shezhi == 0 || shezhi == 1)
{
temp = Read_Password();
if(password == temp) //密码正确并且不是设置状态打开继电器
{
error = 0;
zhengque = 1;
DELAY_TIME = 5000;
GATE_FLAG = 1;
Relay_ON(); //打开继电器
T_GATE = 0; //从头开始计时5s
}
else if(password != temp) //密码不正确,蜂鸣器报警三秒
{
if(++error == 3)
{
error = 0;
DELAY_TIME = 3000;
GATE_FLAG = 1;
Buzz_ON(); //打开继电器
T_GATE = 0; //从头开始计时3s
}
}
}
else if(shezhi == 2)
{
Write_Password(password);
}
if(shezhi == 0 || shezhi == 2)//密码输入完成,显示密码初始界面
{
yi = 10;er = 10;san = 11;si = 11;
wu = 11;liu = 11;qi = 11;ba = 11;
if(shezhi == 2)shezhi = 0 ;
}
else if(shezhi == 1 && zhengque)
{
yi = 10;er = 11;san = 11;si = 11;
wu = 11;liu = 11;qi = 11;ba = 11;
shezhi = 2;
}
else if(shezhi == 1 && zhengque == 0)
{
yi = 11;er = 10;san = 11;si = 11;
wu = 11;liu = 11;qi = 11;ba = 11;
}
password = 0;
intr = 0;
break; //确认按键,表示当前输入完成
}
}
}
else if(KEY_TEMP == 0x0f && flag3)
{
delay_ms(5);
KEY_TEMP = P3 & 0X0F;
if(KEY_TEMP == 0x0f)
{
flag3 = 0;
}
}
P3 = 0XeF;P42 = 1;P44 = 1;
KEY_TEMP = P3 & 0X0F;
if(KEY_TEMP != 0x0f && flag4 == 0 && zidong == 0)
{
delay_ms(5);
KEY_TEMP = P3 & 0X0F;
if(KEY_TEMP != 0x0f)
{
flag4 = 1;
KEY_TEMP = P3;
switch(KEY_TEMP)
{
case 0xEE:intr++;Get_Password(3);break;
case 0xED:intr++;Get_Password(7);break;
case 0xEB: //复位按键,恢复初始密码654321
Write_Password(654321);
intr = 0;
password = 0;
break;
case 0xE7: //退出按键,显示输入密码状态
yi = 10;er = 10;san = 11;si = 11;
wu = 11;liu = 11;qi = 11;ba = 11;
intr = 0;
shezhi = 0;
password = 0;
break;
}
}
}
else if(KEY_TEMP == 0x0f && flag4)
{
delay_ms(5);
KEY_TEMP = P3 & 0X0F;
if(KEY_TEMP == 0x0f)
{
flag4 = 0;
}
}
}
void sonic_send(void)
{
u8 i = 8;
while( i-- )
{
TX = 1;
Delay13us();
TX = 0;
Delay13us();
}
}
void Timer2Init(void) //1毫秒@11.0592MHz
{
AUXR |= 0x04; //定时器时钟1T模式
T2L = 0xCD; //设置定时初值
T2H = 0xD4; //设置定时初值
AUXR |= 0x10; //定时器2开始计时
IE2 |= 0X04;
EA = 1;
}
void timer2(void)interrupt 12
{
//数码管动态显示
P2 |= 0XC0;
P2 &= 0XDF;
P0 = (0X01<<Digcom);
P2 |= 0xE0;
P2 &= 0XFF;
P0 = LED[Digbuf[Digcom]];
if(++Digcom == 8) Digcom = 0;
//超声波测距(200毫秒一次)
if(++Tmeasure == 200 && zidong) //只有在自动的工作状态下才检测距离
{
Tmeasure = 0;
flag = 1;
}
//继电器打开5s
if(++T_GATE == DELAY_TIME && GATE_FLAG)
{
GATE_FLAG = 0;
T_GATE = 0;
OFF(); //关掉蜂鸣器和继电器
}
}
void Timer0Init(void)
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x00; //设置定时初值
TH0 = 0x00; //设置定时初值
TF0 = 0; //清除TF0标志
// TR0 = 1; //定时器0开始计时
}
void main()
{
u8 temp;
//初始化外设、定时器、时钟
INIT();
Timer2Init();
Timer0Init();
DS1302_INIT();
//把初始密码写进EEPROM里面
Write_Password(654321);
while(1)
{
//读取时间
DS1302_GET();
temp = Time[2]/16;
temp = temp*10 + (Time[2]%16);
if( temp>=7 && temp < 22 ) zidong = 1;
else zidong = 0;
//判断工作状态
if(zidong)
{
Digbuf[0] = Time[2]/16; Digbuf[1] = Time[2]%16;
Digbuf[2] = 10; Digbuf[3] = Time[1]/16;
Digbuf[4] = Time[1]%16; Digbuf[5] = 10;
Digbuf[6] = Time[0]/16; Digbuf[7] = Time[0]%16;
if(distance < 30 && GATE_FLAG == 0) //自动工作状态下,如果距离小于30厘米
{
DELAY_TIME = 5000;
GATE_FLAG = 1;
Relay_ON(); //打开继电器
T_GATE = 0; //从头开始计时5s
}
if(flag)
{
flag = 0;
TR0 = 0;
sonic_send();
TR0 = 1;
while(RX == 1 && TF0 == 0 );
TR0 = 0;
if(TF0 == 1)
{
TF0 = 0;
distance = 999;
}
else
{
distance = TH0;
distance = (distance<<8)|TL0;
distance = (u16)(distance*0.00153718);
}
TH0 = 0;
TL0 = 0;
}
}
else
{
Digbuf[0] = yi; Digbuf[1] = er;
Digbuf[2] = san; Digbuf[3] = si;
Digbuf[4] = wu; Digbuf[5] = liu;
Digbuf[6] = qi; Digbuf[7] = ba;
}
KEY_KBD();
}
}