(省一)第十三届蓝桥杯电子类单片机设计与开发程序题个人解答

第十三届蓝桥杯电子类单片机设计与开发程序题个人解答
题目资源
链接:https://pan.baidu.com/s/1DwLiSF4KgkobTsNhdIl4Ew
提取码:wk7v

个人完整参赛代码:
个人水平较低,如发现问题请予以告知,谢谢!

主函数
main.c

#include"stc15f2k60s2.h"
#include"ds1302.h"
#include"onewire.h"
#define uchar unsigned char
#define uint unsigned int
	
//数码管相关
uchar code dis_code[13]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xc1,0xbf,0xff};//0~9 u - 0xff
uchar dis_com=0;//数码管位选
uchar dis_buf[8]={10,1,12,12,12,12,12,12};//数码管缓冲区
uchar dis_mode=0;//数码管显示模式 0-温度 1-时间 2-参数
//按键相关
bit key_flag=0;//按键扫描标志
uchar key_state=0;//按键状态标志
uchar key_cnt=0;//按键每10ms扫描一次
//温度相关
bit tem_flag=0;//温度扫描标志
bit tem_state=0;//温度状态
uchar tem_para=23;//温度参数
uint tem_cnt=0;//设置11位工作方式,最大转换时间为375ms
float tem_value=0;//读取的温度
//时间相关
bit ds_int=0;//当前时间是否为整点
bit ds_flag=0;//时间读取 标志
bit ds_mode=0;//显示模式,0-时 分   1-分 秒
uint ds_cnt=0;//每100ms刷新一次时间
uchar* ds_value;//指向读取的时间 
//继电器相关 (RELAY_SPDT)
bit re_mode=0;//工作模式 0-温度控制   1-时间控制
bit re_flag=0;//继电器时间控制模式下的工作标志
uchar re_cnt0=0;//继电器在整点吸合5s   每1毫秒re_cnt0加1 加到250则re_cnt1加1
uchar re_cnt1=0;//re_cnt1加到20则说明继电器已吸合5s,该关闭了
//LED相关
bit L_flag=0;//LED工作标志
uchar L_cnt=0;//LED每50ms转换一次
bit L1_flag=0;//L1启动标志
uchar L1_cnt0=0;//L1在整点时亮5s  这个参数用来计时,每250ms L1_cnt1加1
uchar L1_cnt1=0;//加到20则说明过了5s
bit L3_flag=0;//L3工作标志
bit L3_state=0;//L3当前亮灭状态
uchar L3_cnt=0;//继电器开启状态下,L3以0.1s为间隔闪烁

void init();//初始化函数
void cls_buzz();//关闭蜂鸣器函数
void display();//数码管动态显示函数
void scan_key();//按键扫描函数
void update();//数据更新函数
void dis_change();//数码管显示改变函数
void led();//LED函数
void re();//继电器函数

void timer0() interrupt 1{//中断 定时器0 1ms
	TL0=0x18;
	TH0=0xfc;
	if(key_flag==0&&++key_cnt>=10){
		key_flag=1;
		key_cnt=0;
	}
	if(tem_flag==1&&++tem_cnt>=375){
		tem_flag=0;
		tem_cnt=0;
		tem_state=1;
	}
	if(ds_flag==0&&++ds_cnt>=100){
		ds_flag=1;
		ds_cnt=0;
	}
	if(L1_flag==1&&++L1_cnt0>=250){
		L1_cnt0=0;
		L1_cnt1++;
	}
	if(L_flag==0&&++L_cnt>=50){
		L_flag=1;
		L_cnt=0;
	}
	if(L3_flag==1&&++L3_cnt>=100){
		L3_state=~L3_state;
		L3_cnt=0;
	}	
	if(re_flag==1&&++re_cnt0>=250){
		re_cnt0=0;
		re_cnt1++;
	}
	display();
}
void main(){//主函数
	init();//初始化
	while(1){//主循环
		update();//不断更新数据
	}
}
void update(){
	uint num;
	if(key_flag==1){//按键
		scan_key();
		key_flag=0;
	}
	if(tem_flag==0&&tem_state==0){//温度
		tem_start_convert();
		tem_flag=1;
	}
	else if(tem_state==1){//温度
		tem_value=rd_tem();
		tem_state=0;
		dis_change();
		num=tem_value*10;
	}
	if(ds_flag==1){//时间
		ds_value=read_ds1302();
		if(( ds_value[2]+ds_value[3]+ds_value[4]+ds_value[5] )==0){
			ds_int=1;//整点
		}
		else{
			ds_int=0;//非整点
		}
		ds_flag=0;
		dis_change();
	}	
	if(L_flag==1){
		re();//将继电器函数放在这里是为了减少代码量
		led();
		L_flag=0;
	}
	return;
}
void dis_change(){
	bit sign=0;//符号位
	uchar num;
	uint t_uint;
	for(num=1;num<8;num++){//数码管清零
		dis_buf[num]=12;
	}
	if(dis_mode==0){//温度显示
		dis_buf[1]=1;
		if(tem_value>=0){//取1小数
			t_uint=tem_value*10;
		}
		else{
			sign=1;
			t_uint=tem_value*(-10);
		}
		if(t_uint>=100){//题设数码管2.3.4熄灭,所以不考虑温度小于等于负10度的情况(考虑了小于零)
			dis_buf[5]=t_uint/100;
			dis_buf[6]=t_uint/10%10;
		}
		else{
			dis_buf[6]=t_uint/10;
			if(sign==1){dis_buf[5]=11;}
		}
		dis_buf[7]=t_uint%10;		
	}
	else if(dis_mode==1){//时间显示
		dis_buf[1]=2;
		if(ds_mode==0){
			dis_buf[3]=ds_value[0];
			dis_buf[4]=ds_value[1];
			dis_buf[5]=11;
			dis_buf[6]=ds_value[2];
			dis_buf[7]=ds_value[3];
		}
		else if(ds_mode==1){
			dis_buf[3]=ds_value[2];
			dis_buf[4]=ds_value[3];
			dis_buf[5]=11;
			dis_buf[6]=ds_value[4];
			dis_buf[7]=ds_value[5];
		}	
	}
	else if(dis_mode==2){//参数显示
		dis_buf[1]=3;
		tem_para>=10?(dis_buf[6]=tem_para/10):(dis_buf[6]=12);
		dis_buf[7]=tem_para%10;
	}
}
void init(){
	cls_buzz();
	set_resolution(0x5f);
	init_ds1302();
	TMOD=0x01;
	TL0=0x18;
	TH0=0xfc;
	ET0=1;
	EA=1;
	TR0=1;
}
void cls_buzz(){
	P0=0x00;
	P2=(P2&0x1f)|0xa0;
	P2&=0x1f;
}
void display(){
	uchar dis_out;
	P0=0xff;
	P2=(P2&0x1f)|0xe0;
	P2&=0x1f;	
	P0=1<<dis_com;
	P2=(P2&0x1f)|0xc0;
	P2&=0x1f;	
	dis_out=dis_code[dis_buf[dis_com]];
	if(dis_mode==0&&dis_com==6&&dis_buf[6]!=12){
		dis_out&=0x7f;
	}
	P0=dis_out;
	P2=(P2&0x1f)|0xe0;
	P2&=0x1f;
	P0=0x00;
	if(++dis_com==8){dis_com=0;}
}
void scan_key(){
	uchar key=0,row=0,col=0;
	switch(key_state){
		case 0:{
			P3=0x0f;
			P42=0;P44=0;
			if(P3!=0x0f){
				key_state=1;
			}
		}
		break;
		case 1:{//按键持续按下
			P3=0x0f;
			P42=0;P44=0;
			key=P3&0x0f;
			if(key==0x0f){
				key_state=0;
				return;
			}
			if(key==0x0b){row=2;}
			else if(key==0x07){row=3;}
			else{//按下的按键在第一二排
				key_state=2;
				return;
			}
			P3=0xf0;
			P42=1;P44=1;
			if(P34==0){col=2;}
			else if(P35==0){col=3;}
			else {//按下的按键在第一二列
				key_state=2;
				return;
			}
			key=row*4+col;
			if(key==10){//S17 减少参数值和输出秒
				if(dis_mode==1){//数字显示界面按下
					ds_mode=1;//切换为分秒显示
				}
				else if(dis_mode==2){//参数界面
					if(tem_para>10){
						tem_para--;
						dis_change();
					}
				}
			}
			else if(key==11){//S13 切换控制模式
				re_mode=~re_mode;
				if(re_mode==1&&ds_int==0){//如果当前继电器为闭合状态且切换到时钟控制模式应关闭则利用re()函数里面的判断,赋re_cnt1=20关闭继电器
					re_cnt1=20;
				}
			}
			else if(key==14){//S16 增加参数值
				if(dis_mode==2){
					if(tem_para<99){
						tem_para++;
						dis_change();
					}
				}
			}
			else if(key==15){//S12 切换显示模式
				if(dis_mode==0){
					dis_mode=1;
				}
				else if(dis_mode==1){
					dis_mode=2;
					
				}
				else if(dis_mode==2){
					dis_mode=0;
				}
				dis_change();
			}
			key_state=2;		
		}
		break;
		case 2:{
			P3=0x0f;
			P42=0;P44=0;
			if(P3==0x0f){
				ds_mode=0;
				key_state=0;
			}
		}
		break;
	}
}
void led(){
	static uchar led_out=0xff;
	if(ds_int==1){//分秒位均为0说明是整点
		L1_flag=1;
		led_out&=0xfe;//开启L1
	}
	if(L1_cnt1>=20){
		L1_flag=0;
		L1_cnt1=0;
		led_out|=0x01;//关闭L1
	}
	if(re_mode==0){
		led_out&=0xfd;//开启L2
	}
	else{
		led_out|=0x02;//关闭L2
	}
	if(L3_state==1){
		led_out&=0xfb;//开启L3
	}
	else{
		led_out|=0x04;//关闭L3
	}
	P0=led_out;
	P2=(P2&0x1f)|0x80;
	P2&=0x1f;
}
void re(){
	static uchar re_out=0x00;
	if(re_mode==0){//温度控制模式
		if(tem_value-tem_para>0){
			re_out=0x10;
			L3_flag=1;
		}
		else{
			re_out=0x00;
			L3_flag=0;
			L3_state=0;
		} 
	}
	else if(re_mode==1){//时间控制模式
		if(ds_int==1){
			re_out=0x10;
			re_flag=1;
			L3_flag=1;
		}
		else{
			if(re_cnt1>=20){
				re_out=0x00;
				re_cnt1=0;
				L3_flag=0;
				L3_state=0;
			}
		}
	}	
	P0=re_out;
	P2=(P2&0x1f)|0xa0;
	P2&=0x1f;
}

onewire.h

#ifndef __ONEWIRE_H
#define __ONEWIRE_H

#include "stc15f2k60s2.h"
#define uchar unsigned char

sbit DQ = P1^4;  

float rd_tem(void);  
void set_resolution(uchar res);
void tem_start_convert();

#endif

onewire.c

#include "onewire.h"

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

//单总线写操作
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);
}

//单总线读操作
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;
}
void set_resolution(uchar res){//0x7f 12 0x5f 11 0x3f 10 0x1f 9这里要求温度刷新时间小于等于1秒钟,那就设置为11位工作方式,最大转换时间为375ms好了
	init_ds18b20();
	write_ds18b20(0xcc);
	write_ds18b20(0x4e);
	write_ds18b20(0x7f);
	write_ds18b20(0x00);
	write_ds18b20(res);
	init_ds18b20();
	write_ds18b20(0xcc);
	write_ds18b20(0x48);
}
void tem_start_convert(){
	init_ds18b20();
	write_ds18b20(0xcc);
	write_ds18b20(0x44);
}
float rd_tem(){
	uchar low,high;
	float out;
	init_ds18b20();
	write_ds18b20(0xcc);
	write_ds18b20(0xbe);
	low=read_ds18b20();
	high=read_ds18b20();
	if(high>>4){//负数
		out=low+high*256;
		out=(4096-(out/16))*(-1);
	}
	else {
		out=low+high*256;
		out/=16;
	}
	return out;
}

ds1302.h

#ifndef __DS1302_H
#define __DS1302_H

#include <stc15f2k60s2.h>
#include <intrins.h>
#define uchar unsigned char 

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

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 init_ds1302();
uchar* read_ds1302();

#endif

ds1302.c

#include "ds1302.h"  									

//写字节
void write_ds1302(unsigned  char temp) 
{
	unsigned char i;
	for (i=0;i<8;i++)     	
	{ 
		SCK = 0;
		SDA = temp&0x01;
		temp>>=1; 
		SCK=1;
	}
}   

//向DS1302寄存器写入数据
void write_ds1302_byte( unsigned char address,unsigned char dat )     
{
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1; 	_nop_();  
 	write_ds1302(address);	
 	write_ds1302(dat);		
 	RST=0; 
}

//从DS1302寄存器读出数据
unsigned char read_ds1302_byte ( unsigned char address )
{
 	unsigned char i,temp=0x00;
 	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_();
	return (temp);			
}

void init_ds1302(){
	write_ds1302_byte(0x8e,0x00);//关闭写入保护
	write_ds1302_byte(0x80,0x50);//秒
	write_ds1302_byte(0x82,0x59);//分
	write_ds1302_byte(0x84,0x22);//时
	write_ds1302_byte(0x8e,0x80);//开启写入保护
}
uchar* read_ds1302(){
	static uchar time[6];
	uchar t_time[3];
	t_time[0]=read_ds1302_byte(0x81);
	t_time[1]=read_ds1302_byte(0x83);
	t_time[2]=read_ds1302_byte(0x85);
	time[0]=t_time[2]>>4;
	time[1]=t_time[2]&0x0f;
	time[2]=t_time[1]>>4;
	time[3]=t_time[1]&0x0f;
	time[4]=t_time[0]>>4;
	time[5]=t_time[0]&0x0f;
	return time;
}

个人水平较低,如发现问题请予以告知,谢谢!


版权声明:本文为qq_39384136原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。