声明:代码确实写的不好,用的都是最笨的方法实现功能,不喜勿喷
第六届省赛题,我是今天上午开始写的到现在刚刚写好,当然中间我也是有其他事情中断了写代码,总共花费时间六个小时左右,我已经在一步一步的逼近五个小时了,今天写这个题我还是有很多收获的。
我今天遇到了几个比较常见的问题在这里跟大家分享一下:
一、尽量不要在中断中让LED灯闪烁,我今天在中断中让LED的一个灯闪烁,我发现很容易出现LED闪烁的错乱现象。如果想让LED闪烁我们可以借助DS1302来定时闪烁,也可以用定时器的标志位来实现。
二、尽量不要在中断中进行数码管的刷新 ,在中断中进行判断刷新,很有可能你的程序会死在判断中,一直在里面,没有办法将其强制中断出来,我们可以用定时器的标志位,在主函数中实现数码管的刷新。
三、针对这个题来说,里面需要你实现以1秒、5秒、30秒、60秒为间隔存储10个DS18B20读取的温度,这个时候我们最好是借助定时器中断来连续的读取十个温度值,不要在主函数中用DS13023实现以上间隔读取温度的数据,因为如果你的语句是
if(shijian[0]%5 == 0)
wendu = DS18B20读取的温度
shiajin[0]是我们存储的时钟的秒数
这样的话,很有可能你在时间是5的整数倍的时候,一秒就读取了十个数,因为主函数执行一遍可能用的时间是非常少的。
下面还是看一下题(题目不一定完全对):
这个题目还是相对比较简单的,我之所以写了那么长时间是因为上面说的三个问题,都被我遇到了,我也是自己比较笨,基础也是比较薄弱,换做你们估计是不是遇到这种简单的问题。遇到了我也很开心,因为自己又进一步的了解了自己在什么层次,同时也提升了自身的知识。虽然耗费了时间但总体来说还是值得的。
我还是说一下自己的思路,当然还是仅供参考:
第一步:实现上电初始化的数码管的显示
第二步:实现S4按键转换采集时间间隔的功能
第三步:实现S5按键确认采集的功能
第四步:完成时间的采集,并实现S6按键的显示功能
最后一步:实现S7的重新设置的功能
其实我的思路都是废话,因为题目就是这个顺序要求的,没错我个人是觉得按照题目要求的一步一步的来做思路比较好,不会说写着写着自己不知道自己要干什么了。
下面看一下程序:
第一:按键程序
#include "key.h"
uchar KEY7_flag;
uchar KEY6_flag;
uchar KEY5_flag;
uchar KEY4_flag;
uchar Ensure_flag;
//独立按键扫描函数
void D_Keyscan(void)
{
if(P30==0) //P30是按键S7
{
Delay5ms();
if(P30==0)
{
KEY7_flag = 1;//回到初始化的标志位
}
while(!P30);
}
else if(P31==0) //P31是按键S6
{
Delay5ms();
if(P31==0)
{
KEY6_flag = 1;//显示存储温度的标志位
}
while(!P31);
}
else if(P32==0) //P32是按键S5
{
Delay5ms();
if(P32==0)
{
KEY5_flag = 1;//确认采集时间间隔的标志位
}
while(!P32);
}
else if(P33==0) //P33是按键S4
{
Delay5ms();
if(P33==0)
{
KEY4_flag += 1;//切换采集时间间隔的标志位
Ensure_flag = 1;//与按键S5的标志位一同确保可以实现确认功能
if(KEY4_flag == 4)//实现采集时间的循环设置
KEY4_flag = 0;
}
while(!P33);
}
}
void Delay5ms() //@11.0592MHz
{
unsigned char i, j;
i = 54;
j = 199;
do
{
while (--j);
} while (--i);
}
第二:数码管程序
#include "shuma.h"
u8 shu_tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XC6,0XFF};//0XC6是英文C
uchar yi,er,san,si,wu,liu,qi,ba;
//第一和第二个数码管
void Display1_2(uchar yi,uchar er)
{
P2=0XC0;//打开位选573 U8
P0=0X01;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[yi];
Delay1ms();Delay1ms();
P2=0XC0;//打开位选573 U8
P0=0X02;//选择第二个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[er];
Delay1ms();Delay1ms();
}
//第四和第五个数码管
void Display4_5(uchar si,uchar wu)
{
P2=0XC0;//打开位选573 U8
P0=0X08;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[si];
Delay1ms();Delay1ms();
P2=0XC0;//打开位选573 U8
P0=0X10;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[wu];
Delay1ms();Delay1ms();
}
//第三和第六个数码管
void Display3_6(uchar san,uchar liu)
{
P2=0XC0;//打开位选573 U8
P0=0X04;//选择第三个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[san];
Delay1ms();Delay1ms();
P2=0XC0;//打开位选573 U8
P0=0X20;//选择第四个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[liu];
Delay1ms();Delay1ms();
}
//第七和第八个数码管
void Display7_8(uchar qi,uchar ba)
{
P2=0XC0;//打开位选573 U8
P0=0X40;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[qi];
Delay1ms();Delay1ms();
P2=0XC0;//打开位选573 U8
P0=0X80;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[ba];
Delay1ms();Delay1ms();
}
void Delay1ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
第三:DS18B20程序
#include "ds18b20.h"
//DS18B20初始化 (温度芯片)
void DS18Init()
{
DQ=0;
Delay500us();
DQ=1;
Delay500us();
}
//温度处理函数
uchar Date_Handing()
{
uchar high,low;
uchar temp;
DS18Init();
write(0xcc);
write(0x44);
//Delay500us();//Delay500us();
DS18Init();
write(0xcc);
write(0xbe);
low=read();
high=read();
temp=high<<4;
temp|=(low>>4);
return temp;
}
//向DS写控制字
void write(uchar dat)
{
uchar i;
for(i=0;i<8;i++)
{
DQ=0;
DQ=dat&0x01;
Delay100us();
DQ=1;
dat>>=1;
}
}
//读取温度存储器的数据
uchar read()
{
uchar i,dat;
for(i=0;i<8;i++)
{
DQ=0;
_nop_();
dat>>=1;
DQ=1;
if(DQ==1)
{
dat|=0x80;
}
Delay100us();
}
return dat;
}
void Delay500us() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
i = 6;
j = 93;
do
{
while (--j);
} while (--i);
}
void Delay100us() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
i = 2;
j = 15;
do
{
while (--j);
} while (--i);
}
第四:DS1302程序
#include "ds1302.h"
uchar shijian[7];
uchar code ds[]={50,59,23,10,10,1,16};
//DS1302初始化
void DS13Init()
{
uchar i;
uchar add=0x80;
write_DS(0x8e,0x00);
for(i=0;i<7;i++)
{
write_DS(add,ds[i]);
add=add+2;
}
write_DS(0x8e,0x80);
}
//向DS1302写地址和数据
void write_DS(uchar add,uchar dat)
{
uchar num;
CE=0;
SCLK=0;
CE=1;
writebyte(add);
num=(dat/10<<4)|(dat%10);
writebyte(num);
CE=0;
}
//将数据存储到指定数组中
void Read_Time()
{
uchar i;
uchar add=0x81;
write_DS(0x8e,0x00);
for(i=0;i<7;i++)
{
shijian[i]=read(add);
add=add+2;
}
write_DS(0x8e,0x80);
}
//读取DS1302指定地址中的数据
uchar read(uchar add)
{
uchar i,temp;
uchar dat_low,dat_high;
CE=0;
SCLK=0;
CE=1;
writebyte(add);
for(i=0;i<8;i++)
{
SCLK=0;
temp>>=1;
if(IO)
{
temp|=0x80;
}
SCLK=1;
}
IO=0;//数据位要从零开始
dat_high=temp/16;
dat_low=temp%16;
temp=dat_high*10+dat_low;
return temp;
}
//向DS1302写数据
void writebyte(uchar dat)
{
uchar i;
for(i=0;i<8;i++)
{
SCLK=0;
IO=dat&0x01;
SCLK=1;
dat>>=1;
}
}
第五:初始化程序(.c)
#include "system.h"
void Init(void)
{
P2=0XA0;//打开蜂鸣器,继电器控制端
P0=0X00;//关闭蜂鸣器,继电器
P2=0X80;//打开LED灯控制端
P0=0XFF;//关闭LED灯
P2=0XC0;//打开数码管片选控制端
P0=0XFF;//选择所有数码管
P2=0XFF;//打开数码管段选控制端
P0=0XFF;//关闭所有数码管段选
}
初始化(.h)
#ifndef __SYSTEM_H
#define __SYSTEM_H
#include "STC15F2K60S2.H"
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
typedef unsigned int u16;
typedef unsigned char u8;
void Init(void);
#endif
最后:主函数程序
#include "system.h"
#include "ds18b20.h"
#include "ds1302.h"
#include "key.h"
#include "shuma.h"
void Timer0Init(void);
extern uchar yi,er,san,si,wu,liu,qi,ba;
extern uchar KEY7_flag;
extern uchar KEY6_flag;
extern uchar KEY5_flag;
extern uchar KEY4_flag;
extern uchar Ensure_flag;
extern uchar shijian[7];
uchar num; //控制数码管显示十个温度
uchar num_flag; //检测存储温度数据为十个的标志位
uchar wendu[10]; //十个温度数据的存储数组
uchar Timer_flag; //设置采集时间的变量
uchar Init_flag; //确保上电之后的初始化接界面能显示
uchar Makesure_flag;//在采集时间间隔设置好之后,时钟开始计时
uchar display_flag; //数码管显示的控制位
uchar timermove_flag;//数码管显示时间的控制位
void main(void)
{
Init();
DS18Init();
DS13Init();
Timer0Init();//定时器的初始化
while(1)
{
D_Keyscan();//按键扫描
Read_Time();//调用DS1302读取时间
if((KEY4_flag == 0) && (Init_flag == 0))//在刚上电之后显示的初始化界面
{
yi = 12;er = 12;san = 12; si = 12;
wu = 12;liu = 10; qi = 0; ba = 1;
KEY6_flag = 0;
if(KEY5_flag == 1)
{
Timer_flag = 1;//设置采集时间的变量
Init_flag = 1;//确保在S5按键按下之后退出采集时间间隔的设置
Makesure_flag = 1;//在采集时间间隔设置好之后,时钟开始计时
KEY5_flag = 0; //确保第二次按下S5才能确认时间采集间隔
}
Display1_2(yi,er);
Display4_5(si,wu);
Display3_6(san,liu);
Display7_8(qi,ba);
}
else if((KEY4_flag == 0) && (Ensure_flag == 1))//S4按键第四次或者0次按下之后回到采集时间间隔为1秒的设置
{
yi = 12;er = 12;san = 12; si = 12;
wu = 12;liu = 10; qi = 0; ba = 1;
if(KEY5_flag == 1)
{
Timer_flag = 1;//设置采集时间的变量
Makesure_flag = 1;//在采集时间间隔设置好之后,时钟开始计时
Ensure_flag = 0;//确保在S5按键按下之后退出采集时间间隔的设置
KEY5_flag = 0;//确保第二次按下S5才能确认时间采集间隔
}
Display1_2(yi,er);
Display4_5(si,wu);
Display3_6(san,liu);
Display7_8(qi,ba);
}
else if((KEY4_flag == 1) && (Ensure_flag == 1))//S4按键第一次按下之后回到采集时间间隔为5秒的设置
{
yi = 12;er = 12;san = 12; si = 12;
wu = 12;liu = 10; qi = 0; ba = 5;
if(KEY5_flag == 1)
{
Timer_flag = 5;//设置采集时间的变量
Makesure_flag = 1;//在采集时间间隔设置好之后,时钟开始计时
Ensure_flag = 0;//确保在S5按键按下之后退出采集时间间隔的设置
KEY5_flag = 0;//确保第二次按下S5才能确认时间采集间隔
}
Display1_2(yi,er);
Display4_5(si,wu);
Display3_6(san,liu);
Display7_8(qi,ba);
}
else if((KEY4_flag == 2) && (Ensure_flag == 1))//S4按键第二次按下之后回到采集时间间隔为30秒的设置
{
yi = 12;er = 12;san = 12; si = 12;
wu = 12;liu = 10; qi = 3; ba = 0;
if(KEY5_flag == 1)
{
Timer_flag = 30;//设置采集时间的变量
Makesure_flag = 1;//在采集时间间隔设置好之后,时钟开始计时
Ensure_flag = 0;//确保在S5按键按下之后退出采集时间间隔的设置
KEY5_flag = 0;//确保第二次按下S5才能确认时间采集间隔
}
Display1_2(yi,er);
Display4_5(si,wu);
Display3_6(san,liu);
Display7_8(qi,ba);
}
else if((KEY4_flag == 3) && (Ensure_flag == 1))//S4按键第三次按下之后回到采集时间间隔为60秒的设置
{
yi = 12;er = 12;san = 12; si = 12;
wu = 12;liu = 10; qi = 6; ba = 0;
if(KEY5_flag == 1)
{
Timer_flag = 60;//设置采集时间的变量
Makesure_flag = 1;//在采集时间间隔设置好之后,时钟开始计时
Ensure_flag = 0;//确保在S5按键按下之后退出采集时间间隔的设置
KEY5_flag = 0;//确保第二次按下S5才能确认时间采集间隔
}
Display1_2(yi,er);
Display4_5(si,wu);
Display3_6(san,liu);
Display7_8(qi,ba);
}
else
{
if(Makesure_flag == 1)//在采集时间间隔设置好之后,时钟开始计时
{
Read_Time();
yi = shijian[2]/10;er = shijian[2]%10;san = 10; si = shijian[1]/10;
wu = shijian[1]%10;liu = 10; qi = shijian[0]/10; ba = shijian[0]%10;
if(ba%2 == 0)//实现第三个数码管和第六个数码管闪烁
{
P2 = 0XC0;P0 = 0X24;
P2 = 0XFF;P0 = 0XFF;
}
else
{
Display3_6(san,liu);
}
Display1_2(yi,er);
Display4_5(si,wu);
Display7_8(qi,ba);
if(num_flag == 10)//判断温度数据是否已经采集够10个
{
if(ba%2 == 0)//采集完成提示LED灯闪烁
{
P2=0X80;//打开LED灯控制端
P0=0XFE;
}
else
{
P2=0X80;//打开LED灯控制端
P0=0XFF;
}
Timer_flag = 0;//将采集时间存储变量赋值为0,停止定时器中断中的时间采集
display_flag = 1;//数码管显示的控制位
KEY7_flag = 0;//防止在之前已经误按S7,在这里将其清空,不影响温度的显示
}
}
if(display_flag == 1)//数码管显示的控制位
{
if(KEY6_flag == 1)//如果S6按键按下就显示采集的温度
{
Makesure_flag = 0;//将时钟计时的数码管显示关闭,开始显示温度
P2=0X80;//打开LED灯控制端
P0=0XFF;//关闭LED灯
yi = 10;er = 0;san = 0; si =12;
wu = 12;liu = 10;
qi = wendu[num]/10;
ba = wendu[num]%10;
if(timermove_flag == 1)//定时显示每一个温度值
{
num++; //实现十个数据的循环显示
timermove_flag = 0;
if(num == 10) //只显示采集的十个数据
{
num = 0;
}
}
Display1_2(yi,er);
Display4_5(si,wu);
Display3_6(san,liu);
Display7_8(qi,ba);
if(KEY7_flag == 1) //判断按键S7是否按下
{
KEY6_flag = 0;//如果按键S7按下,清空S6标志位,清空S7标志位,清空S4标志位
display_flag = 0;//清除显示控制位
num_flag = 0;//清空采集数量记录位
Ensure_flag = 1;//与S4的标志位一起实现回到初始化的界面
KEY7_flag = 0;
KEY4_flag = 0;
}
}
}
}
}
}
void Timer0Init(void) //2毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x9A; //设置定时初值
TH0 = 0xA9; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
EA = 1;
}
void Time0(void) interrupt 1
{
u16 num1;
u16 num2;
TL0 = 0x9A; //设置定时初值
TH0 = 0xA9; //设置定时初值
num2++;
if(num2 == 200)//定时显示温度值
{
num2 = 0;
timermove_flag = 1;
}
if(Timer_flag == 1)//实现采集时间间隔是1秒
{
num1++;
if(num1 == 500)
{
num1 = 0;
wendu[num_flag] = Date_Handing();//读取温度值
num_flag = num_flag + 1;
}
}
else if(Timer_flag == 5)//实现采集时间间隔是5秒
{
num1++;
if(num1 == 2500)
{
num1 = 0;
wendu[num_flag] = Date_Handing();//读取温度值
num_flag = num_flag + 1;
}
}
else if(Timer_flag == 30)//实现采集时间间隔是30秒
{
num1++;
if(num1 == 15000)
{
num1 = 0;
wendu[num_flag] = Date_Handing();//读取温度值
num_flag = num_flag + 1;
}
}
else if(Timer_flag == 60)//实现采集时间间隔是60秒
{
num1++;
if(num1 == 30000)
{
num1 = 0;
wendu[num_flag] = Date_Handing();//读取温度值
num_flag = num_flag + 1;
}
}
}
上面的程序我都是用的模块,都是我之前自己封装好的函数模块,用起来比较方便,但是很能导致自己会忘记很多模块是怎么写的,其中利弊都有,看自己选择吧。
最后我还是把我的工程上传一下https://download.csdn.net/my