撼山岳—第六届之温度记录器

声明:代码确实写的不好,用的都是最笨的方法实现功能,不喜勿喷

第六届省赛题,我是今天上午开始写的到现在刚刚写好,当然中间我也是有其他事情中断了写代码,总共花费时间六个小时左右,我已经在一步一步的逼近五个小时了,今天写这个题我还是有很多收获的。

我今天遇到了几个比较常见的问题在这里跟大家分享一下:

一、尽量不要在中断中让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

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值