蓝桥杯单片机14届省赛解析(个人)

2023-11-18

下面记录一下自己这届省赛比赛时的思路,不太会写作文,比较口语化。而且一些看法仅仅是我个人观点,赛后我还没有看过任何讲解或例程,可能会有很多理解不对的地方希望大家能够指出一起交流

cd7f610e490d4cc4b7ae6f5c662b5d43.png

26adc62ddbb549afba701cd2bed35826.png

17288112dcf24e5b86002b8f3da75a2d.png

8194204a4a0d4d4fa0b0c646b77288c4.png

28d7ca910e994cd59945ce452e3fc4c3.png

一:硬件框图

往届省赛基本上都是考两个外设,这次一看硬件框图就知道难度提高了。先由硬件框图分析:

1. NE555需要单独占用一个定时器0,作为计数器来计脉冲;还需要一个定时器来做各种定时工作,比如多久采集一次数据或者数码管消隐,由于要用于数码管消隐,所以将第二个定时器设为1ms即,采集数据如果需要100ms就定义一个变量在该定时器中断里++就可以了。

2. NE555测量脉冲数用到P34引脚,与矩阵键盘中的最右边一列有引脚冲突,所以在扫描矩阵键盘时需要注意不能影响到P34引脚(后面题目中也只用了S4,S5,S8,S9,所以只要不扫描最后一列即可)。

下面对不常见的功能部分进行分析。

二:功能分析

1. PCF8591采集光敏电阻的电压值,且能够检测“亮”和“暗”两种状态:

         采集电压是常见的,就那一小段代码。而亮和暗如何界定,可以自己先把电压值显示在数码管上,遮挡住光敏电阻看显示的值是多少(我测了是三十多或四十多,属于我将电压值低于50设为暗状态),这个可以自己试一试,很简单。

2. 将NE555测得的频率转为环境湿度数据:

        由图二很容易知道是线性关系,y=kx+b,代入两个频率和湿度就能算出来k和b是多少,最好在求出来后再把频率=200代入算一下湿度是否为10,因为求出来的kb并不是整数,舍弃后面一些小数后会有误差。

3. 数码管显示功能:

        听说很多人没完全实现。其实看起来很复杂,实际上可以看作只是一个模式下有一个子模式而已,比如mode_1这变量表示时间界面,回显界面,参数界面,温湿度界面;而mode_2可以作为回显界面下的温度回显,湿度回显和时间回显。写在代码里就是一个嵌套if判断而已。

4. 由“亮”变“暗”触发采集功能:

        这个功能好像是在12届国赛里出现过类似的,其实就是一个下降沿触发(注意是单次触发),比赛时还是紧张了,写的逻辑不太清晰,可以按照下面这段代码实现(这是我之前练习12届国赛写的,感觉比这次省赛写的好....)后悔考前没回顾一下自己练习的题了hhhf51bf4611a76470bad388806d1a9600e.png

 5.  采集触发后切换到温湿度显示,3s后自动切换回原来的状态:

        在切换到温度显示之前需要对数码管显示模式进行记录,然后计时到3s后再切换回来  

89ea8ba8ae484cb385246efecd2f0665.png

6. 还有一个问题,采集湿度,即测量频率需要1s时间,所以可能采集触发开始时测量时间从0开始,那么触发发生1s后数据才得到更新,所以我对采集湿度和温度分别设了一个标志位,就不会在只有一个采集完时就判断为采集完成了。(而我这份比赛时写的代码中有个缺点就是为了方便,标志位设的太多了,自己看着都有点晕)。

7. LED功能每个灯不要互相影响,对P0口赋值时注意一点即可。

三:对自己这次比赛的小总结:

1. 客观题没预料到考这么难,没复习过模电数电,基本上都是靠蒙,错了很多个。

2. 个人感觉程序设计题难度其实是不如12届国赛的,我另一篇博客中也记录了一下12国赛我用三个半小时做完,自己感觉是无bug的。但是这个省赛五个小时有四个半小时在写程序,我还是觉得写的代码逻辑比较乱,而且自己暂时发现有两个bug。

趁刚考完还没忘记题目,简单写下博客记录一下。

四. 我的代码 (bug没有修改,考完也不想看了,仅作记录), 下面只给出.c文件,我懒,没有做模块化:

main.c 部分代码,其它部分不小心删掉了,没有备份。。。

#include <STC15F2K60S2.H>
#include "iic.h"
#include "onewire.h"
#include "ds1302.h"
#include <intrins.h>

//BCD转十进制
#define BCDToInt(bcd)  (bcd/16*10)+(bcd%16);

//LED
typedef struct
{
	unsigned char b1:1;
	unsigned char b2:1;
	unsigned char b3:1;
	unsigned char b4:1;
	unsigned char b5:1;
	unsigned char b6:1;
	unsigned char b7:1;
	unsigned char b8:1;
}Bit;

typedef union
{
	unsigned char Hex;
	Bit B;
}HexToBit;

HexToBit led_control;




bit flag_3s=0;
code unsigned char Seg_Table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88};
unsigned char smg[8];

//时间 秒 分 时
unsigned char time[]={0x05,0x03,0x13};
unsigned char sec,min,hour;

//HC573操作 io口
void Device_Process(unsigned char p2dat,unsigned char p0dat)
{
	P0 = p0dat;
	P2 = (P2&0x1f)|p2dat;
	P2 = P2&0x1f;
}

//----------定时器-------------
//定时器2
void Timer2Init(void)		//1毫秒@12.000MHz
{
	AUXR |= 0x04;		//定时器时钟1T模式
	T2L = 0x20;		//设置定时初值
	T2H = 0xD1;		//设置定时初值
	AUXR |= 0x10;		//定时器2开始计时
	
	EA=1;
	IE2 |= 0x04;
}

//计数器0 NE555
void Timer0Init(void)		//65535微秒@12.000MHz
{
	TMOD |= 0x05;		//设置定时器模式
	TL0 = 0x00;		//设置定时初值
	TH0 = 0x00;		//设置定时初值
	TR0 = 1;		//定时器0开始计时
}

//---------触发(光敏电阻)-----------
unsigned char rd1;
unsigned char cnt_rd1;
bit flag_rd1=0;  //亮是0 暗是1触发 下降沿
bit flag_getsd=0;
bit flag_gettp=0;
unsigned char pre_hour,pre_min; //上次触发时间
unsigned char cnt_chufa;
unsigned int cnt_3s; //三秒显示
void vRead_rd1()
{
	if(cnt_rd1>=10)
	{
		cnt_rd1=0;
		rd1=Read_rd1();
		if((rd1<50)&&(flag_rd1==0))//flag置1后下次这个if一定不满足,所以单次触发
		{
			flag_rd1=1; //暗
			flag_getsd=1;
			flag_gettp=1;
			cnt_chufa++;
			pre_hour =hour;
			pre_min = min;
			flag_3s=1;
		}		
		if(rd1>100) flag_rd1=0;
	}
}


//-----------参数设置----------------
unsigned char temp_set=25; 


//---------采集时间---------
//1.时间采集

unsigned char cnt_time;
void vRead_time()
{
	if(cnt_time>=100)
	{
		cnt_time=0;
		sec = BCDToInt(Read_Ds1302_Byte(0x81));
		min = BCDToInt(Read_Ds1302_Byte(0x83));
		hour = BCDToInt(Read_Ds1302_Byte(0x85));
	}
}

//2.温度采集
unsigned char temp;
unsigned int temp_mean=0; //平均温度
unsigned char max_temp=0; //最大温度
unsigned char cnt_temp; 
unsigned char last_tp;//上一次
unsigned char led_6=0;
unsigned char ca;
bit flag_tp=0; //温度是否有效
bit flash_led=0;//led闪烁
void vRead_temp()
{
	if(cnt_temp>=100)
	{
		cnt_temp=0;
		last_tp=ca;
		ca=Read_tempture();
		if(flag_gettp==1)
		{	
			if(cnt_chufa>=1)
			{
				
			}			
			temp = ca;
			if(temp>last_tp) led_6++;
			if(temp>temp_set)//报警
			{
				flash_led=1;
			}
			else if(temp<temp_set)
			{
				led_control.B.b4=1;
				flash_led=0;
			}
			if((temp>0)&&(temp<99)) //有效
			{
				flag_tp=1;
			}
			else flag_tp=0;
			

			if(temp>max_temp) max_temp=temp;//最大温度记录更新	
				
			temp_mean = (temp*10+temp_mean*(cnt_chufa-1))/cnt_chufa;
			
			flag_gettp=0;
		}
	}
}

//3.湿度采集 NE555频率
unsigned int freq;
unsigned int cnt_freq; //计时一秒
unsigned char ShiDu; //湿度
unsigned char max_sd=0; //最大值湿度
unsigned int mean_sd=0; //均值湿度
unsigned int ShiDu_mean; //湿度平均值
unsigned char last_sd;
bit flag_sd=1; //湿度有效标志位
bit flag_led5=0;
void vNE555_Process()
{
	if(cnt_freq>=1000)
	{
		cnt_freq=0;
		if(flag_getsd==1)
		{
			if(cnt_chufa>=1)
			{
				last_sd=freq;
			}		
			freq = (TH0<<8)|TL0;
			if(freq>last_sd) led_6++;
			if((freq>200) && (freq<2000))//有效范围内
			{
				ShiDu = 0.044*freq+1.2;
				flag_sd=1;
				flag_led5=0;
				if(ShiDu>max_sd) max_sd=ShiDu;
				mean_sd = ((mean_sd*(cnt_chufa-1)+ShiDu*10))/cnt_chufa; //均值有问题
			}
			else
			{
				flag_led5=1;
				flag_sd=0; //字符A
			}	
			flag_getsd=0;				
		}		
		TH0=0;TL0=0;			
	}
}


IIC.C

/*	#   I2C代码片段说明
	1. 	本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
	2. 	参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
		中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include <reg52.h>
#include <intrins.h>

#define DELAY_TIME	5

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


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;
}

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

//采集光敏电阻
unsigned char Read_rd1()
{
	unsigned char dat;
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	I2CSendByte(0x01);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0x91);
	I2CWaitAck();
	dat = I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();
	return dat;
}



onewire.c

/*	# 	单总线代码片段说明
	1. 	本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
	2. 	参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
		中对单片机时钟频率的要求,进行代码调试和修改。
*/
//
#include <reg52.h>

sbit DQ=P1^4;


void Delay_OneWire(unsigned int t)  
{
	unsigned char 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;
}

//
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 Read_tempture()
{
	float temp;
	unsigned char LSB, MSB;
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0x44);
	
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0xBE);
	
	LSB = Read_DS18B20();
	MSB = Read_DS18B20();
	
	temp = ((MSB<<8)|LSB)*0.0625;
	return temp;
}



ds1302.c

/*	# 	DS1302代码片段说明
	1. 	本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
	2. 	参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
		中对单片机时钟频率的要求,进行代码调试和修改。
*/								

//
#include <reg52.h>
#include <intrins.h>

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);	
 	Write_Ds1302(dat);		
 	RST=0; 
}

//
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 Write_time(unsigned char sec,unsigned char min, unsigned char hour)
{
	Write_Ds1302_Byte(0x8e,0x00); //关闭写保护
	Write_Ds1302_Byte(0x80,sec);
	Write_Ds1302_Byte(0x82,min);
	Write_Ds1302_Byte(0x84,hour);
	Write_Ds1302_Byte(0x8e,0x80);//打开写保护
}



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

蓝桥杯单片机14届省赛解析(个人) 的相关文章

  • 实际工作中的高级技术(训练加速、推理加速、深度学习自适应、对抗神经网络)

    目录 一 训练加速 1 基于数据的并行 Model Average 模型平均 SSGD 同步随机梯度下降
  • 大学生选课抢课如何提高选中概率

    作者位于哈尔滨某高校 选课总是激动人心的一件大事 但是明明与同学一起进的系统 他就能顺利选课 而我却被强退出来 无数辛酸让我知道了一些道理 写下这篇文章给学弟学妹们作为参考 原理 问 为什么大多数学校教务系统选课时都会卡 答 学校教务系统平
  • 热敏电阻测温

    热敏电阻器主要分为 PTC 和 NTC 正温度系数热敏电阻器 PTC 在温度越高时电阻值越大 负温度系数热敏电阻器 NTC 在温度越高时电阻值越低 它们同属于半导体器件 测温的热敏电阻一般为NTC 其主要参数有以下几个 标称阻值 标称阻值是
  • 期货有哪些(正规期货公司排名)

    期货有哪些 期货暂时重要分为两大版块 辨别是商品期货和金融期货 与此同声这两大版块又不妨辨别细化出各别的品种 商品期货又可细分为非金属商品 动力商品 农产物等 金融期货重要指保守的金融商品或东西 如一手一足 内债 税率 汇率等 商品期货农产
  • 58同城面经

    文章目录 58一面 58二面 58同城通过了技术面试 但迟迟没有hr面 可能表现的不是很好 58一面 自我介绍 数据结构大概有哪些分类 关于项目 为什么会考虑做商城项目 商城首页的优化 操作系统为什么会有线程这个操作吗 Java创建线程的方

随机推荐

  • Golang基础 流程控制 循环控制

    循环控制 01 基础循环 for 02 键值循环 for range 参考资料 循环控制通常用于程序中需要重复执行的逻辑模块 循环结构通常由循环变量 循环终止条件和循环体三个部分构成 01 基础循环 for Golang 中所有的循环控制都
  • PCL 最小点数约束的改进半径滤波(C++详细过程版)

    目录 一 概述 1 不足 2 改进 二 代码实现 三 结果展示 一 概述 1 不足 传统半径滤波算法在点云数据量巨大的情况下 算法效率会大幅度降低 而对于稠密点云数据 一个影响效率的重要因素就是搜索半径的大小 当搜索半径较大时 需要计算邻域
  • @vue/cli 创建项目报Cannot find module ‘inquirer‘错

    解决 这可能是因为cli版本问题 1 第一步 2 第二步 npm uninstall g vue cli 3 第三步 npm install g vue cli
  • 由PyRetri浅谈基于深度学习的图像检索

    前言 最近发现face 开源了一个图像检索和行人重识别的基于深度学习的软件包 最近一段时间也一直在接触图像检索相关的东西 故借此机会 对里面涉及的一些常用的方法模块进行一个简单的介绍总结 便于日后回顾 PyRetri是什么 PyRetri是
  • 如何查看linux服务器字符集,Linux字符集查看与设置

    查看字符集 Linux 中字符集在系统中的体现是一个环境变量 以 CentOS 6 5 为例 查看当前终端使用的字符集的方式有 1 root jerry echo LANG zh CN GB18030 2 root jerry env gr
  • 对 React Hook的闭包陷阱的理解,有哪些解决方案?

    hooks中 奇怪 其实符合逻辑 的 闭包陷阱 的场景 同时 在许多 react hooks 的文章里 也能看到 useRef 的身影 那么为什么使用 useRef 又能摆脱 这个 闭包陷阱 搞清楚这些问题 将能较大的提升对 react h
  • vue 全局组件注册_如何注册vue3全局组件

    vue 全局组件注册 With the new versions of Vue3 out now it s useful to start learning how the new updates will change the way w
  • unity playerprefs android,Unity持久化存储之PlayerPrefs的使用

    一 PlayerPrefs类支持3中数据类型的保存和读取 浮点型 整形 和字符串型 分别对应的函数为 php SetInt 保存整型数据 GetInt 读取整形数据 SetFloat 保存浮点型数据 GetFlost 读取浮点型数据 Set
  • pygame之五子棋的实现

    先上代码 调用pygame库 import pygame import sys 调用常用关键字常量 from pygame locals import QUIT KEYDOWN import numpy as np 初始化pygame py
  • laravel-vue后端返回数据的字符串中(<br/> \n)换行无效

    laravel 做后端 vue做前端 后端返回数据的字符串中含有 br 或 n r n 等换行符 在前端页面无法正常渲染出换行效果 尝试用str replace方法无效 最终找到解决办法 解决办法 给包含换行符的字符串元素增加css whi
  • 【STM32学习】——串口通信协议&STM32-USART外设&数据帧/输入数据策略/波特率发生器&串口发送/接受实操

    文章目录 前言 一 串口通信 1 通信接口 2 串口通信 1 串口简介 2 串口硬件电路 3 串口软件部分 二 STM32的USART外设 1 USART简介 2 图示详解 三 细节问题 1 数据帧 2 输入数据策略 1 起始位侦测 2 数
  • iOS开发,tableView中cell的重用详解

    注意 原创版权 转载必须标明出处作者 翻版必究 iOS中tableView是一个大的模块组件 它的重要性每个iOSCoder都是了解的 但是tableView中却有个重大的坑 就是cell的重用 每个刚接触iOS开发的人都深受其海 那么经过
  • AD18出现Unknown Pin报错解决

    问题描述 检查错误 检查原理图对应元件的封装是否存在 检查原理图与封装PCB引脚数量是否对应 检查原理图与封装的管脚是否统一 找到原因 原理图的管脚命名与PCB封装管脚命名不一致 问题解决 修改原理图管脚名称 修改PCB Library的管
  • luajit struct

    This page is intended to give you an overview of the features of the FFI library by presenting a few use cases and guide
  • 使用Stable Diffusion图像修复来生成自己的目标检测数据集

    点击上方 AI公园 关注公众号 选择加 星标 或 置顶 作者 R dig par Gabriel Guerin 编译 ronghuaiyang 导读 有些情况下 收集各种场景下的数据很困难 本文给出了一种方法 深度学习模型需要大量的数据才能
  • MOS管做二极管使用

    注 个人学习记录 目录 原理分析 电路仿真 NMOS电路连接方法 NMOS仿真I V特性曲线 PMOS电路连接方法 PMOS二极管接法的I V特性曲线 原理分析 如下图所示 左边为NMOS 右边为PMOS 由MOS管的结构可以看出 其衬底B
  • 图解laravel的生命周期

    先来张图大致理解下laravel的生命周期 下面对应相应的代码 解释上图 文件路径 laravel public index php laravel的启动时间 define LARAVEL START microtime true 加载项目
  • 2024王道408数据结构 P92 T3

    2024王道408数据结构 P92 T3 思考过程 这题比较复杂做的我好 累 首先我们还是先看懂题目 让我们用一个栈来实现递归函数的非递归计算 我们先剖析一下这个表达式 式子展开变成图上这样 那既然让我们用非递归来计算 那我们顺理成章就想到
  • [Qt]控件

    文章摘于 爱编程的大丙 文章目录 1 按钮类型控件 1 1 按钮基类 QAbstractButton 1 1 1 标题和图标 1 1 2 按钮的 Check 属性 1 1 3 信号 1 1 4 槽函数 1 2 QPushButton 1 2
  • 蓝桥杯单片机14届省赛解析(个人)

    下面记录一下自己这届省赛比赛时的思路 不太会写作文 比较口语化 而且一些看法仅仅是我个人观点 赛后我还没有看过任何讲解或例程 可能会有很多理解不对的地方希望大家能够指出一起交流 一 硬件框图 往届省赛基本上都是考两个外设 这次一看硬件框图就