当前位置: 首页 > news >正文

蓝桥杯单片机第16届4T模拟赛三思路讲解

声明:以下代码仅供参考

蓝桥杯单片机第16届4T模拟赛三于3月2日结束,做完题目忘记把题目截下来了,成绩出了再补上,本篇文章只讲思路(思路大体上是没问题的,有些地方可能存在不足,见谅)。
本次模拟赛涉及的知识点都是很常见的,没有像13届、14届的几次模拟赛一样考到串口通信。涉及的模块:基础三件套(Led&Relay,按键、数码管)+ 进阶单件套(pcf8591的AD模块),考的模块虽然很少,数码管显示页面也很好实现,但是也是存在一个难点的,就是后面Led模块的如何正确的让继电器吸合,这个是本题最大的难点。

一、数码管部分

1.页面1

页面1要显示的格式是:
最左边的数码管显示字母C,最后两位显示湿度的十位和个位(不足两位十位熄灭)

01234567
C30

湿度是由pcf8591的AD模块读取通道3的电压值转换来的,他们的关系是(从图转换成函数)
h u m i d i t y = { 10 , U ≤ 1 0.266 ∗ U − 16.666 ,    1 ≤ x ≤ 4 90 , U ≥ 4 humidity = \begin{cases} 10,U\le1\\ 0.266*U-16.666,\,\,1\le x \le 4\\ 90,U\ge 4\\ \end{cases} humidity= 10,U10.266U16.666,1x490,U4
所以在AD的处理函数就可以先将通道3的电压读出来后直接进行湿度转换。下面给出的是用rb2_100x接收放大100倍后的电压值,你也可以直接使用float型变量接收未放大的电压值。

void ADProc()
{
   rb2_100x = ADRead() * 100 / 51;
   if(rb2_100x <= 100)
   	humidity = 10;
   else if(rb2_100x >= 400)
   	humidity = 90;
   else
   	humidity = 0.266 * rb2_100x - 16.666;
}

然后把humidity放到数码管显示时,最好是将中间三位显示成电压值(这样可以直观的看到湿度转换是不是正确的),比如这样:

switch(SegMode)
{
	case 0:
		SegBuf[0] = 11;
		SegBuf[1] = 10;
		SegBuf[2] = rb2_100x / 100;
		SegBuf[3] = rb2_100x / 10 % 10;
		SegBuf[4] = rb2_100x % 10;
		SegBuf[5] = 10;
		SegBuf[6] = humidity / 10;
		SegBuf[7] = humidity % 10;
	break;
}

实物显示:
电压为4时,对应湿度90
在这里插入图片描述
电压为1时,对应湿度10
在这里插入图片描述

2.页面2

页面2要显示的格式是:
最左边的数码管显示字母E,最后两位显示湿度参数的十位和个位(不足两位十位熄灭)

湿度参数默认值为50

01234567
E50

这个就特别简单了,页面1的代码直接复制下来就可以了,唯一要改的地方就是页面2的显示要对湿度参数的十位进行判断,为0时熄灭。

case 1:
	SegBuf[0] = 12;
	SegBuf[1] = 10;
	SegBuf[2] = 10;
	SegBuf[3] = 10;
	SegBuf[4] = 10;
	SegBuf[5] = 10;
	SegBuf[6] = (humidity_set / 10) ? (humidity_set / 10) : 10;
	SegBuf[7] = humidity_set % 10;
break;

3. 页面3

页面3要显示的格式是:
最左边的数码管显示字母H,最后两位显示时间间隔的十位和个位(不足两位十位熄灭)

时间间隔默认值为3。
时间间隔是继电器点亮的间隔,跟数码管没关系,直接显示即可。

01234567
E3

二、按键部分

按键只用到了按键S4、S5、S8、S9。
按键S4是切换页面,实现也很简单。
按键5是继电器启动标志位,在任何界面按一次标志位取反。
按键8、按键9:参数控制按键
在页面2按下,湿度参数每次加/减5,页面3按下,时间间隔每次加/减1,湿度参数取值范围:30 ~ 90,时间间隔取值范围:1 ~ 10。
当湿度参数达到最大值时,下次按下S8,回到最小值开始加,时间间隔也是如此。
比如:

S8
S8
S8
S9
S9
S9
S8
80
85
90
30
40
35
90
35
case 8:
	if(SegMode == 1)
	{
		humidity_set += 5;
		if(humidity_set == 95)
			humidity_set = 30;
	}
	else if(SegMode == 2)
	{
		if(++relay_light_time == 11)
			relay_light_time = 1;
	}
break;

三、继电器部分

no
yes
no
yes
继电器工作?
继电器断开
湿度参数>湿度?
继电器吸合,经过时间间隔后断开

这边继电器吸合的判断是继电器工作标志位为1而且湿度参数大于湿度的时候,继电器吸合,经过时间间隔设置的时间后,继电器闭合。

题目出的不是很严谨,因为第一次湿度参数大于湿度的时候,继电器进行吸合-断开操作后,它还可以重复吸合吗?当湿度参数或者湿度或者时间间隔数据变了,它还可以吸合吗?
根据正常人的思维,这边继电器应该是可以重复吸合的(当湿度数据或者湿度参数变了后),也就是说,湿度为30,湿度数据为35,继电器工作的时候,继电器吸合,3秒后断开,此时不能重复吸合,然后将湿度调成33,继电器吸合,3秒后断开。保持湿度不变,湿度数据变成40,此时继电器吸合,3秒后断开。

按照上面分析的继电器吸合逻辑,难点如下:

  • 让继电器吸合很简单,让继电器闭合也很简单,要怎么让继电器吸合后经过时间间隔设定的时间后断开呢?
  • 怎么避免继电器重复吸合的情况下又不影响湿度/湿度参数改变后让继电器吸合呢?
    碰到这种逻辑性很强的题目,采取的做法是从大到小,也就是先写继电器不工作时断开、继电器工作时吸合,然后观察板子的现象是否正确(防止继电器底层代码书写错误)
void LedProc()
{
	/*Relay*/
	if(!relay_work)
		relay_flag = 0;
	else
		relay_flag = 1;
		
	Relay(relay_flag);
}

然后开始写继电器工作时,如果湿度参数大于湿度时,继电器吸合,否则断开。

void LedProc()
{
	/*Relay*/
	if(!relay_work)
		relay_flag = 0;
	else
	{
		if(humidity < humidity_set)
		{
			relay_flag = 1;
		}
		else
			relay_flag = 0;
	}
		
	Relay(relay_flag);
}

然后就可以开始写继电器吸合后经过时间间隔设定的时间后断开了。
定义全局变量unsigned int time_relay_light为时间计时变量,这边对time_relay_light处理防止数据越界,然后当time_relay_light大于等于时间间隔设定的时间时,继电器闭合。(relay_light_time为时间间隔,由于定时器为1秒产生1次中断,所以将time_relay_lightrelay_light_time * 1000进行比较)

void LedProc()
{
	/*Relay*/
	if(!relay_work)
		relay_flag = 0;
	else
	{
		if(humidity < humidity_set)
		{
			relay_flag = 1;
			if(time_relay_light >= (relay_light_time * 1000))
				relay_flag = 0;
		}
		else
			relay_flag = 0;
	}
		
	Relay(relay_flag);
}

void Timer0_Isr(void) interrupt 1
{
	if(relay_work && relay_flag)
	{
		if(++time_relay_light >= 10000)
			time_relay_light = 10000;
	}
}

然后就要开始写防止重复吸合了(湿度、湿度参数、继电器工作模式没有改变的情况下重复吸合)

idata bit relay_has_light;

void LedProc()
{
	/*Relay*/
	if(!relay_work)
		relay_flag = 0;
	else
	{
		//防止重复吸合
		if(!relay_has_light)
		{
			relay_flag = 1;//继电器吸合
			relay_has_light = 1;//继电器重复点亮判断生效
		}


		if(humidity < humidity_set)
		{
			relay_flag = 1;
			if(time_relay_light >= (relay_light_time * 1000))
				relay_flag = 0;
		}
		else
			relay_flag = 0;
	}
		
	Relay(relay_flag);
}

防止重复吸合写完,就要写在哪里让relay_has_light标志位清零了,这个时候,我们可以模仿一下Led的底层代码中定义的temp temp_old,也就是说,第一次湿度<湿度参数吸合继电器的时候,用humidity_oldhumidity_set_old保存当前的humidityhumidity_set,所以判断relay_has_light标志位清零只需要在下次的湿度<湿度参数的时候判断一下(humidity_old != humidity)或者(humidity_set_old != humidity_set)就可以了。

else
{
	if(humidity < humidity_set)
	{
		if((humidity_old != humidity) || (humidity_set_old != humidity_set))
		{
			time_relay_light = 0;//重置计时器
			relay_has_light = 0;//继电器重复点亮判断失效
			humidity_old = humidity;
			humidity_set_old = humidity_set;
		}
		if(!relay_has_light)
		{
			relay_flag = 1;//继电器吸合
			relay_has_light = 1;//继电器重复点亮判断生效
		}
		if(time_relay_light >= (relay_light_time * 1000))
		{
			relay_flag = 0;//达到时间后继电器断开
		}
	}
	else
	{
		relay_flag = 0;
		time_relay_light = 0;
	}
}

然后就要考虑最后一种情况了,当湿度参数和湿度都没有改变,只改变继电器标志位的时候,继电器也是要吸合的。

if(!relay_work)
{
	relay_has_light = 0;
	relay_flag = 0;
	humidity_old = humidity_set_old = 0;//重置保存值
}
else
{
	//...
}

这样写出的程序显示时是没有明显问题的(如果继电器吸合是按照上面我的理解来说的话),如果你有别的看法或者发现了错误,请在评论区告诉我。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dtcms.com/a/45261.html

相关文章:

  • 计算机毕业设计SpringBoot+Vue.js汽车资讯网站(源码+文档+PPT+讲解)
  • Java支持多继承么,为什么?
  • 4-3自定义加载器,并添加功能
  • 本地部署大模型
  • 《动手学习深度学习》的笔记,将会持续更新。
  • vue3:三项目增加404页面
  • Mysql 语法再巩固
  • 接口自动化测试框架(pytest+allure+aiohttp+用例自动生成)
  • 香港大学deep-research开源项目
  • (动态规划 最大(连续)子数组和)leetcode 53
  • Elasticsearch 数据量大时如何优化查询性能?
  • Python正则
  • [M数据结构] lc2353. 设计食物评分系统(数据结构+set 平衡树+懒删除堆)
  • 达梦数据库如何查看当前锁表和如何解决锁表问题
  • 企业access_token,与用户access_token区别,获取方式,如何获取用户信息
  • 释放你的IDE潜能:Code::Blocks 插件创意开发深度指南
  • C++—类与对象(下)
  • C#上位机--三元运算符
  • 【分库分表】基于mysql+shardingSphere的分库分表技术
  • 1-kafka单机环境搭建
  • 2025-2-27-4.10 动态规划(0-1 背包问题)
  • Python 编程题 第五节:落体反弹问题、求指定数列之和、求阶乘的和、年龄急转弯、判断回文数、判断星期几、矩阵主对角线元素之和
  • Rk3568驱动开发_自动创建设备节点_8
  • ListControl双击实现可编辑
  • 更新anaconda安装包后重新配置环境
  • LabVIEW 无法播放 AVI 视频的编解码器解决方案
  • [SAP MM] 标准价格和移动平均价格
  • 小程序性能优化-预加载
  • 知识图谱科研文献推荐系统vue+django+Neo4j的知识图谱
  • AtCoder Beginner Contest AT_abc395_d ABC395D Pigeon Swap 题解