蓝桥杯14届临近,俺也在准备蓝桥杯单片机组比赛,在此贴出13届的训练题
首先是头文件和各种全局定义,以及main函数
#include <REG52.H>
#include <intrins.h>
typedef unsigned char u8;
typedef unsigned int u16;
sbit SCK=P1^7;
sbit SDA=P2^3;
sbit RST = P1^3; // DS1302复位
sbit DQ = P1^4; //单总线接口
// 0 1 2 3 4 5 6 7 8 9 U -
const smg_code[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,~0x3e,~0x40};//0b00111110
void h138(u8 x);
void sys_init(void);
void smg_dis_page(void);
u8 key_scan(void);
void key_set(void);
void time_read(u8 time[]);
void time_init(u8 time[]);
float get_tmp(void);
u8 g_page=0; //页面显示标志
u8 g_mode=0; //显示模式标志
u16 g_tmp=235; //需要显示的温度
u8 g_set_tmp=23; //设置温度
u8 time[3] = {30,21,12}; //显示的时间
u8 init_time[3] = {24,33,17}; //写入的初始时间
u8 g_key_flag=0; //按键标志,没有松开为1
u8 g_time_mode=0; //时间界面模式标志
void main()
{
sys_init(); //系统初始化
time_init(init_time); //时间初始化
while(1)
{
key_set(); //按键改变各种标志
smg_dis_page(); //根据标志显示
time_read(time); //获取时间
g_tmp = get_tmp()*10; //获取温度
}
}
74h138驱动和数码管显示函数
void delay(u16 x)
{
while(x--);
}
void h138(u8 x)
{
switch(x)
{
case 1: {P2 = P2&0X1F|0XA0;break;} //RELAY
case 2: {P2 = P2&0X1F|0X80;break;} //LED
case 3: {P2 = P2&0X1F|0XE0;break;} //SMG_D
case 4: {P2 = P2&0X1F|0XC0;break;} //SMG_W
}
}
//显示一位数码管
void smg_dis_one(u8 x,u8 dat)
{
h138(4);
P0=0X01<<x;
delay(10);
h138(3);
P0=dat;
delay(100);
P0=0XFF;
}
//显示8位数码管
void smg_dis_all(u8 d0,u8 d1,u8 d2,u8 d3,u8 d4,u8 d5,u8 d6,u8 d7)
{
smg_dis_one(0,d0);
smg_dis_one(1,d1);
smg_dis_one(2,d2);
smg_dis_one(3,d3);
smg_dis_one(4,d4);
smg_dis_one(5,d5);
smg_dis_one(6,d6);
smg_dis_one(7,d7);
}
页面显示和系统初始化函数
void smg_dis_page()
{
if(g_page==0)//页面1,温度
{
smg_dis_all(smg_code[10],smg_code[1],0xff,0xff,0xff,smg_code[g_tmp/100],smg_code[g_tmp%100/10]&0x7f,smg_code[g_tmp%10]);
}
if(g_page==1)//页面二,时间,两种显示
{
if(g_time_mode==0)
smg_dis_all(smg_code[10],smg_code[2],0xff,smg_code[time[2]/10],smg_code[time[2]%10],~0x40,smg_code[time[1]/10],smg_code[time[1]%10]);
else
smg_dis_all(smg_code[10],smg_code[2],0xff,smg_code[time[1]/10],smg_code[time[1]%10],~0x40,smg_code[time[0]/10],smg_code[time[0]%10]);
}
if(g_page==2) //页面三,温度设置
{
smg_dis_all(smg_code[10],smg_code[3],0xff,0xff,0xff,0xff,smg_code[g_set_tmp/10],smg_code[g_set_tmp%10]);
}
}
void sys_init()
{
h138(1);
P0=0X00;
h138(2);
P0=0XFF;
}
按键扫描函数和按键改变显示函数
u8 key_scan(void)
{
u8 key=0;
u8 H,L;
P42=1;P44=1;P3=0XF0;
if(P42!=1||P44!=1||P3!=0XF0&&g_key_flag==0) //按键不松开不扫描
{
if(P44==0) L=1;
if(P42==0) L=2;
if(P35==0) L=3;
if(P34==0) L=4;
}
P42=0;P44=0;P3=0X0F;
if(P3!=0X0F&&g_key_flag==0) //按键不松开不扫描
{
g_key_flag=1;
if(P33==0) H=1;
if(P32==0) H=2;
if(P31==0) H=3;
if(P30==0) H=4;
}
key = L*4+H-1;
while(P3!=0X0F)
{
return key;
}
g_key_flag=0; //松开标志位置0
return 0;
}
void key_set() //按键改变显示
{
u8 key=0;
key = key_scan();
if(key==12) //按键12切换页面
{
g_page+=1;
if(g_page==3) g_page=0;
}
if(key==13) g_mode=!g_mode; //按键13改变模式
if(g_page==2)
{
if(key==16) {g_set_tmp+=1;} //页面2下,按键16,17有效
if(key==17) {g_set_tmp-=1;}
}
if(g_page==1) //页面1下,长按17切换显示
{
if(key==17&&g_key_flag==1) g_time_mode=1;
if(g_key_flag==0) g_time_mode=0;
}
}
ds1302读取与写入函数
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_();_nop_();_nop_();
SCK=0; _nop_();_nop_();_nop_();
RST=1; _nop_();_nop_();_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_();_nop_();_nop_();
SCK=0; _nop_();_nop_();_nop_();
RST=1; _nop_();_nop_();_nop_();
Write_Ds1302(address);
for (i=0;i<8;i++)
{
SCK=0;
temp>>=1;
if(SDA)
temp|=0x80;
SCK=1;
}
RST=0; _nop_();_nop_();_nop_();
SCK=0; _nop_();_nop_();_nop_();
SCK=1; _nop_();_nop_();_nop_();
SDA=0; _nop_();_nop_();_nop_();
SDA=1; _nop_();_nop_();_nop_();
return (temp);
}
void time_init(u8 time[])
{
u8 i=0;
Write_Ds1302_Byte(0x8e,0x00);
for(i=0;i<3;i++)
{
time[i]=time[i]/10*16+time[i]%10;
Write_Ds1302_Byte(0x80+2*i,time[i]);
}
Write_Ds1302_Byte(0x8e,0x80);
}
void time_read(u8 time[])
{
u8 i=0;
for(i=0;i<3;i++)
{
time[i]=Read_Ds1302_Byte(0x81+2*i);
time[i]=time[i]/16*10+time[i]%16;
}
}
ds18b20获取温度函数
//单总线延时函数
void Delay_OneWire(unsigned int t) //STC89C52RC
{
unsigned j=0;
while(t--){
for(j=5;j>0;j--);
}
}
//通过单总线向DS18B20写一个字节
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(5);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(5);
}
//从DS18B20读取一个字节
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
DQ = 0;
dat >>= 1;
DQ = 1;
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(5);
}
return dat;
}
//DS18B20设备初始化
bit init_ds18b20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(12);
DQ = 0;
Delay_OneWire(80);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
float get_tmp(void)
{
u16 temp;
u8 LSB,MSB;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
LSB = Read_DS18B20();
MSB = Read_DS18B20();
temp|=MSB;
temp<<=8;
temp|=LSB;
return temp*0.0625;
}
还有一些功能就不写了,这里建议按键和数码管显示放在定时器里面,以获得最好的显示效果,我就是这样做的,定时器1ms中断一次,显示效果非常好。