蓝桥杯单片机第7届省赛程序题参考答案

        答案仅供参考,有错误欢迎指正,非常感谢!!!

        文件较多,代码较长,感谢查看!!!

目录

main.h

main.c

Init.h

Init.c

SMG.h

SMG.c

DLKey.h

DLKey.c

DSQ.h

DSQ.c

onewire.h

onewire.c

PWM.h

PWM.c

YanShi.h

 YanShi.c

        首先个人觉得题目有些地方不是很好理解,比如图中的S5按键的用法。个人的理解是每次按下S5,倒计时加1分钟,有4位数码管可以显示剩余时间,说明剩余时间最大可达9999秒,然后忽略S5 的工作过程。同时,PWM的输出通过示波器来展现。

        其次还有个温度数据的获取问题,如果在获取温度数据时,直接获取温度数据,偶尔会出现温度数据错乱问题,即是温度在显示的时候会发生跳动,这个跳动是由于定时器中断打断了温度数据的读取,从而发生的温度数据错乱。如果在获取获取温度数据前,把中断关闭,获取完温度数据后,再开启定时器中断,温度数据就不会发生错乱,但是PWM输出的信号却出现了问题,信号偶尔会发生跳动,不够稳定。

        我这里采取,每20ms进行一次温度的采集,在温度采集前,关闭定时器的中断,采集完温度数据后,再开启定时器中断,进行减少信号的波动。

main.h

#ifndef __MAIN_H_
#define __MAIN_H_

#define uchar unsigned char 
#define uint unsigned int

#include <STC15F2K60S2.H>

#include "Init.h"
#include "SMG.h"
#include "DSQ.h"
#include "YanShi.h"
#include "DLKey.h"
#include "PWM.h"
#include "onewire.h"

void SMG_XianShi();
void LED_XianShi();

#endif

main.c

#include "main.h"

uchar key_num=0;
uchar pwm=0;
uchar pwm_time=0;
uchar GongZuo_MoShi=0;//¹¤×÷ģʽ£¬0£ºË¯Ã߷磻1£º×ÔÈ»·ç£»2£º³£·ç
int ShengYu_ShiJian=0;//Ê£Óàʱ¼ä£¬µ¥Î»£ºs
uchar JieMian=0;//½çÃ棬0£º¹¤×÷ģʽºÍÊ£Ó๤×÷ʱ¼äÏÔʾ£¬1£ºÊÒÎÂÏÔʾ½çÃæ
uint time=0;
char wen_du=0;//ζÈ
uchar WenDu_Time=0;

void main(){
	Init_BZ();
	SMG_Init();
	DLKey_Init();
	DSQ_2_Init();
	PWM_DSQ_1_Init();
	while(1){
		key_num=DLKey_GetKeynum();
		if(key_num==4){
			GongZuo_MoShi++;
			GongZuo_MoShi=GongZuo_MoShi%3;
			switch(GongZuo_MoShi){
				case 0:{
					pwm=20;
					break;
				}
				case 1:{
					pwm=30;
					break;
				}
				case 2:{
					pwm=70;
					break;
				}
			}
		}
		else if(key_num==5){
			ShengYu_ShiJian=ShengYu_ShiJian+60;
			if(ShengYu_ShiJian>9999){
				ShengYu_ShiJian=9999;
			}
			ET1=1;
		}
		else if(key_num==6){
			ShengYu_ShiJian=0;
			ET1=0;
		}
		else if(key_num==7){
			JieMian++;
			JieMian=JieMian%2;
		}
		
		if(WenDu_Time>=20){
			WenDu_Time=0;
			wen_du=(char)DS18B20_GetWenDu();
		}
	}
}

void DSQ_1_ZD() interrupt 3{
	pwm_time++;
	if(pwm_time<pwm){
		P34=1;
	}
	else if(pwm_time>=pwm&&pwm_time<=100){
		P34=0;
	}
	else if(pwm_time>=101){
		P34=0;
		pwm_time=0;
	}
}

void DSQ_2_ZD() interrupt 12{
	WenDu_Time++;
	if(ShengYu_ShiJian>0){
		time++;
		if(time>=1000){
			time=0;
			ShengYu_ShiJian--;
			if(ShengYu_ShiJian<=0){
				ShengYu_ShiJian=0;
				ET1=0;
			}
		}
	}
	
	SMG_XianShi();
	LED_XianShi();
}

void SMG_XianShi(){
	if(JieMian){
		if(wen_du>=10){
			SMG_Show(17,4,17,16,16,wen_du/10,wen_du%10,12);
		}
		else if(wen_du>=0){
			SMG_Show(17,4,17,16,16,16,wen_du,12);
		}
		else if(wen_du<0){
			SMG_Show(17,4,17,16,16,17,-wen_du,12);
		}
	}
	else{
		SMG_Show(17,GongZuo_MoShi+1,17,16,ShengYu_ShiJian/1000,(ShengYu_ShiJian/100)%10,(ShengYu_ShiJian/10)%10,ShengYu_ShiJian%10);
	}
}

void LED_XianShi(){
	uchar L1=0xff;
	uchar L2=0xff;
	uchar L3=0xff;
	if(ShengYu_ShiJian>0){
		switch(GongZuo_MoShi){
			case 0:{
				L1=0xfe;
				break;
			}
			case 1:{
				L2=0xfd;
				break;
			}
			case 2:{
				L3=0xfb;
				break;
			}
		}
		
	}
	P0=L1&L2&L3;
	P2=(P2&0x1f)|0x80;
	P2=(P2&0x1f)|0x00;
}

Init.h

#ifndef __INIT_H_
#define __INIT_H_

#include <STC15F2K60S2.H>

void Init_BZ();

#endif

Init.c

#include "Init.h"

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

SMG.h

#ifndef __SMG_H_
#define __SMG_H_

#include <STC15F2K60S2.H>

void SMG_Init();
void SMG_Show(unsigned char n1,n2,n3,n4,n5,n6,n7,n8);

#endif

SMG.c

#include "SMG.h"

unsigned char code t_display[]={                       //????
//   0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
    0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
//black  -     H    J    K    L    N    o   P    U     t    G    Q    r   M    y
    0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e,
    0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x46};    //0. 1. 2. 3. 4. 5. 6. 7. 8. 9. -1

void SMG_Init(){
	P2=(P2&0x1f)|0xc0;
	P0=0xff;
	P2=(P2&0x1f)|0xe0;
	P0=0xff;
}

void SMG_Show(unsigned char n1,n2,n3,n4,n5,n6,n7,n8){
	static unsigned char i=0;
	i++;
	i=i%8;
	P2=(P2&0x1f)|0xc0;
	switch(i){
		case 1:{
			P0=0x01;
			P2=(P2&0x1f)|0xe0;
			P0=~t_display[n1];
			break;
		}
		case 2:{
			P0=0x02;
			P2=(P2&0x1f)|0xe0;
			P0=~t_display[n2];
			break;
		}
		case 3:{
			P0=0x04;
			P2=(P2&0x1f)|0xe0;
			P0=~t_display[n3];
			break;
		}
		case 4:{
			P0=0x08;
			P2=(P2&0x1f)|0xe0;
			P0=~t_display[n4];
			break;
		}
		case 5:{
			P0=0x10;
			P2=(P2&0x1f)|0xe0;
			P0=~t_display[n5];
			break;
		}
		case 6:{
			P0=0x20;
			P2=(P2&0x1f)|0xe0;
			P0=~t_display[n6];
			break;
		}
		case 7:{
			P0=0x40;
			P2=(P2&0x1f)|0xe0;
			P0=~t_display[n7];
			break;
		}
		case 0:{
			P0=0x80;
			P2=(P2&0x1f)|0xe0;
			P0=~t_display[n8];
			break;
		}
	}
	P2=(P2&0x1f)|0x00;
}

DLKey.h

#ifndef __DLKEY_H_
#define __DLKEY_H_

#include "YanShi.h"

void DLKey_Init();
unsigned char DLKey_GetKeynum();

#endif

DLKey.c

#include "DLKey.h"

void DLKey_Init(){
	P30=1;
	P31=1;
	P32=1;
	P33=1;
}

unsigned char DLKey_GetKeynum(){
	unsigned char key_num=0;
	if(P30==0){
		Delay10ms();
		if(P30==0){
			key_num=7;
		}
		while(P30==0);
	}
	else if(P31==0){
		Delay10ms();
		if(P31==0){
			key_num=6;
		}
		while(P31==0);
	}
	else if(P32==0){
		Delay10ms();
		if(P32==0){
			key_num=5;
		}
		while(P32==0);
	}
	else if(P33==0){
		Delay10ms();
		if(P33==0){
			key_num=4;
		}
		while(P33==0);
	}
	DLKey_Init();
	return key_num;
}

DSQ.h

#ifndef __DSQ_H_
#define __DSQ_H_

#include <STC15F2K60S2.H>

void DSQ_2_Init();

#endif

DSQ.c

#include "DSQ.h"

void DSQ_2_Init(){
	AUXR |= 0x04;		//定时器时钟1T模式
	T2L = 0x20;		//设置定时初值
	T2H = 0xD1;		//设置定时初值
	AUXR |= 0x10;		//定时器2开始计时
	AUXR=AUXR&0xf7;
	IE2=IE2|0x04;
	EA=1;
}

onewire.h

#ifndef __ONEWIRE_H
#define __ONEWIRE_H

#include <STC15F2K60S2.H>

float DS18B20_GetWenDu();

#endif

onewire.c

/*
  程序说明: 单总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台(外部晶振12MHz) STC89C52RC单片机
  日    期: 2011-8-9
*/
#include "onewire.h"

sbit DQ = P1^4;  //单总线接口

//单总线延时函数
void Delay_OneWire(unsigned int t)  //STC89C52RC
{
	unsigned char i;
	while(t--){
		for(i=0;i<12;i++);
	}
}

//通过单总线向DS18B20写一个字节
void Write_DS18B20(unsigned char dat)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		DQ = 0;
		DQ = dat&0x01;
		Delay_OneWire(5);
		DQ = 1;
		dat >>= 1;
	}
	Delay_OneWire(5);
}

//从DS18B20读取一个字节
unsigned char Read_DS18B20(void)
{
	unsigned char i;
	unsigned char dat;
  
	for(i=0;i<8;i++)
	{
		DQ = 0;
		dat >>= 1;
		DQ = 1;
		if(DQ)
		{
			dat |= 0x80;
		}	    
		Delay_OneWire(5);
	}
	return dat;
}

//DS18B20设备初始化
bit init_ds18b20(void)
{
  	bit initflag = 0;
  	
  	DQ = 1;
  	Delay_OneWire(12);
  	DQ = 0;
  	Delay_OneWire(80);
  	DQ = 1;
  	Delay_OneWire(10); 
    initflag = DQ;     
  	Delay_OneWire(5);
  
  	return initflag;
}

float DS18B20_GetWenDu(){
	float wen_du,zs,xs;
	unsigned char di,gao;
	
	init_ds18b20();
	EA=0;
	Write_DS18B20(0xcc);
	Write_DS18B20(0x44);
	EA=1;
	Delay_OneWire(200);
	
	init_ds18b20();
	EA=0;
	Write_DS18B20(0xcc);
	Write_DS18B20(0xbe);
	EA=1;
	
	di=Read_DS18B20();
	gao=Read_DS18B20();
	
	if(gao>=240){
		di=~di;
		gao=~gao;
		if(di==0xff){
			di=0;
			gao++;
		}
		else{
			di++;
		}
		zs=((gao<<4)|(di>>4))*1.0;
		xs=(di&0x0f)*0.0625;
		wen_du=-(zs+xs);
	}
	else{
		zs=((gao<<4)|(di>>4))*1.0;
		xs=(di&0x0f)*0.0625;
		wen_du=(zs+xs);
	}
	return wen_du;
}

PWM.h

#ifndef __PWM_H_
#define __PWM_H_

#include <STC15F2K60S2.H>

void PWM_DSQ_1_Init();

#endif

PWM.c

#include "PWM.h"

void PWM_DSQ_1_Init(){
	AUXR |= 0x40;		//定时器时钟1T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0x88;		//设置定时初值
	TH1 = 0xFF;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	ET1=1;
	EA=1;
}

YanShi.h

#ifndef __YANSHI_H_
#define __YANSHI_H_

#include <STC15F2K60S2.H>
#include "intrins.h"

void Delay10ms();

#endif

 YanShi.c

#include "YanShi.h"

void Delay10ms()		//@12.000MHz
{
	unsigned char i, j;

	i = 117;
	j = 184;
	do
	{
		while (--j);
	} while (--i);
}
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

因心,三人水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值