蓝桥杯单片机第七届国赛——电压频率采集设备

目录

题目

个人见解

程序

        iic.c
        iic.h
       ds1302.c
       ds1302.h
        main.c

题目

个人见解

没记错的话,这一届是第一次要求使用NE555测量频率,所有对于没有接触过的同学来说,是有难度的(我第一次碰到也不会测)。其他要求都比较基础,但也有挑战性,其中采集的上升沿和下降沿我采取的是标志位法,大家还有好的方法可以分享以下哈,接下来一起看看吧(本人写的代码都很基础简单易懂)。

程序

首先肯定是先添加底层驱动文件,本来运用了ds1302时钟芯片和iic总线。

iic.c
#include <stc15f2k60s2.h>
#include <iic.h>
#include <intrins.h>

sbit sda=P2^1;
sbit scl=P2^0;

#define DELAY_TIME	5

//
static void I2C_Delay(unsigned char n)
{
    do
    {
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();		
    }
    while(n--);      	
}

//
void I2CStart(void)
{
    sda = 1;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 0;
	I2C_Delay(DELAY_TIME);
    scl = 0;    
}

//
void I2CStop(void)
{
    sda = 0;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 1;
	I2C_Delay(DELAY_TIME);
}

//
void I2CSendByte(unsigned char byt)
{
    unsigned char i;
	
    for(i=0; i<8; i++){
        scl = 0;
		I2C_Delay(DELAY_TIME);
        if(byt & 0x80){
            sda = 1;
        }
        else{
            sda = 0;
        }
		I2C_Delay(DELAY_TIME);
        scl = 1;
        byt <<= 1;
		I2C_Delay(DELAY_TIME);
    }
	
    scl = 0;  
}

//
unsigned char I2CReceiveByte(void)
{
	unsigned char da;
	unsigned char i;
	for(i=0;i<8;i++){   
		scl = 1;
		I2C_Delay(DELAY_TIME);
		da <<= 1;
		if(sda) 
			da |= 0x01;
		scl = 0;
		I2C_Delay(DELAY_TIME);
	}
	return da;    
}

//
unsigned char I2CWaitAck(void)
{
	unsigned char ackbit;
	
    scl = 1;
	I2C_Delay(DELAY_TIME);
    ackbit = sda; 
    scl = 0;
	I2C_Delay(DELAY_TIME);
	
	return ackbit;
}

uchar AD_Read(uchar add)
{
	uchar temp;
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	I2CSendByte(add);
	I2CWaitAck();
	I2CStop();
	
	I2CStart();
	I2CSendByte(0x91);
	I2CWaitAck();
	temp=I2CReceiveByte();
	I2CWaitAck();
	I2CStop();
	
	return temp;
}
void EEPROM_Write(uchar add,uchar dat)
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(add);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
}
uchar EEPROM_Read(uchar add)
{
	uchar temp;
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(add);
	I2CWaitAck();
	I2CStop();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	temp=I2CReceiveByte();
	I2CWaitAck();
	I2CStop();
	
	return temp;
}
iic.h
#ifndef _IIC_H
#define _IIC_H

#define uchar unsigned char
#define uint unsigned int
	
static void I2C_Delay(unsigned char n);
void I2CStart(void);
void I2CStop(void);
void I2CSendByte(unsigned char byt);
unsigned char I2CReceiveByte(void);
unsigned char I2CWaitAck(void);
uchar AD_Read(uchar add);
void EEPROM_Write(uchar add,uchar dat);
uchar EEPROM_Read(uchar add);
#endif
ds1302.c
#include <stc15f2k60s2.h>
#include <ds1302.h>
#include <intrins.h>
char shijian[7];
uchar Init_Time[]={55,59,23,0,0,0,0};

sbit SCK=P1^7;
sbit SDA=P2^3;
sbit RST=P1^3;

//
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_();
 	SCK=0;	_nop_();
 	RST=1; 	_nop_();  
 	Write_Ds1302(address);	
	dat=(dat/10)<<4 | dat%10;
 	Write_Ds1302(dat);		
 	RST=0; 
}

//
unsigned char Read_Ds1302_Byte ( unsigned char address )
{
 	unsigned char i,temp=0x00,dat1,dat2;
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1;	_nop_();
 	Write_Ds1302(address);
 	for (i=0;i<8;i++) 	
 	{		
		SCK=0;
		temp>>=1;	
 		if(SDA)
 		temp|=0x80;	
 		SCK=1;
	} 
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
	SCK=1;	_nop_();
	SDA=0;	_nop_();
	SDA=1;	_nop_();
	dat1=temp/16;
	dat2=temp%16;
	temp=dat1*10+dat2;
	return (temp);			
}
void DS1302_Init(void)
{
	uchar i,add;
	add=0x80;
	Write_Ds1302_Byte(0x8e,0x00);
	for(i=0;i<7;i++)
	{
		Write_Ds1302_Byte(add,Init_Time[i]);
		add+=2;
	}
	Write_Ds1302_Byte(0x8e,0x80);
}
void DS1302_Gett(void)
{
	uchar i,add;
	add=0x81;
	Write_Ds1302_Byte(0x8e,0x00);
	for(i=0;i<7;i++)
	{
		shijian[i]=Read_Ds1302_Byte(add);
		add+=2;
	}
	Write_Ds1302_Byte(0x8e,0x80);
}
ds1302.h
#ifndef _DS1302_H
#define _DS1302_H

#define uchar unsigned char
#define uint unsigned int
	
void Write_Ds1302(unsigned  char temp);
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );     
unsigned char Read_Ds1302_Byte ( unsigned char address );
void DS1302_Init(void);
void DS1302_Gett(void);


#endif
main.c
#include <stc15f2k60s2.h>
#include <iic.h>
#include <ds1302.h>

uchar tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff};
uchar dis_bit[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
uchar dis_buf[]={11,11,11,11,11,11,11,11};
void Allinit(void);
void display(void);
void Delayms(uint ms);
void keyscan(void);
void Timer0Init(void);
void Time_Display(void);//时钟显示函数
void Voltage_Display(void);//电压显示函数
void Freq_Display(void);//频率显示函数
void Timer1Init(void);
void Interrupt_Appeared(void);//判断采集是否发生函数
void Search_Display(void);//查询显示函数
extern char shijian[7];
extern uchar Init_Time[7];
int Vcc,Vh=2000,Vl=1000;
uint freq,time,zheng,fan,Newzheng,Newfan,period;
bit hour,second,minute,high,low,flag,start,T,Low_Enter_flag,High_Enter_flag,st;//设置了上升和下降沿触发的标志位,具体可以看判断采集发生函数
uchar Three_Clock,i,clock=0,voltage=0,high_low_mode=0,tt,Low_flag,Low_count,High_flag,High_count,search,Type,a,b,c;

void main(void)
{
	Allinit();
	DS1302_Init();
	Timer0Init();
	Timer1Init();
	Vh=EEPROM_Read(0x10)*100;
	Delayms(10);
	Vl=EEPROM_Read(0x20)*100;
	Delayms(10);
	a=EEPROM_Read(0x30);
	Delayms(10);
	b=EEPROM_Read(0x40);
	Delayms(10);
	c=EEPROM_Read(0x50);
	Delayms(10);
	Type=EEPROM_Read(0x60);
	Delayms(10);
	while(1)
	{
		if(voltage==1){Vcc=AD_Read(0x03)*19.53125;}
		if(clock==1&&Three_Clock==0){DS1302_Gett();}
		keyscan();
		Time_Display();
		Voltage_Display();
		Freq_Display();
		Interrupt_Appeared();
		Search_Display();
		display();
	}
}

void keyscan(void)//矩阵键盘函数,这种写法可以借鉴一下,挺好理解的
{
	uchar row=5,col=5,keyval=0xff;
	P30=1;P31=1;P32=1;P33=1;
	P34=0;P35=0;P42=0;P44=0;
	if(P30==0||P31==0||P32==0||P33==0)
	{
		Delayms(10);
		if(P30==0||P31==0||P32==0||P33==0)
		{
			if(P30==0)row=0;
			else if(P31==0)row=1;
			else if(P32==0)row=2;
			else if(P33==0)row=3;
			P30=0;P31=0;P32=0;P33=0;
			P34=1;P35=1;P42=1;P44=1;
			if(P34==0)col=3;
			if(P35==0)col=2;
			if(P42==0)col=1;
			if(P44==0)col=0;
		}
		while(P34==0||P35==0||P42==0||P44==0);
		keyval = 4*row+col;
	}
	switch(keyval)
	{
		case 0:
		voltage=0;high_low_mode=0;start=0;search=0;
		clock++;//记得进入其他的之前把clock清零,其他同理
		break;//shizhong
		case 1:
		if(clock==1)
		{
			if(Three_Clock==1)//这里全部再赋值的目的是精准的获取此刻的时间
			{
				shijian[2]++;if(shijian[2]==24){shijian[2]=0;}
				Init_Time[2]=shijian[2];Init_Time[1]=shijian[1];Init_Time[0]=shijian[0];if(Init_Time[2]==24)Init_Time[2]=0;
			}
			else if(Three_Clock==2)
			{
				shijian[1]++;if(shijian[1]==60){shijian[1]=0;}
				Init_Time[2]=shijian[2];Init_Time[1]=shijian[1];Init_Time[0]=shijian[0];if(Init_Time[1]==60)Init_Time[1]=0;
			}
			else if(Three_Clock==3)
			{
				shijian[0]++;if(shijian[0]==60){shijian[0]=0;}
				Init_Time[2]=shijian[2];Init_Time[1]=shijian[1];Init_Time[0]=shijian[0];if(Init_Time[0]==60)Init_Time[0]=0;
			}
		}
		if(voltage==1)
		{
			if(high_low_mode==1)
			{
				Vh+=500;if(Vh>5000)Vh=5000;
			}
			else if(high_low_mode==2)
			{
				Vl+=500;if(Vl>5000)Vl=5000;
			}
		}
		break;//jia
		case 4:
		clock=0;Three_Clock=0;start=0;search=0;//进入其他操作之前一定要把前一个操作的所有标志位置零
		voltage++;
		break;//dianya
		case 5:
		if(clock==1)
		{
			if(Three_Clock==1)
			{
				shijian[2]--;if(shijian[2]<0){shijian[2]=23;}
				Init_Time[2]=shijian[2];Init_Time[1]=shijian[1];Init_Time[0]=shijian[0];if(Init_Time[2]<0)Init_Time[2]=59;
			}
			else if(Three_Clock==2)
			{
				shijian[1]--;if(shijian[1]<0){shijian[1]=59;}
				Init_Time[2]=shijian[2];Init_Time[1]=shijian[1];Init_Time[0]=shijian[0];if(Init_Time[1]<0)Init_Time[1]=59;
			}
			else if(Three_Clock==3)
			{
				shijian[0]--;if(shijian[0]<0){shijian[0]=59;}
				Init_Time[2]=shijian[2];Init_Time[1]=shijian[1];Init_Time[0]=shijian[0];if(Init_Time[0]<0)Init_Time[0]=59;
			}
		}	
		if(voltage==1)
		{
			if(high_low_mode==1)
			{
				Vh-=500;if(Vh<0)Vh=0;
			}
			else if(high_low_mode==2)
			{
				Vl-=500;if(Vl<0)Vl=0;
			}
		}
		break;//jian
		case 8:
		clock=0;Three_Clock=0;voltage=0;high_low_mode=0;tt=0;
		start=1;search=0;
		break;//pinglv
		
		case 9:
		search=1;clock=0;Three_Clock=0;voltage=0;high_low_mode=0;start=0;
		break;//chaxun
		case 12:
		if(clock==1)//时钟子功能,三个闪烁
		{
			Three_Clock++;i=0;
			if(Three_Clock==4)Three_Clock=1;
		}
		if(voltage==1)
		{
			high_low_mode++;i=0;
			if(high_low_mode==3)high_low_mode=1;
		}
		if(start==1)
		{
			if(T==1)T=0;
			else if(T==0)T=1;
		}
		if(search==1)
		{
			if(st==1)st=0;
			else if(st==0)st=1;
		}
		break;//gongneng
		default:break;
	}
	
}

void Timer0Init(void)		//5毫秒@11.0592MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x00;		//设置定时初值
	TH0 = 0x28;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	EA=1;
	ET0=1;
}

void Tim0(void) interrupt 1
{
	i++;
	if(i==200)
	{
		i=0;
		if(Three_Clock==1)//时
		{
			hour=~hour;
			if(hour==1)
			{
				dis_buf[0]=11;dis_buf[1]=11;dis_buf[2]=10;
				dis_buf[3]=shijian[1]/10;dis_buf[4]=shijian[1]%10;dis_buf[5]=10;
				dis_buf[6]=shijian[0]/10;dis_buf[7]=shijian[0]%10;
			}
			else if(hour==0)
			{
				dis_buf[0]=shijian[2]/10;dis_buf[1]=shijian[2]%10;dis_buf[2]=10;
				dis_buf[3]=shijian[1]/10;dis_buf[4]=shijian[1]%10;dis_buf[5]=10;
				dis_buf[6]=shijian[0]/10;dis_buf[7]=shijian[0]%10;
			}
		}
		else if(Three_Clock==2)//分
		{
			minute=~minute;
			if(minute==1)
			{
				dis_buf[0]=shijian[2]/10;dis_buf[1]=shijian[2]%10;dis_buf[2]=10;
				dis_buf[3]=11;dis_buf[4]=11;dis_buf[5]=10;
				dis_buf[6]=shijian[0]/10;dis_buf[7]=shijian[0]%10;
			}
			else if(minute==0)
			{
				dis_buf[0]=shijian[2]/10;dis_buf[1]=shijian[2]%10;dis_buf[2]=10;
				dis_buf[3]=shijian[1]/10;dis_buf[4]=shijian[1]%10;dis_buf[5]=10;
				dis_buf[6]=shijian[0]/10;dis_buf[7]=shijian[0]%10;
			}
		}
		else if(Three_Clock==3)//秒
		{
			second=~second;
			if(second==1)
			{
				dis_buf[0]=shijian[2]/10;dis_buf[1]=shijian[2]%10;dis_buf[2]=10;
				dis_buf[3]=shijian[1]/10;dis_buf[4]=shijian[1]%10;dis_buf[5]=10;
				dis_buf[6]=11;dis_buf[7]=11;
			}
			else if(second==0)
			{
				dis_buf[0]=shijian[2]/10;dis_buf[1]=shijian[2]%10;dis_buf[2]=10;
				dis_buf[3]=shijian[1]/10;dis_buf[4]=shijian[1]%10;dis_buf[5]=10;
				dis_buf[6]=shijian[0]/10;dis_buf[7]=shijian[0]%10;
			}
		}
		if(high_low_mode==1)
		{
			high=~high;
			if(high==1)
			{
				dis_buf[0]=Vh/1000;dis_buf[1]=Vh%1000/100;dis_buf[2]=Vh%100/10;
				dis_buf[3]=Vh%10;dis_buf[4]=Vl/1000;dis_buf[5]=Vl%1000/100;
				dis_buf[6]=Vl%100/10;dis_buf[7]=Vl%10;
			}
			else if(high==0)
			{
				dis_buf[0]=11;dis_buf[1]=11;dis_buf[2]=11;
				dis_buf[3]=11;dis_buf[4]=Vl/1000;dis_buf[5]=Vl%1000/100;
				dis_buf[6]=Vl%100/10;dis_buf[7]=Vl%10;
			}
		}
		else if(high_low_mode==2)
		{
			low=~low;
			if(low==1)
			{
				dis_buf[0]=Vh/1000;dis_buf[1]=Vh%1000/100;dis_buf[2]=Vh%100/10;
				dis_buf[3]=Vh%10;dis_buf[4]=Vl/1000;dis_buf[5]=Vl%1000/100;
				dis_buf[6]=Vl%100/10;dis_buf[7]=Vl%10;
			}
			else if(low==0)
			{
				dis_buf[0]=Vh/1000;dis_buf[1]=Vh%1000/100;dis_buf[2]=Vh%100/10;
				dis_buf[3]=Vh%10;dis_buf[4]=11;dis_buf[5]=11;
				dis_buf[6]=11;dis_buf[7]=11;
			}
		}
	}

//以下是频率测量,NE555频率有范围,既要有最小测量时间也要有最大
	if(start==1)
	{
		tt++;
	}
	if(tt==192&&start==1)
	{
		TR1=1;
	}
	else if(tt==198)
	{
		TR1=0;tt=0;
		do
		{
			time=(Newzheng+Newfan)*5;
			freq=1000000/time;
		}
		while(freq==65535);
	}
	
}

void Timer1Init(void)		//50微秒@11.0592MHz
{
	AUXR |= 0x40;		//定时器时钟1T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0xc9;		//设置定时初值
	TH1 = 0xFf;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	EA=1;		//定时器1开始计时
	ET1=1;
}

void Tim1(void) interrupt 3
{
	if(P34==1)
	{
		zheng++;
		if(flag==1)
		{
			flag=0;
			Newfan=fan;
			fan=0;
		}
	}
	else if(P34==0)
	{
		fan++;
		if(flag==0)
		{
			flag=1;
			Newzheng=zheng;
			zheng=0;
		}
	}
}

void Time_Display(void)//时钟显示函数
{
	if(clock==1&&Three_Clock==0)
	{
		dis_buf[0]=shijian[2]/10;dis_buf[1]=shijian[2]%10;dis_buf[2]=10;
		dis_buf[3]=shijian[1]/10;dis_buf[4]=shijian[1]%10;dis_buf[5]=10;
		dis_buf[6]=shijian[0]/10;dis_buf[7]=shijian[0]%10;
	}
	else if(clock==2)
	{
		DS1302_Init();clock=1;Three_Clock=0;
	}
}

void Voltage_Display(void)//电压显示函数
{
	if(voltage==1&&high_low_mode==0)
	{
		dis_buf[0]=10;dis_buf[1]=1;dis_buf[2]=10;
		dis_buf[3]=11;dis_buf[4]=Vcc/1000;dis_buf[5]=Vcc%1000/100;
		dis_buf[6]=Vcc%100/10;dis_buf[7]=Vcc%10;	
	}
	else if(voltage==2)
	{
		voltage=1;high_low_mode=0;
		EEPROM_Write(0x10,Vh/100);Delayms(10);
		EEPROM_Write(0x20,Vl/100);Delayms(10);
	}
}

void Freq_Display(void)//频率显示函数
{
	if(start==1&&T==0)
	{
		dis_buf[0]=10;dis_buf[1]=2;dis_buf[2]=10;
		dis_buf[3]=freq/10000;dis_buf[4]=freq%10000/1000;dis_buf[5]=freq%1000/100;
		dis_buf[6]=freq%100/10;dis_buf[7]=freq%10;	
	}
	else if(start==1&&T==1)
	{
		period=1000000/freq;
		dis_buf[0]=10;dis_buf[1]=2;dis_buf[2]=10;
		dis_buf[3]=period/10000;dis_buf[4]=period%10000/1000;dis_buf[5]=period%1000/100;
		dis_buf[6]=period%100/10;dis_buf[7]=period%10;
	}
}

void Interrupt_Appeared(void)//采集发生判断函数
{
	if(Vcc>Vl&&Low_Enter_flag==0)//下降检测
	{
		Low_flag++;Low_Enter_flag=1;
	}
	else if(Vcc<Vl&&Low_flag>Low_count)
	{
		Low_count++;Low_Enter_flag=0;Type=0;
		a=shijian[2];b=shijian[1];c=shijian[0];
		EEPROM_Write(0x30,a);Delayms(10);//延时不能掉
		EEPROM_Write(0x40,b);Delayms(10);
		EEPROM_Write(0x50,c);Delayms(10);
		EEPROM_Write(0x60,Type);Delayms(10);
	}
	
	if(Vcc<Vh&&High_Enter_flag==0)//上升检测
	{
		High_flag++;High_Enter_flag=1;
	}
	else if(Vcc>Vh&&High_flag>High_count)
	{
		High_count++;High_Enter_flag=0;Type=1;
		a=shijian[2];b=shijian[1];c=shijian[0];
		EEPROM_Write(0x30,a);Delayms(10);
		EEPROM_Write(0x40,b);Delayms(10);
		EEPROM_Write(0x50,c);Delayms(10);
		EEPROM_Write(0x60,Type);Delayms(10);
	}
}

void Search_Display(void)//查询显示函数
{
	if(search==1&&st==0)
	{
		dis_buf[0]=11;dis_buf[1]=11;dis_buf[2]=11;
		dis_buf[3]=11;dis_buf[4]=11;dis_buf[5]=11;
		dis_buf[6]=Type/10;dis_buf[7]=Type%10;
	}
	else if(search==1&&st==1)
	{
		dis_buf[0]=a/10;dis_buf[1]=a%10;dis_buf[2]=10;
		dis_buf[3]=b/10;dis_buf[4]=b%10;dis_buf[5]=10;
		dis_buf[6]=c/10;dis_buf[7]=c%10;
	}
}

void Allinit(void)
{
	P2=(P2&0x1f)|0xa0;
	P0=0x00;P2=0;
	P2=(P2&0x1f)|0x80;
	P0=0xff;P2=0;
	P2=(P2&0x1f)|0xc0;
	P0=0x00;P2=0;
	P2=(P2&0x1f)|0xf0;
	P0=0xff;P2=0;
}

void display(void)//数码管的动态显示
{
	uchar i;
	for(i=0;i<8;i++)
	{
		P0=0x00;
		P2=(P2&0x1f)|0xc0;
		P0=dis_bit[i];
		P2=0;
		
		P0=0xff;
		P2=(P2&0x1f)|0xf0;
		P0=tab[dis_buf[i]];
		P2=0;
		
		Delayms(1);
		
		P2=(P2&0x1f)|0xf0;//消除鬼影
		P0=0xff;P2=0;
	}
}

void Delayms(uint ms)
{
	uint i,j;
	for(i=ms;i>0;i--)
	for(j=845;j>0;j--);
}

以上就是第七届国赛的全部功能,均已实现,有不足之处望大佬们的指点!谢谢

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值