本人参加了第十届蓝桥杯单片机比赛,现将整理过的自己写的第四届国赛的程序给大家参考一下。烧录国信长天的单片机即可工作。
以下有
1个main.c
1个iic.c
1个iic.h
1个ds1302.c
1个ds1302.h
#include<stc15f2k60s2.h>
#include<intrins.h>
#include<ds1302.h>
#include<iic.h>
#define somenop {nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();}
#define u8 unsigned char
u8 code smg_duan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,0x40};
u8 code smg_wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
sbit buzzer=P0^6;
sbit relay= P0^4;
sbit RX=P1^1;
sbit TX=P1^0;
#define KEY P3
#define NO_KEY 0xff
#define KEY_STATE0 0
#define KEY_STATE1 1
#define KEY_STATE2 2
u8 xian_shi[8];
u8 mo_si=1,shi_zhong;
void send_wave()
{
TX=1;
somenop;somenop;somenop;somenop;somenop;
somenop;somenop;somenop;somenop;somenop;
TX=0;
}
void Delay2ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
i = 22;
j = 128;
do
{
while (--j);
} while (--i);
}
u8 key_scan() //状态机键盘处理
{
static unsigned char key_state=KEY_STATE0;
u8 key_value=0,key_temp;
u8 key1,key2;
P30=0;P31=0;P32=0;P33=0;P34=1;P35=1;P42=1;P44=1;
if(P440) key1=0x70;
if(P420) key1=0xb0;
if(P350) key1=0xd0;
if(P340) key1=0xe0;
if((P341)&&(P351)&&(P421)&&(P441)) key1=0xf0;
P30=1;P31=1;P32=1;P33=1;P34=0;P35=0;P42=0;P44=0;
if(P300) key2=0x0e;
if(P310) key2=0x0d;
if(P320) key2=0x0b;
if(P330) key2=0x07;
if((P301)&&(P311)&&(P321)&&(P331)) key2=0x0f;
key_temp=key1|key2;
switch(key_state)
{
case KEY_STATE0:
if(key_temp!=NO_KEY)
{
key_state=KEY_STATE1;
}
break;
case KEY_STATE1:
if(key_tempNO_KEY)
{
key_state=KEY_STATE0;
}
else
{
switch(key_temp)
{
case 0x77:key_value=4 ;break;
case 0x7b:key_value=5 ;break;
case 0x7d:key_value=6 ;break;
case 0x7e:key_value=7 ;break;
case 0xb7:key_value=8 ;break;
case 0xbb:key_value=9 ;break;
case 0xbd:key_value=10;break;
case 0xbe:key_value=11;break;
case 0xd7:key_value=12;break;
case 0xdb:key_value=13;break;
case 0xdd:key_value=14;break;
case 0xde:key_value=15;break;
case 0xe7:key_value=16;break;
case 0xeb:key_value=17;break;
case 0xed:key_value=18;break;
case 0xee:key_value=19;break;
}
key_state=KEY_STATE2;
}
break;
case KEY_STATE2:
if(key_tempNO_KEY)
{
key_state=KEY_STATE0;
}
break;
}
return key_value;
}
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 43;
j = 6;
k = 203;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Timer0Init(void) //1毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初值
TH0 = 0xD4; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
EA = 1;
}
void Time1Init() //超声波计时用
{
AUXR&=0xbf;
TMOD&=0xbf;
TL1=0x00;
TH1=0x00;
TF1=0;
TR1=0;
}
bit key_flag,sonic_flag=0,shan_shuo=0;
void main()
{
unsigned int t,distance;
u8 shi,fen,miao,shi_1,fen_1,miao_1,shi_zhong=0;//分别是真的时分秒,和设置时的时分秒
u8 csb_set=30,csb_mo_si=0; //超声波初始警报值 以及是否打开超声波
u8 key_val = NO_KEY;
csb_set=Read_24C02(0x01);
P2 = 0X80; //题目要求初始化
P0 = 0X00;
P2=0XA0;
buzzer =1; //题目要求初始化
Delay1000ms();
P2 = 0X80;
P0=0XFF;
P2=0XA0;
buzzer =0;
P2 = 0X00;
Timer0Init();
Time1Init();
set_sfm(11,50,59);
while(1)
{
if(key_flag == 1)
{
key_flag = 0;
key_val = key_scan();
switch(key_val)
{
case 4:
if(mo_si==1) //时钟设置
{
if(shi_zhong==3)
{
if(shi_1==0)
shi_1=24;
shi_1--;
}
if(shi_zhong==2)
{
if(fen_1==0)
fen=60;
fen_1--;
}
if(shi_zhong==1)
{
if(miao_1==0)
miao_1=60;
miao_1--;
}
}
if(mo_si==0) //超声波设置
{
csb_set--;
Write_24C02(0x01,csb_set);
}
break;
case 5:
if(mo_si==1) //时钟设置
{
if(shi_zhong==3)
{
shi_1++;
if(shi_1>23)
shi_1=0;
}
if(shi_zhong==2)
{
fen_1++;
if(fen_1>59)
fen_1=0;
}
if(shi_zhong==1)
{
miao_1++;
if(miao_1>59 )
miao_1=0;
}
}
if(mo_si==0) //超声波设置
{
csb_set++;
Write_24C02(0x01,csb_set);
}
break;
case 6:
if(mo_si==1)
{
shi_zhong++;
if(shi_zhong>=4)
shi_zhong=0;
}
if(mo_si==0)
{
csb_mo_si++;
if(csb_mo_si>=2)
{
csb_mo_si=0;
}
}
break;
case 7: //时钟调整或超声波调整
mo_si++;
if(mo_si>=2)
mo_si=0;
break;
}
}
if(shi_zhong!=0&&mo_si==1) //显示
{
if(shi_zhong==1&&shan_shuo==1) //数码管闪烁
{
xian_shi[0]=10;
xian_shi[1]=10;
}
else
{
xian_shi[0]=shi_1/10;
xian_shi[1]=shi_1%10;
}
xian_shi[2]=11;
if(shi_zhong==2&&shan_shuo==1) //数码管闪烁
{
xian_shi[3]=10;
xian_shi[4]=10;
}
else
{
xian_shi[3]=fen_1/10;
xian_shi[4]=fen_1%10;
}
xian_shi[5]=11;
if(shi_zhong==3&&shan_shuo==1) //数码管闪烁
{
xian_shi[6]=10;
xian_shi[7]=10;
}
else
{
xian_shi[6]=miao_1/10;
xian_shi[7]=miao_1%10;
}
if(shi_zhong==3)
set_sfm(shi_1,fen_1,miao_1); //写入调整后时间
}
if(mo_si==1&&shi_zhong==0)
{
ET0=0;
shi=Ds1302_Single_Byte_Read(ds1302_hr_addr); //读ds1302数据
fen=Ds1302_Single_Byte_Read(ds1302_min_addr);
miao=Ds1302_Single_Byte_Read(ds1302_sec_addr);
ET0=1;
shi_1=shi/16*10+shi%16; //缓存当前时间,用于调整用
fen_1=fen/16*10+fen%16;
miao_1=miao/16*10+miao%16;
xian_shi[0]=shi/16; //显示时间
xian_shi[1]=shi%16;
xian_shi[2]=11;
xian_shi[3]=fen/16;
xian_shi[4]=fen%16;
xian_shi[5]=11;
xian_shi[6]=miao/16;
xian_shi[7]=miao%16;
}
if(mo_si==0&&csb_mo_si==0) //超声波模式工作
{
sonic_flag=0;
send_wave();
TR1=1;
while((RX==1)&&(TF1==0));
TR1=0;
if(TF1==1)
{
TF1=0;
distance=999;
}
else
{
t=TH1;
t<<=8;
t|=TL1;
distance=(unsigned int)(t*0.017);
}
TH1=0;
TL1=0;
xian_shi[0]=10;
xian_shi[1]=10;
xian_shi[2]=10;
xian_shi[3]=10;
xian_shi[4]=10;
xian_shi[5]=distance/100;
xian_shi[6]=distance%100/10;
xian_shi[7]=distance%10;
Delay2ms() ;
Delay2ms() ;
Delay2ms() ;
Delay2ms() ;
if(distance<csb_set*1.2) //超声波近距离警告
{
if(shan_shuo==1)
P2=0X80;P0=0X7F;P2=0X00; //led
if(shan_shuo==0)
P2=0X80;P0=0XfF;P2=0X00;
}
if(distance>csb_set*1.2) //超声波远距离无警告
{
P2=0X80;P0=0XfF;P2=0X00;
}
if(distance<=csb_set) //超声波近距离警告
{
P2=0XA0;buzzer=1;relay=0;P2=0X00; //继电器 蜂鸣器
}
if(distance>csb_set) //超声波远距离无警告
{
P2=0XA0;buzzer=0;relay=0;P2=0X00;
}
}
if(mo_si==0&&csb_mo_si==1) //超声波设置值显示
{
xian_shi[0]=10;
xian_shi[1]=10;
xian_shi[2]=10;
xian_shi[3]=10;
xian_shi[4]=10;
xian_shi[5]=csb_set/100;
xian_shi[6]=csb_set%100/10;
xian_shi[7]=csb_set%10;
}
}
}
void Timer0() interrupt 1 using 1
{
static unsigned int key_count = 0,sing_count = 0,i = 0,shan_count=0;
key_count++;
sing_count++;
if(key_count == 10) //中断进入键盘程序
{
key_count = 0;
key_flag = 1;
}
if(sing_count == 3)
{
sing_count = 0;
P2 = 0xc0; P0 = 0X00; P2=0X00;
P2 = 0xE0; P0 =~smg_duan[xian_shi[i]]; P2=0X00; //中断进入显示数码管
P2 = 0xc0; P0 = smg_wei[i]; P2=0X00;
i++;
if(i == 8)
i = 0;
}
shan_count++; //中断进入闪烁程序
if(shan_count>1000)
{
shan_count=0;
shan_shuo=~shan_shuo;
}
}
此处是iic的c文件
/*
程序说明: IIC总线驱动程序
软件环境: Keil uVision 4.10
硬件环境: CT107单片机综合实训平台(12MHz)
日 期: 2011-8-9
*/
#include “iic.h”
//总线启动条件
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
somenop;
SDA = 0;
somenop;
SCL = 0;
}
//总线停止条件
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
somenop;
SDA = 1;
}
//应答位控制
void IIC_Ack(unsigned char ackbit)
{
if(ackbit)
{
SDA = 0;
}
else
{
SDA = 1;
}
somenop;
SCL = 1;
somenop;
SCL = 0;
SDA = 1;
somenop;
}
//等待应答
bit IIC_WaitAck(void)
{
SDA = 1;
somenop;
SCL = 1;
somenop;
if(SDA)
{
SCL = 0;
IIC_Stop();
return 0;
}
else
{
SCL = 0;
return 1;
}
}
//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0;i<8;i++)
{
if(byt&0x80)
{
SDA = 1;
}
else
{
SDA = 0;
}
somenop;
SCL = 1;
byt <<= 1;
somenop;
SCL = 0;
}
}
//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++)
{
SCL = 1;
somenop;
da <<= 1;
if(SDA)
da |= 0x01;
SCL = 0;
somenop;
}
return da;
}
unsigned char Read_24C02(unsigned char addr)
{
unsigned char tmp;
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0xa1);
IIC_WaitAck();
tmp = IIC_RecByte();
IIC_Ack(0);
IIC_Stop();
return tmp;
}
void Write_24C02(unsigned char addr, unsigned char dat)
{
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
unsigned char read_adc(unsigned char add)
{
unsigned char temp;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
temp=IIC_RecByte();
IIC_WaitAck();
IIC_Stop();
return temp;
}
void write_adc(unsigned char add)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_Stop();
}
此处是iic的h文件
#ifndef _IIC_H
#define _IIC_H
#include<stc15f2k60s2.h>
#include “intrins.h”
#define somenop {nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();}
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
//总线引脚定义
sbit SDA = P2^1; /* 数据线 /
sbit SCL = P2^0; / 时钟线 */
//函数声明
void IIC_Start(void);
void IIC_Stop(void);
void IIC_Ack(unsigned char ackbit);
void IIC_SendByte(unsigned char byt);
unsigned char Read_24C02(unsigned char addr);
void Write_24C02(unsigned char addr, unsigned char dat);
unsigned char read_adc(unsigned char add);
void write_adc(unsigned char add);
bit IIC_WaitAck(void);
unsigned char IIC_RecByte(void);
#endif
此处是ds1302的c文件
#include “ds1302.h”
/单字节写入一字节数据/
void Write_Ds1302_Byte(unsigned char dat)
{
unsigned char i;
SCK = 0;
for (i=0;i<8;i++)
{
if (dat & 0x01) // 等价于if((addr & 0x01) 1)
{
SDA_SET; //#define SDA_SET SDA=1 /电平置高/
}
else
{
SDA_CLR; //#define SDA_CLR SDA=0 /电平置低/
}
SCK_SET;
SCK_CLR;
dat = dat >> 1;
}
}
/********************************************************************/
/单字节读出一字节数据/
unsigned char Read_Ds1302_Byte(void)
{
unsigned char i, dat=0;
for (i=0;i<8;i++)
{
dat = dat >> 1;
if (SDA_R) //等价于if(SDA_R1) #define SDA_R SDA /电平读取/
{
dat |= 0x80;
}
else
{
dat &= 0x7F;
}
SCK_SET;
SCK_CLR;
}
return dat;
}
/********************************************************************/
/向DS1302 单字节写入一字节数据/
void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat)
{
RST_CLR; /*RST脚置低,实现DS1302的初始化*/
SCK_CLR; /*SCK脚置低,实现DS1302的初始化*/
RST_SET; /*启动DS1302总线,RST=1电平置高 */
addr = addr & 0xFE;
Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是写操作,写之前将最低位置零*/
Write_Ds1302_Byte(dat); /*写入数据:dat*/
RST_CLR; /*停止DS1302总线*/
}
/********************************************************************/
/从DS1302单字节读出一字节数据/
unsigned char Ds1302_Single_Byte_Read(unsigned char addr)
{
unsigned char temp;
RST_CLR; /RST脚置低,实现DS1302的初始化/
SCK_CLR; /SCK脚置低,实现DS1302的初始化/
RST_SET; /*启动DS1302总线,RST=1电平置高 */
addr = addr | 0x01;
Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是读操作,写之前将最低位置高*/
temp=Read_Ds1302_Byte(); /*从DS1302中读出一个字节的数据*/
RST_CLR; /*停止DS1302总线*/
SDA_CLR; //xiu gai fei chang zhong yao
return temp;
}
void set_sfm(char shi,char fen,char miao)
{
Ds1302_Single_Byte_Write(0x8e,0); //关闭写保护
Ds1302_Single_Byte_Write(0x80,(miao/10)*16+miao%10); //以BCD码写入秒数据
Ds1302_Single_Byte_Write(0x82,(fen/10)*16+fen%10); //以BCD码写入分数据
Ds1302_Single_Byte_Write(0x84,(shi/10)*16+shi%10); //以BCD码写入时数据
Ds1302_Single_Byte_Write(0x8e,0x80); //打开写保护
}
此处是ds1302的h文件
#ifndef DS1302_H
#define DS1302_H
#include<stc15f2k60s2.h>
#include<intrins.h>
sbit SCK=P1^7;
sbit SD=P2^3;
sbit RST=P1^3;
//
/复位脚/
#define RST_CLR RST=0 /电平置低/
#define RST_SET RST=1 /电平置高/
/双向数据/
#define SDA_CLR SD=0 /电平置低/
#define SDA_SET SD=1 /电平置高/
#define SDA_R SD /电平读取/
/时钟信号/
#define SCK_CLR SCK=0 /时钟信号/
#define SCK_SET SCK=1 /电平置高/
//
#define ds1302_sec_addr 0x80 //秒数据地址
#define ds1302_min_addr 0x82 //分数据地址
#define ds1302_hr_addr 0x84 //时数据地址
#define ds1302_date_addr 0x86 //日数据地址
#define ds1302_month_addr 0x88 //月数据地址
#define ds1302_day_addr 0x8A //星期数据地址
#define ds1302_year_addr 0x8C //年数据地址
#define ds1302_control_addr 0x8Ee //写保护命令字单元地址
#define ds1302_charger_addr 0x90 //涓电流充电命令字地址
#define ds1302_clkburst_addr 0xBE //日历、时钟突发模式命令字地址
/********************************************************************/
//
/单字节写入一字节数据/
extern void Write_Ds1302_Byte(unsigned char dat);
//
/单字节读出一字节数据/
extern unsigned char Read_Ds1302_Byte(void);
//
//
/向DS1302单字节写入一字节数据/
extern void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat);
/********************************************************************/
/从DS1302单字节读出一字节数据/
extern unsigned char Ds1302_Single_Byte_Read(unsigned char addr);
extern void set_sfm(char shi,char fen,char miao);
#endif
//
// END FILE
//