蓝桥杯单片机设计与开发决赛-第七届-电压频率采集设备

这里的代码是主文件的代码,其他的头文件之前已经提供,下面的代码仅提供思路,不提供原理,如有错误请及时留言提醒。

#include <stc15f2k60s2.h>
#include <intrins.h>
#include "ds1302.h"
#include "iic.h"

typedef unsigned char uchar;
typedef unsigned int uint;

code uchar TAB[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0xff, 0xbf};//显示1-9 灭 -
uchar tab1, tab2, tab3, tab4, tab5, tab6, tab7, tab8;

uchar key, sec, min, hour, AD, dat;//常用的参数,秒,分,时,数据存放,AD读取

uint fre_time, frequ, H_tem, L_tem, H, L;//定义频率采集所需的变量
bit fre_state;

uint dat_t;
bit time_state, AD_state;//读取时间标志位,读取电压标志位

uchar function;
uchar T_set, V_set;//记录时间显示状态,电压显示状态
bit F_T;//记录频率周期显示状态

uchar hour_tem, min_tem, sec_tem;//时间调节临时存放
uchar V_h  = 20, V_l = 10;//电压上限=2.0V  电压下限=1.0V

bit inqu_state, thing_num;//记录查询显示状态,存放事件类型
uchar hour_in = 13, min_in = 50, sec_in = 12;//存放发生时间
bit times;//触发标志位
void delay(uint z)//延时函数
{
	uint x, y;
	for(x=z; x>0; x--)
		for(y=845; y>0; y--);
}

void timer_int()//定时器初始,一般是手写放在这里面
{
	EA = 1;
	TR0 = 1;//定时器0,16位,定时1ms,定时中断
	ET0 = 1;
	TMOD |= 0X01;
	TH0 = (65535-1000)/256;
	TL0 = (65535-1000)%256;

	TMOD |= 0X20;// 定时器1,8位自动装载,用来定时采样频率,5us
	TH1 = 255-5;
	TL1 = 255-5;
}

void display()//显示函数,配合定时器0中断使用,达到循环扫描
{
	static uchar i;//定义静态变量i
	switch(i)
	{
		case 0: P2=0XC0; P0=0X01; P2=0XE0; P0=TAB[tab1]; i=1; break;
		case 1: P2=0XC0; P0=0X02; P2=0XE0; P0=TAB[tab2]; i=2; break;
		case 2: P2=0XC0; P0=0X04; P2=0XE0; P0=TAB[tab3]; i=3; break;
		case 3: P2=0XC0; P0=0X08; P2=0XE0; P0=TAB[tab4]; i=4; break;

		case 4: P2=0XC0; P0=0X10; P2=0XE0; P0=TAB[tab5]; i=5; break;
		case 5: P2=0XC0; P0=0X20; P2=0XE0; P0=TAB[tab6]; i=6; break;
		case 6: P2=0XC0; P0=0X40; P2=0XE0; P0=TAB[tab7]; i=7; break;
		case 7: P2=0XC0; P0=0X80; P2=0XE0; P0=TAB[tab8]; i=0; break;
	}
}

void key_scan()//半矩阵键盘扫描,常用需要理解记住
{
	key = 0;
	P44=1; P42=1; P3=0X00;
	if((P44==0)|(P42==0))//判断竖行
	{
		delay(2);//消抖
		P44=1; P42=1; P3=0X00;
		if((P44==0)|(P42==0))
		{
			if(P44==0) key = 4;
			if(P42==0) key = 8;
		}
		P44=0; P42=0; P3=0X3F;
		if(P3!=0X3F)//判断横行
		{
			P44=0; P42=0; P3=0X3F;
			delay(2);//消抖
			if(P3!=0X3F)
			{
				if(P33==0) key += 0;
				if(P32==0) key += 1;
				if(P31==0) key += 2;
				if(P30==0) key += 3;
			}	
		}
		while(P3!=0X3F);//判断抬手
	}
}

void time_read()//时间读取函数,需要赋值几个变量,所以放在主函数写
{	
	EA = 0;//使用时间读取,需要关闭中断
	Write_Ds1302_Byte(0x8e,0x00);
	sec = Read_Ds1302_Byte(0x81);
	min = Read_Ds1302_Byte(0x83);
	hour = Read_Ds1302_Byte(0x85);
	Write_Ds1302_Byte(0x8e,0x80);
	EA = 1;//写完后,打开中断
}

void time_display()//时间显示函数,里面附加调整参数,里面附加切换按键
{
	if(key==4)//功能按键,切换显示功能
	{
		if(T_set==0) { T_set = 1; hour_tem = hour, min_tem = min, sec_tem = sec; }//临时赋值时间,好处,调整时间的时候,时间显示不会正常走时
		else if(T_set==1) T_set = 2;//1-3循环,依照题目的要求,只有按下S7的时候,保存数据
		else if(T_set==2) T_set = 3;
		else if(T_set==3) T_set = 1;
	}
	else if(key==10)//减按键
	{
		if(T_set==1) { if(hour_tem==0) hour_tem=1; hour_tem--; }//注意设置范围
		else if(T_set==2) { if(min_tem==0) min_tem=1; min_tem--; }
		else if(T_set==3) { if(sec_tem==0) sec_tem=1; sec_tem--; }
	}
	else if(key==11)//加按键
	{
		if(T_set==1) { hour_tem++; if(hour_tem==24) hour_tem=23;}//注意设置范围
		else if(T_set==2) { min_tem++; if(min_tem==60) min_tem=59;}
		else if(T_set==3) { sec_tem++; if(sec_tem==60) sec_tem=59;}
	}

	if(T_set==0)//正常时间显示
	{
		tab1=hour/10; tab2=hour%10; tab3=11; tab4=min/10; tab5=min%10; tab6=11; tab7=sec/10; tab8=sec%10;
	}
	else if(T_set==1)//时间调整
	{	//所调整的值闪烁
		if(sec%2==0) { tab1=hour_tem/10; tab2=hour_tem%10; tab3=11; tab4=min_tem/10; tab5=min_tem%10; tab6=11; tab7=sec_tem/10; tab8=sec_tem%10; }
		else { tab1=10; tab2=10; tab3=11; tab4=min_tem/10; tab5=min_tem%10; tab6=11; tab7=sec_tem/10; tab8=sec_tem%10; }
	}
	else if(T_set==2)//分钟调整	
	{
		if(sec%2==0) { tab1=hour_tem/10; tab2=hour_tem%10; tab3=11; tab4=min_tem/10; tab5=min_tem%10; tab6=11; tab7=sec_tem/10; tab8=sec_tem%10; }
		else { tab1=hour_tem/10; tab2=hour_tem%10; tab3=11; tab4=10; tab5=10; tab6=11; tab7=sec_tem/10; tab8=sec_tem%10; }
	}
	else if(T_set==3)//秒调整
	{
		if(sec%2==0) { tab1=hour_tem/10; tab2=hour_tem%10; tab3=11; tab4=min_tem/10; tab5=min_tem%10; tab6=11; tab7=sec_tem/10; tab8=sec_tem%10; }
		else { tab1=hour_tem/10; tab2=hour_tem%10; tab3=11; tab4=min_tem/10; tab5=min_tem%10; tab6=11; tab7=10; tab8=10; }
	}
}
void voltage_display()//电压显示函数,里面附加调整参数,里面附加切换按键
{
	if(key==4)//功能按键,切换显示功能
	{
		if(V_set==0) V_set = 1;
		else if(V_set==1) V_set = 2;
		else if(V_set==2) V_set = 1;
	}
	else if(key==10)//减按键
	{
		if(V_set==1) { if(V_h==0) V_h = 5; if(V_h>V_l) V_h-=5; }//注意设置范围,加减500mV
		else if(V_set==2) { if(V_l==0) V_l = 5; V_l-=5; }
	}
	else if(key==11)//加按键
	{
		if(V_set==1) { V_h+=5; if(V_h==55) V_h = 50; }
		else if(V_set==2) { if(V_h>V_l) V_l+=5; if(V_l==55) V_l = 50; }
	}

	if(V_set==0)//正常电压显示
	{
		tab1=11; tab2=1; tab3=11; tab4=10; tab5=AD/10; tab6=AD%10; tab7=0; tab8=0;
	}	
	else if(V_set==1)//调整上限电压
	{ 	//所调整的值闪烁
		if(sec%2==0) { tab1=V_h/10; tab2=V_h%10; tab3=0; tab4=0; tab5=V_l/10; tab6=V_l%10; tab7=0; tab8=0; }
		else { tab1=10; tab2=10; tab3=10; tab4=10; tab5=V_l/10; tab6=V_l%10; tab7=0; tab8=0; }
	}
	else if(V_set==2)//调整下限电压
	{
		if(sec%2==0) { tab1=V_h/10; tab2=V_h%10; tab3=0; tab4=0; tab5=V_l/10; tab6=V_l%10; tab7=0; tab8=0; }
		else { tab1=V_h/10; tab2=V_h%10; tab3=0; tab4=0; tab5=10; tab6=10; tab7=10; tab8=10; }	
	}	
} 
void frequ_display()//频率显示函数,里面附加切换按键
{
	if(key==4) F_T = ~F_T;//功能按键,切换显示功能
	if(F_T==0)//显示频率
	{
		tab1=11; tab2=2; tab3=11; tab4=frequ/10000; tab5=frequ%10000/1000; tab6=frequ%1000/100; tab7=frequ%100/10; tab8=frequ%10;	
	}
	else //显示周期
	{
		tab1=11; tab2=2; tab3=11; tab4=fre_time/10000; tab5=fre_time%10000/1000; tab6=fre_time%1000/100; tab7=fre_time%100/10; tab8=fre_time%10;
	}
		
}

void inquiry()//查询显示函数,里面附加切换按键
{
	if(key==4) inqu_state = ~inqu_state;
	if(inqu_state==0)//显示事件类型
	{
		tab1=10; tab2=10; tab3=10; tab4=10; tab5=10; tab6=10; tab7=0; tab8=thing_num;		
	}	
	else//显示发生时间
	{
		tab1=hour_in/10; tab2=hour_in%10; tab3=11; tab4=min_in/10; tab5=min_in%10; tab6=11; tab7=sec_in/10; tab8=sec_in%10;	
	}
}

void dat_read()//从EEPROM获取题目所需的变量
{
	if(EEPROM_read(0x01)!=3)//初始化参数,第一遍烧录程序只执行一次,比较好的模板,可记住
	{
		delay(3); 
		EEPROM_write(0x01,3); delay(3);
		EEPROM_write(0x11,20); delay(3);
		EEPROM_write(0x12,10);
	}
	delay(3);
	V_h = EEPROM_read(0x11); delay(3);//连续读取或写入,必须加小延迟
	V_l = EEPROM_read(0x12); delay(3);
	thing_num = EEPROM_read(0x20); delay(3);
	hour_in = EEPROM_read(0x21); delay(3);
	min_in = EEPROM_read(0x22); delay(3);
	sec_in = EEPROM_read(0x23); delay(3);	
}

void dat_gain()//定时数据获取函数
{
	if(AD_state==1) //一般可在获取数据后判断状态,保证数据正确
	{
		AD_state = 0; AD = AD_read(0x03)/5.1; //读取电压*10
		if((V_h<AD)&(times==0)) //判断超过上限
		{ 
			times = 1;
			thing_num = 1;
			hour_in = hour; min_in = min; sec_in = sec;
			EEPROM_write(0x20,thing_num); delay(5); //向EEPROM写入事件类型,发生时间
			EEPROM_write(0x21,hour_in); delay(5);
			EEPROM_write(0x22,min_in); delay(5);
			EEPROM_write(0x23,sec_in); 
		}
		else if((AD<V_l)&(times==0))//判断低于下限
		{
			times = 1;
			thing_num = 0;
			hour_in = hour; min_in = min; sec_in = sec;
			EEPROM_write(0x20,thing_num); delay(5); //向EEPROM写入事件类型,发生时间
			EEPROM_write(0x21,hour_in); delay(5);
			EEPROM_write(0x22,min_in); delay(5);
			EEPROM_write(0x23,sec_in); 	
		}
		else if((AD>=V_l)&(AD<=V_h)) times = 0;//判断电压是否回到正常值,times只有置零,才能开始下次判断
	}
	else if(time_state==1) { time_state = 0; time_read();}	
}

void key_function()//按键功能
{
	if((key==7)&(V_set==0))//时钟按键,进入相关显示函数
	{
		function = 0;
		if(T_set!=0)//判断是否处于设置界面
		{
			T_set = 0;
			EA = 0;
			Write_Ds1302_Byte(0x8e,0x00);//重新写入所设置的时间
			Write_Ds1302_Byte(0x80,sec_tem);
			Write_Ds1302_Byte(0x82,min_tem);
			Write_Ds1302_Byte(0x84,hour_tem);
			Write_Ds1302_Byte(0x8e,0x80);
			EA = 1;
		}
	}
	else if((key==6)&(T_set==0))//电压测量按键,进入相关显示函数
	{
		function = 1;
		if(V_set!=0)//判断是否处于设置界面
		{
			V_set = 0;
			EEPROM_write(0x11,V_h);//向EEPROM写入所设置的时间
			delay(3);
			EEPROM_write(0x12,V_l);
		}
	}
	else if((key==5)&(V_set==0)&(T_set==0))//频率测量按键,进入相关显示函数
	{	
		function = 2;
		if(F_T!=0) F_T = 0;//返回初始界面
	}
	else if(key==9)//查询按键,进入相关显示函数
	{
		function = 3;
		if(inqu_state!=0) inqu_state = 0;	//返回初始界面
	}
	//function   0为时间显示界面 1为电压测量界面 2为电压阈值设置界面  3为查询界面
	if(function==0)  time_display();
	else if(function==1) voltage_display();
	else if(function==2) frequ_display();
	else if(function==3) inquiry();
}	


void main()
{
	P2=0XA0; P0=0X00; P2=0X80; P0=0XFF;//初始化,熄灭灯,关闭蜂鸣器和继电器

	Write_Ds1302_Byte(0x8e,0x00);//写入时间 23-59-55
	Write_Ds1302_Byte(0x80,55);
	Write_Ds1302_Byte(0x82,59);
	Write_Ds1302_Byte(0x84,23);
	Write_Ds1302_Byte(0x8e,0x80);

	dat_read();//初始化读取
		
	timer_int();//定时器初始化
	while(1)
	{
		key_scan();//按键扫描

		dat_gain();//定时获取时间
		
		key_function();//按键功能
	}
}

void display_timer0()interrupt 1
{
	TH0 = (65535-1000)/256;//定时器1装载
	TL0 = (65535-1000)%256;
	display();//数码管扫描显示 	

	dat_t++;//定时数据获取的时刻,定义时,记得超过256,需要定义为 unsigned int
	if(dat_t==50) AD_state = 1;
	else if(dat_t==150) time_state = 1;
	else if(dat_t==250) //打开定时器1中断,开始计数
	{	TR1 = 1; ET1 = 1; }
	else if(dat_t==280)
	{
		TR1 = 0; ET1 = 0;//关闭定时器1中断,计数完毕
		fre_time = (H_tem + L_tem)*5;//计算周期
		frequ = 1000000/fre_time;//计算频率
	}
	else if(dat_t==400) dat_t = 0;//时间最后记得清零
}

void frequ_time1()interrupt 3//定时器1中断,因为存在2个中断,所以有一个中断必须限制中断时长,在定时器0中断中设置30ms的使用时间
{
	if(P34==1)//判断高电平
	{
		H++;//记录高电平周期数
		if(fre_state==1)//保存一次低电平的周期数
		{
			fre_state = 0;
			L_tem = L;//赋值
			L = 0;//清零,为下次读取做准备
		}
	}
	else if(P34==0)//判断低电平
	{
		L++;//记录低电平周期数
		if(fre_state==0)//保存一次高电平的周期数
		{
			fre_state = 1;
			H_tem = H;//赋值
			H = 0;//清零,为下次读取做准备
		}
	}	
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
蓝桥杯单片机设计开发实训指导PDF》是一份提供蓝桥杯单片机设计开发实训指导的电子书。该指导书的目的是帮助参加蓝桥杯的学生在单片机设计开发方面获得必要的知识和技能。 该指导书主要分为以下几个方面:理论基础、实训项目、实训操作指导和实验报告要求等。 在理论基础篇中,指导书介绍了单片机的基本概念和原理,包括常见的单片机类型、单片机的工作原理和基本应用等。学生可以通过阅读这些内容了解单片机的工作原理和基本功能。 在实训项目篇中,指导书给出了一些常见的实训项目,如LED灯控制、温度检测、蜂鸣器控制等。学生可以按照指导书中的项目要求进行实训,并运用所学的知识进行设计开发。 在实训操作指导篇中,指导书详细介绍了每个实训项目的具体操作步骤和注意事项。学生可以通过按照指导书的步骤进行实操,熟悉单片机的操作方法和常用编程语言。 最后,在实验报告要求篇中,指导书给出了实验报告的撰写要求和模板。学生需要按照指导书的要求进行实验报告的撰写,并对实验过程和结果进行详细的描述和分析。 总而言之,《蓝桥杯单片机设计开发实训指导PDF》是一份提供蓝桥杯单片机设计开发实训指导的电子书,通过阅读指导书的内容,学生可以掌握单片机的基本知识和技能,并通过实训项目的操作和实验报告的撰写来提高自己的实践能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值