第十届蓝桥杯省赛再现(编程部分)


2019年3月26日更新

重新审了一下题目要求,好的,最基础的错误审题错误,没有理会出题人意思。

1、电压测量显示模式下就一直显示RB2的输出电压,不会随着S5的按下而锁定为2.0V

2、S5改变的是DAC输出,还是要写DAC输出,S5决定DAC的输出是否锁定。

代码就懒得改了

就这水平还想着进国赛,脑子有泡吧!专心考研吧孩子。


ok,蓝桥第一阶段告一段落,看一个月后能不能进国赛再说了。

emmmm,忘了备份试题pdf......

那就完全靠回忆吧。

1、题目

需要使用AD模块、数码管、LED、NE555以及独立按键。

第十届蓝桥杯省赛再现(编程部分)

第十届蓝桥杯省赛再现(编程部分)

第十届蓝桥杯省赛再现(编程部分)

第十届蓝桥杯省赛再现(编程部分)

2、思路

其实我拿到这个题后,一看笑了,使用NE555测频,不就是第七届国赛题吗,而且官方在赛前以及在官网放了这个模拟题,我正好就写了这个题(滑稽)。参考 https://blog.****.net/Xiaomo_haa/article/details/88597373

但是又一看,DAC,我他妈,我还没调试过这个东西啊,当时就懵逼了,但是再一看,什么鬼DAC,还是AD。

那么,这个题就很有意思了,非常简单了。

NE555测频原理

很多人不知道NE555测频怎么搞,其实很简单。

第十届蓝桥杯省赛再现(编程部分)

已经使用跳线帽将P34和NE555的输出端接在一起了,关乎NE555,有些许数电基础的都明白,NE555就是改变RB3,改变负载电阻,使其输出方波的频率发生改变,其中并不涉及任何对NE555的编程,当然你也没法对其编程。

官方的CT107D的NE555输出频率范围是50-20K赫兹(以上)。

那么我们怎么测频呢。

P34对应的是单片机的定时器0的脉冲输入口,那么我们可以把定时器0设置为计数模式,每接收到NE555的一个脉冲,定时器0计数值就加1,然后500ms读取一次定时器0的计数值,再乘以2大约就是1s内的脉冲,不就是NE555输出的方波的频率吗。

然后按键、LED、数码管等等其余需要使用定时器的就使用定时器1来完成。

3、程序

这个题真的很简单,一小时多一点点搞定。

注释写的应该够详细了,凑合看吧。

main.c

#include "sys.h"

bit flag200ms = 0, flag500ms = 0;
bit flagval = 0, flagled = 1, flagtube = 1;
unsigned char mode = 2;
unsigned int FRE, VAL;
unsigned char LEDDAT = 0xff, led = 0xff;

void main(void)
{
	All_Init();
	Timer1Init();
	Timer0Init();
	EA = 1;
	while(1)
	{
		//200ma读取一次AD
		if(flag200ms)
		{
			flag200ms = 0;
			VAL = Read_AIN(0x03);		//读取AIN3的数据
		}
		//500ms测频一次
		if(flag500ms)
		{
			flag500ms = 0;
			TR0 = 0;								//关闭定时器0计数
			FRE = TH0 * 256 + TL0;	//统计500ms内脉冲数
			FRE *= 2;								//乘以2就是1s内脉冲数,就是频率
			TH0 = TL0 = 0;					//清除定时器0计数数据
			TR0 = 1; 								//定时器0重新开始计数
		}

		//如果S5按下,val就是固定的2.0V
		if(flagval == 0)
			VAL = 200;

		//如果LED显示打开
		if(flagled)
		{
			switch(mode)
			{
				case 1: LEDDAT = (LEDDAT | 0x03) & 0xfd; break;			//模式1为测频模式
				case 2: LEDDAT = (LEDDAT | 0x03) & 0xfe; break;			//模式2为测电压模式
			}

			//如果是测频模式,根据范围选择点亮LED
			if(mode == 1)		
			{
				LEDDAT = LEDDAT | 0x10;		//关闭L5
				LEDDAT = LEDDAT | 0x04;		//关闭L3					
				if(FRE < 1000)
					LEDDAT = LEDDAT | 0x08;	//关闭L4
				else if((FRE >= 1000) && (FRE < 5000))
					LEDDAT = (LEDDAT | 0x08) & 0xf7;	//打开L4
				else if((FRE >= 5000) && (FRE < 10000))
					LEDDAT = LEDDAT | 0x08;		//关闭L4
				else if(FRE > 10000)
					LEDDAT = (LEDDAT | 0x08) & 0xf7;	//打开L4
			}
			//如果是测电压模式,根据电压范围选择点亮LED
			else if(mode == 2)
			{
				//不是固定输出2.0V状态
				if(flagval)	
				{
					LEDDAT = LEDDAT & 0xef;		//打开L5
					LEDDAT = LEDDAT | 0x08;		//关闭L4
					if(VAL < 150)
						LEDDAT = LEDDAT | 0x04;	//关闭L3
					else if((VAL >= 150) && (VAL < 250))
						LEDDAT = (LEDDAT | 0x04) & 0xfb;	//打开L3
					else if((VAL > 250) && (VAL < 350))
						LEDDAT = LEDDAT | 0x04;	//关闭L3
					else if(VAL > 350)
						LEDDAT = (LEDDAT | 0x04) & 0xfb;		//打开L3
				}
				//固定输出2.0V状态
				else 
				{
					LEDDAT = LEDDAT | 0x10;			//关闭L5
					LEDDAT = LEDDAT | 0x04;			//关闭L3
				}
			}
		}
		//LED关闭状态,LED全灭
		else
			LEDDAT = 0xff;
		
		led = LEDDAT;

		KeyPress();
		TubeScan();
	}
}

sys.c

#include "sys.h"

void All_Init(void)
{
	P2 = (P2 & 0x1f) | 0x80;
	P0 = 0xff;				
	P2 = (P2 & 0x1f) | 0xe0;
	P0 = 0xff;			
	P2 = (P2 & 0x1f) | 0xa0;	
	P0 = 0x00;				
	P2 = P2 & 0x1f;
}

//定时器1初始化
void Timer1Init(void)		//2毫秒@12.000MHz
{
	AUXR &= 0xBF;		//定时器时钟12T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0x30;		//设置定时初值
	TH1 = 0xF8;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	ET1 = 1;
}

//定时器1中断服务程序
void Timer1(void) interrupt 3
{
	static unsigned char t00 = 0, t01 = 0;

	t00 ++;		//200ms
	t01 ++;		//500ms

	if(t00 >= 100)
	{
		t00 = 0;
		flag200ms = 1;
	}

	if(t01 >= 250)
	{
		t01 = 0;
		flag500ms = 1;
	} 

	LedLight();
	KeyScan();
	TubeShow();
}

//定时器0初始化为计数模式
void Timer0Init(void)
{
	AUXR &= 0x7F;					//定时器时钟12T模式
  TMOD = 0x04;          //设置定时器0为16位自动重装载外部记数模式
  TH0 = TL0 = 0;     		//设置定时器0初始值
	TR0 = 1;              //定时器0开始工作
}

sys.h

#ifndef _SYS_H_
#define _SYS_H_

#include <stc15.h>
#include <intrins.h>
#include "iic.h"

sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;

extern bit flag200ms, flag500ms;
extern bit flagval, flagled, flagtube;
extern unsigned char mode;		//mode=为测频模式, mode =2为测电压模式
extern unsigned int FRE, VAL;
extern unsigned char LEDDAT, led;

void All_Init(void);
void Timer1Init(void);
void Timer0Init(void);

void KeyScan(void);
void KeyPress(void);
void KeyAction(unsigned char key);

void TubeScan(void);
void TubeShow(void);
void LedLight(void);



#endif

display.c

#include "sys.h"

unsigned char code table[]={0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 
                            0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e,
														0xff, 0xbf, 0xc1};
unsigned char TubeBuff[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
unsigned char smg1, smg2, smg3, smg4, smg5, smg6, smg7, smg8;

void TubeShow(void)
{
	static unsigned char index = 0;
	
	P0 = 0x00;
	P2 = (P2 & 0x1f) | 0xc0;
	P0 = 0x01 << index;
	P2 = P2 & 0x1f;
	
	P0 = 0xff;
	P2 = (P2 & 0x1f) | 0xe0;
	P0 = TubeBuff[index];
	P2 = P2 & 0x1f;
	
	index ++;
	index &= 0x07;
}

void TubeScan(void)
{
	//如果为测频显示,这样显示
	if(mode == 1)
	{
		smg1 = 15;		//显示F
		smg2 =smg3 = 16;	 	//熄灭
		smg4 = FRE / 10000;
		smg5 = (FRE % 10000) / 1000;
		smg6 = (FRE % 1000) / 100;
		smg7 = (FRE % 100) / 10;
		smg8 = FRE % 10;
	
		//消0
		if(smg4 == 0)
		{
			smg4 = 16;
			if(smg5 == 0)
			{
				smg5 = 16;
				if(smg6 == 0)
				{
					smg6 = 16;
					if(smg7 == 0)
					{
						smg7 = 16;
					}
				}
			}
		}
	}
	//如果是测电压模式
	else if(mode == 2)
	{
		smg1 = 18;			 		//显示U
		smg2 = smg3 = smg4 = smg5 = 16;	 //熄灭
		smg6 = VAL / 100;
		smg7 = (VAL % 100) / 10;
		smg8 = VAL % 10;
	}

	//如果关闭数码管时全部熄灭
	if(flagtube == 0)
		smg1 = smg2 = smg3 = smg4 = smg5 = smg6 = smg7 = smg8 = 16;

	if((mode == 2) && (flagtube == 1))
		TubeBuff[5] = table[smg6] & 0x7f;		//测电压时加上小数点
	else
			TubeBuff[5] = table[smg6];		
	TubeBuff[0] = table[smg1];
	TubeBuff[1] = table[smg2];
	TubeBuff[2] = table[smg3];
	TubeBuff[3] = table[smg4];
	TubeBuff[4] = table[smg5];
	TubeBuff[6] = table[smg7];
	TubeBuff[7] = table[smg8];
}

void LedLight(void)
{
	P0 = 0xff;
	P2 = (P2 & 0x1f) | 0x80;
	P0 = led;			
	P2 = P2 & 0x1f;
}

key.c

#include "sys.h"

unsigned char keysta[] = {1, 1, 1, 1};
unsigned char keybackup[] = {1, 1, 1, 1};

unsigned char keybuff[] = {0xff, 0xff, 0xff, 0xff};

void KeyScan(void)
{
	unsigned char i;

	keybuff[0] = (keybuff[0] << 1) | S4;
	keybuff[1] = (keybuff[1] << 1) | S5;
	keybuff[2] = (keybuff[2] << 1) | S6;
	keybuff[3] = (keybuff[3] << 1) | S7;

	for(i = 0; i < 4; i ++)
	{
		if(keybuff[i] == 0xff)
			keysta[i] = 1;
		else if(keybuff[i] == 0x00)
			keysta[i] = 0;
	}
}

void KeyPress(void)
{
	unsigned char i;

	for(i = 0; i < 4; i ++)
	{
		if(keysta[i] != keybackup[i])
		{
			if(keysta[i] == 0)
				KeyAction(i);
			keybackup[i] = keysta[i];
		}
	}
}

void KeyAction(unsigned char key)
{
	//S4按键切换测频和测电压模式
	if(key == 0)	
	{
		if(mode == 1)	//如果是模式就切换到模式2
			mode = 2;
		else if(mode == 2)	//如果是模式2就切换到模式
			mode = 1;
	}

	//S5为是否为固定输出2.0V
	else if(key == 1)
		flagval = !flagval;

	//S6控制是否打开LED
	else if(key == 2)	
		flagled = ~flagled;

	//S7控制是否打开数码管显示
	else if(key == 3)	//S7
		flagtube = !flagtube;
}



iic.c

#include "sys.h"

#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}    

sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */

void IIC_Start(void)
{
	SDA = 1;
	SCL = 1;
	somenop;
	SDA = 0;
	somenop;
	SCL = 0;	
}

void IIC_Stop(void)
{
	SDA = 0;
	SCL = 1;
	somenop;
	SDA = 1;
}

void IIC_Ack(bit ackbit)
{
	if(ackbit) 
	{	
		SDA = 0;
	}
	else 
	{
		SDA = 1;
	}
	somenop;
	SCL = 1;
	somenop;
	SCL = 0;
	SDA = 1; 
	somenop;
}

bit IIC_WaitAck(void)
{
	SDA = 1;
	somenop;
	SCL = 1;
	somenop;
	if(SDA)    
	{   
		SCL = 0;
		IIC_Stop();
		return 0;
	}
	else  
	{ 
		SCL = 0;
		return 1;
	}
}

void IIC_SendByte(unsigned char byt)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{   
		if(byt&0x80) 
		{	
			SDA = 1;
		}
		else 
		{
			SDA = 0;
		}
		somenop;
		SCL = 1;
		byt <<= 1;
		somenop;
		SCL = 0;
	}
}

unsigned char IIC_RecByte(void)
{
	unsigned char da;
	unsigned char i;
	
	for(i=0;i<8;i++)
	{   
		SCL = 1;
		somenop;
		da <<= 1;
		if(SDA) 
		da |= 0x01;
		SCL = 0;
		somenop;
	}
	return da;
}

unsigned int Read_AIN(unsigned char chn)
{
	unsigned int temp_val;
	unsigned char dat;
	IIC_Start();							
	IIC_SendByte(0x90);		
	IIC_WaitAck();  		  
	IIC_SendByte(chn); 		
	IIC_WaitAck();  			
	IIC_Stop(); 					
	
	IIC_Start();									
	IIC_SendByte(0x91); 	
	IIC_WaitAck(); 			  
	dat = IIC_RecByte();				
	IIC_Ack(0); 					
	IIC_Stop(); 	
	temp_val = ((unsigned int)(dat) * (50000 / 255));
	temp_val /= 100;
	
	return temp_val;	
}

iic.h

#ifndef _IIC_H
#define _IIC_H

void IIC_Start(void); 
void IIC_Stop(void);  
void IIC_Ack(bit ackbit); 
void IIC_SendByte(unsigned char byt); 
bit IIC_WaitAck(void);  
unsigned char IIC_RecByte(void); 
unsigned int Read_AIN(unsigned char chn);
void Write_E2PROM(unsigned char add, unsigned char dat);
unsigned char Read_E2PROM(unsigned char add);


#endif