蓝桥杯第十三届国赛程序设计题

前言:定时器是用的珍妮码多。

题目

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

个人理解与感受

首先看上去模块比前两年多了,但其实底层大部分用的是IIC,另外两个没考。来了个PWM NE555 长短按检测 LED秒闪定时器全家桶我是真的服了,PWM还挤不进去定时器0和1(因为1KHZ的80%占空比需要有100μs才能好好走,而频率测量占用的完全是两个极端:一个要1s一个就要一次),把它塞进定时器2的后果是优先级太低了,占空比调不准确。
然后我发现记录“数据记录”的次数,好像连续考了三年,还是两年,非常奇特,一个标志位的事情搞定。
这次新加了Y5,之前都是只考Y4(LED)、Y6(数码管位选)、(Y7)(数码管段选),这也称得上是一种创新吧。霍尔元件对参赛选手对单片机开发以外的学科要求比较高,可能就不大会考,步进电机更是要大量占用定时器资源,更不太可能考。

底层驱动代码

玛德把IIC给玩出花了,IIC全来一遍,另外两个驱动愣是用都不用。

IIC

unsigned char dianya(){
	unsigned char ret;
	
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	I2CSendByte(0x43);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0x91);
	I2CWaitAck();
	ret = I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();
	
	return ret;
}

void DAC(unsigned char dat){
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	I2CSendByte(0x41);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
}

void eepromwrite(unsigned char dat){
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(0x00);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
}

unsigned char eepromread(){
	unsigned char ret;
	
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(0x00);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	ret = I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();
	
	return ret;
}

延迟函数以及锁存器

void Delay(unsigned char xms)	//@12.000MHz
{
	while(xms--){
		unsigned char data i, j;

	i = 12;
	j = 169;
	do
	{
		while (--j);
	} while (--i);
	}
}
#include <STC15F2K60S2.H>
#include "delay.h"

void inithc138(unsigned char channel){
	switch(channel){
		case 0:P2 = (P2 & 0x1f) | 0x00;break;
		case 4:P2 = (P2 & 0x1f) | 0x80;break;
		case 5:P2 = (P2 & 0x1f) | 0xa0;break;
		case 6:P2 = (P2 & 0x1f) | 0xc0;break;
		case 7:P2 = (P2 & 0x1f) | 0xe0;break;
	}
}

void outputp0(unsigned char channel,unsigned char dat){
	inithc138(0);
	P0 = dat;
	inithc138(channel);
	inithc138(0);
}

void showsmg(unsigned char pos,unsigned char dat){
	outputp0(7,0xff);
	outputp0(6,0x01 << (pos - 1));
	outputp0(7,dat);
	Delay(1);
}

void initsys(){
	outputp0(4,0xff);
	outputp0(5,0x00);
	outputp0(6,0xff);
	outputp0(7,0xff);
}

主程序核心代码

#include <STC15F2K60S2.H>
#include "intrins.h"
#include "delay.h"
#include "inithc138.h"
#include "iic.h"


#define de 5
code unsigned char Seg_Table[17] = 
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0x88, //A
0x83, //b
0xc6, //C
0xa1, //d
0x86, //E
0x8e, //F
0xbf
};
unsigned char count = 0;
unsigned int hz_count = 0;
unsigned int tmp = 0;
unsigned char show = 0;
bit danwei1 = 0;//频率显示的单位
unsigned char voltage = 0;//用于读取电压值
unsigned int wet = 0;//用于转化湿度值
unsigned int time = 0;//超声波接受时间
unsigned int distance = 0;//测距距离
bit danwei2 = 0;//测距界面显示的单位
unsigned char canshu = 0;//参数界面切换
unsigned char hzcanshu = 15;//频率参数
unsigned char wetcanshu = 20;//湿度参数
unsigned char discanshu = 50;//距离参数
bit keystat = 0;//按键状态
unsigned char count_key = 0;//用于数长按的秒数
unsigned int wetDAC = 0;//湿度对输出电压的转换
bit motor = 0;//脉冲输出
unsigned char y5stat = 0x00;
unsigned char pwm = 0;
bit flag = 0;
unsigned char ledstat = 0xff;
bit ledspark = 0;//LED闪烁
bit flag2 = 0;//继电器吸合状态
unsigned char xihecishu = 0;//继电器吸合次数
//**************************************频率测量
void Timer0_Isr(void) interrupt 1
{
	hz_count++;
}
void Timer1_Isr(void) interrupt 3
{
	count++;
	if(keystat){
		count_key++;
	}
	if(count == 20){
		tmp = hz_count;
		hz_count = 0;
		count = 0;
	}
	if(count % 2 == 0){
		ledspark = ~ledspark;
	}
}

void Timer_Init(void)		//@12.000MHz
{
	//50毫秒
	TMOD = 0x07;			//设置定时器模式
	TL1 = 0xB0;				//设置定时初始值
	TH1 = 0x3C;				//设置定时初始值
	TF1 = 0;				//清除TF1标志
	TR1 = 1;				//定时器1开始计时
	ET1 = 1;				//使能定时器1中断
	//单次
	TL0 = 0xFF;				//设置定时初始值
	TH0 = 0xFF;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
	ET0 = 1;				//使能定时器0中断
	EA = 1;
}
//**************************************
//**************************************湿度读取
void shidu(){
	voltage = dianya();
	Delay(1);
	wet = voltage * 100 / 255;
}
//**************************************
//**************************************超声波测距
sbit TX = P1^0;
sbit RX = P1^1;
void Delay12us(void)	//@12.000MHz
{
	unsigned char data i;

	_nop_();
	_nop_();
	i = 33;
	while (--i);
}

void fangbo(){
	unsigned char i;
	for(i = 0;i < 8;i++){
		TX = 1;
		Delay12us();
		TX = 0;
		Delay12us();
	}
}

void ceju(){
	CMOD = 0x00;			//设置定时器模式
	CL = 0x00;				//设置定时初始值
	CH = 0x00;				//设置定时初始值
	CF = 0;				//清除TF0标志
	CR = 0;				//定时器0开始计时
	
	fangbo();
	CR = 1;
	while((RX == 1) && (CH < 17));
	CR = 0;
	
	if(RX == 0){
		RX = 1;
		time = (CH << 8) | CL;
		distance = time * 0.017;
	}
}
//**************************************
//**************************************显示功能
void pinlvjiemian(){//频率界面
	showsmg(1,Seg_Table[15]);
	if(danwei1 == 0){
		showsmg(8,Seg_Table[tmp % 10]);
		if(tmp > 9){showsmg(7,Seg_Table[tmp  / 10 % 10]);}
		if(tmp > 99){showsmg(6,Seg_Table[tmp  / 100 % 10]);}
		if(tmp > 999){showsmg(5,Seg_Table[tmp  / 1000 % 10]);}
		if(tmp > 9999){showsmg(4,Seg_Table[tmp  / 10000 % 10]);}
	}else if(danwei1){
		showsmg(8,Seg_Table[tmp / 100 % 10]);
		showsmg(7,Seg_Table[tmp / 1000 % 10] & 0x7f);
		if(tmp > 9999){showsmg(6,Seg_Table[tmp  / 10000 % 10]);}
	}
}

void shidujiemian(){//湿度界面
	showsmg(1,0x89);
	
	showsmg(8,Seg_Table[wet % 10]);
	if(wet > 9){showsmg(7,Seg_Table[wet / 10 % 10]);}
	if(wet > 99){showsmg(6,Seg_Table[wet / 100]);}
}

void cejujiemian(){
	showsmg(1,Seg_Table[10]);
	if(danwei2 == 0){
		showsmg(8,Seg_Table[distance % 10]);
		if(distance > 9){showsmg(7,Seg_Table[distance / 10 % 10]);}
		if(distance > 99){showsmg(6,Seg_Table[distance / 100 % 10]);}
	}else if(danwei2){
		showsmg(8,Seg_Table[distance % 10]);
		showsmg(7,Seg_Table[distance / 10 % 10]);
		showsmg(6,Seg_Table[distance / 100 % 10] & 0x7f);
	}
}

/*void showcishu(){
	showsmg(8,Seg_Table[xihecishu % 10]);
	showsmg(7,Seg_Table[xihecishu / 10 % 10]);
	showsmg(6,Seg_Table[xihecishu / 100 % 10]);
}*/
//**************************************
//**************************************参数界面
void pinlvcanshu(){//频率参数
	showsmg(1,0x8c);
	showsmg(2,Seg_Table[1]);
	showsmg(7,Seg_Table[hzcanshu / 10 % 10] & 0x7f);
	showsmg(8,Seg_Table[hzcanshu % 10]);
	if(hzcanshu > 99){
		showsmg(6,Seg_Table[hzcanshu / 100]);
	}
}

void shiducanshu(){
	showsmg(1,0x8c);
	showsmg(2,Seg_Table[2]);
	showsmg(7,Seg_Table[wetcanshu / 10]);
	showsmg(8,Seg_Table[wetcanshu % 10]);
}

void julicanshu(){
	showsmg(1,0x8c);
	showsmg(2,Seg_Table[3]);
	showsmg(7,Seg_Table[discanshu / 100] & 0x7f);
	showsmg(8,Seg_Table[discanshu / 10 % 10]);
}

void canshujiemian(){
	switch(canshu){
		case 0:pinlvcanshu();break;
		case 1:shiducanshu();break;
		case 2:julicanshu();break;
	}
}
//**************************************
//**************************************
void showselect(){
	switch(show){
		case 0:pinlvjiemian();break;
		case 1:shidujiemian();break;
		case 2:cejujiemian();break;
		case 3:canshujiemian();break;
		//case 4:showcishu();break;
	}
}
//**************************************
//**************************************DAC输出
void DACshuchu(){
	if(wet > 80){
		wetDAC = 255;
	}else if((wet >= 10) && (wet <= 80)){
		wetDAC = 2.91429 * wet + 21.8568;
	}else if(wet < 10){
		wetDAC = 51;
	}
	DAC(wetDAC);
}
//**************************************
//**************************************按键扫描
void scankey(){
	if(P33 == 0){Delay(de);while(P33 == 0){showselect();}//S4
		show++;
		show %= 4;
		canshu = 0;
	}
	if(show == 3){
		if(P32 == 0){Delay(de);while(P32 == 0){showselect();}//S5
			canshu++;
			canshu %= 3;
		}
	}
	if(P31 == 0){Delay(de);while(P31 == 0){showselect();}//S6
		if(show == 2){
				danwei2 = ~danwei2;
			}
		if(show == 3){
			if(canshu == 0){hzcanshu += 5;if(hzcanshu > 120){hzcanshu = 10;}}
			if(canshu == 1){wetcanshu += 10;if(wetcanshu > 60){wetcanshu = 10;};}
			if(canshu == 2){discanshu += 10;if(discanshu > 120){discanshu = 10;}}
		}
	}
	if(P30 == 0){
		Delay(de);
		while(P30 == 0){
			showselect();
			if(show == 1){
				keystat = 1;
			}
		}
		keystat = 0;
		if(count_key <= 20){
			if(show == 0){
				danwei1 = ~danwei1;
			}
			if(show == 3){
				if(canshu == 0){hzcanshu -= 5;if(hzcanshu < 10){hzcanshu = 120;}}
				if(canshu == 1){wetcanshu -= 10;if(wetcanshu < 10){wetcanshu = 60;};}
				if(canshu == 2){discanshu -= 10;if(discanshu < 10){discanshu = 120;}}
			}
		}else if(count_key > 20){
			xihecishu = 0;
			eepromwrite(xihecishu);
			Delay(2);
		}
		count_key = 0;
	}
}
//**************************************
//**************************************继电器控制功能
void jidianqikongzhi(){
	if(distance > discanshu){
		if(flag2 == 0){
			xihecishu++;
			eepromwrite(xihecishu);
			Delay(2);
		}
		flag2 = 1;
		y5stat = y5stat | 0x10;
	}else{
		flag2 = 0;
		y5stat = y5stat & ~0x10;
	}
	outputp0(5,y5stat);
}
//**************************************
//**************************************脉冲输出功能
void Timer2_Isr(void) interrupt 12
{
	pwm++;
	if(pwm > 10){
		pwm = 1;
	}
	if(motor){
		if(pwm <= 8){
			flag = 1;
		}else if((pwm > 8) && (pwm <= 10)){
			flag = 0;
		}
	}else if(motor == 0){
		if(pwm <= 8){
			flag = 0;
		}else if((pwm > 8) && (pwm <= 10)){
			flag = 1;
		}
	}
}

void Timer2_Init(void)		//100微秒@12.000MHz
{
	AUXR &= 0xFB;			//定时器时钟12T模式
	T2L = 0x9C;				//设置定时初始值
	T2H = 0xFF;				//设置定时初始值
	AUXR |= 0x10;			//定时器2开始计时
	IE2 |= 0x04;			//使能定时器2中断
}

void pinlvpanduan(){
	if(tmp > (100*hzcanshu)){
		motor = 1;
	}else{
		motor = 0;
	}
}

void maichongshuchu(){
	pinlvpanduan();
	if(flag){
		y5stat = y5stat | 0x20;
	}else{
		y5stat = y5stat & ~0x20;
	}
	outputp0(5,y5stat);
}
//**************************************
//**************************************LED指示灯
void LED(){
	if((show == 0) && (ledspark == 1)){
		ledstat = ledstat & ~0x01;
	}else{
		ledstat = ledstat | 0x01;
	}
	
	if((show == 1) && (ledspark == 1)){
		ledstat = ledstat & ~0x02;
	}else{
		ledstat = ledstat | 0x02;
	}
	
	if((show == 2) && (ledspark == 1)){
		ledstat = ledstat & ~0x04;
	}else{
		ledstat = ledstat | 0x04;
	}
	
	if(tmp > (hzcanshu*100)){
		ledstat = ledstat & ~0x08;
	}else{
		ledstat = ledstat | 0x08;
	}
	
	if(wet > wetcanshu){
		ledstat = ledstat & ~0x10;
	}else{
		ledstat = ledstat | 0x10;
	}
	
	if(distance > discanshu){
		ledstat = ledstat & ~0x20;
	}else{
		ledstat = ledstat | 0x20;
	}
	outputp0(4,ledstat);
}
//**************************************
//**************************************
void main(){
	xihecishu = eepromread();
	Delay(2);
	initsys();
	Timer_Init();
	Timer2_Init();
	while(1){
		ceju();
		shidu();
		DACshuchu();
		jidianqikongzhi();
		maichongshuchu();
		LED();
		scankey();
		showselect();
		outputp0(4,ledstat);
	}
}

展示视频

注:
DAC我一个人不好拿手机拍,因而不在视频中展示
脉冲输出功能没办法直接体现,我用L8代替了,效果还不错,只不过定时器用的是定时器2,优先级很低,就导致看起来断断续续。但是明显可以看出超过频率参数的时候led闪的更连续,没超过时闪的断断续续。
对于存储在EEPROM内的触发次数,我临时创了一个界面来展示,在主程序代码中注释掉了。

G013L8代替MOTOR

G013


G013触发次数展示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值