蓝桥杯单片机第16届4T模拟赛三思路讲解
- 手机
- 2025-09-20 09:27:02

声明:以下代码仅供参考
蓝桥杯单片机第16届4T模拟赛三于3月2日结束,做完题目忘记把题目截下来了,成绩出了再补上,本篇文章只讲思路(思路大体上是没问题的,有些地方可能存在不足,见谅)。 本次模拟赛涉及的知识点都是很常见的,没有像13届、14届的几次模拟赛一样考到串口通信。涉及的模块:基础三件套(Led&Relay,按键、数码管)+ 进阶单件套(pcf8591的AD模块),考的模块虽然很少,数码管显示页面也很好实现,但是也是存在一个难点的,就是后面Led模块的如何正确的让继电器吸合,这个是本题最大的难点。
一、数码管部分 1.页面1页面1要显示的格式是: 最左边的数码管显示字母C,最后两位显示湿度的十位和个位(不足两位十位熄灭)
01234567C30湿度是由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,U≤10.266∗U−16.666,1≤x≤490,U≥4 所以在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
01234567E50这个就特别简单了,页面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。 时间间隔是继电器点亮的间隔,跟数码管没关系,直接显示即可。
01234567E3 二、按键部分按键只用到了按键S4、S5、S8、S9。 按键S4是切换页面,实现也很简单。 按键5是继电器启动标志位,在任何界面按一次标志位取反。 按键8、按键9:参数控制按键 在页面2按下,湿度参数每次加/减5,页面3按下,时间间隔每次加/减1,湿度参数取值范围:30 ~ 90,时间间隔取值范围:1 ~ 10。 当湿度参数达到最大值时,下次按下S8,回到最小值开始加,时间间隔也是如此。 比如:
#mermaid-svg-vGUKv6wfgD18MXca {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-vGUKv6wfgD18MXca .error-icon{fill:#552222;}#mermaid-svg-vGUKv6wfgD18MXca .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-vGUKv6wfgD18MXca .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-vGUKv6wfgD18MXca .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vGUKv6wfgD18MXca .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vGUKv6wfgD18MXca .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vGUKv6wfgD18MXca .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vGUKv6wfgD18MXca .marker{fill:#333333;stroke:#333333;}#mermaid-svg-vGUKv6wfgD18MXca .marker.cross{stroke:#333333;}#mermaid-svg-vGUKv6wfgD18MXca svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vGUKv6wfgD18MXca .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-vGUKv6wfgD18MXca .cluster-label text{fill:#333;}#mermaid-svg-vGUKv6wfgD18MXca .cluster-label span{color:#333;}#mermaid-svg-vGUKv6wfgD18MXca .label text,#mermaid-svg-vGUKv6wfgD18MXca span{fill:#333;color:#333;}#mermaid-svg-vGUKv6wfgD18MXca .node rect,#mermaid-svg-vGUKv6wfgD18MXca .node circle,#mermaid-svg-vGUKv6wfgD18MXca .node ellipse,#mermaid-svg-vGUKv6wfgD18MXca .node polygon,#mermaid-svg-vGUKv6wfgD18MXca .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-vGUKv6wfgD18MXca .node .label{text-align:center;}#mermaid-svg-vGUKv6wfgD18MXca .node.clickable{cursor:pointer;}#mermaid-svg-vGUKv6wfgD18MXca .arrowheadPath{fill:#333333;}#mermaid-svg-vGUKv6wfgD18MXca .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-vGUKv6wfgD18MXca .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-vGUKv6wfgD18MXca .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-vGUKv6wfgD18MXca .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-vGUKv6wfgD18MXca .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-vGUKv6wfgD18MXca .cluster text{fill:#333;}#mermaid-svg-vGUKv6wfgD18MXca .cluster span{color:#333;}#mermaid-svg-vGUKv6wfgD18MXca div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-vGUKv6wfgD18MXca :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 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; 三、继电器部分 #mermaid-svg-ZDm8EnJAdMkNzoyv {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ZDm8EnJAdMkNzoyv .error-icon{fill:#552222;}#mermaid-svg-ZDm8EnJAdMkNzoyv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZDm8EnJAdMkNzoyv .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-ZDm8EnJAdMkNzoyv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZDm8EnJAdMkNzoyv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZDm8EnJAdMkNzoyv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZDm8EnJAdMkNzoyv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZDm8EnJAdMkNzoyv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZDm8EnJAdMkNzoyv .marker.cross{stroke:#333333;}#mermaid-svg-ZDm8EnJAdMkNzoyv svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZDm8EnJAdMkNzoyv .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZDm8EnJAdMkNzoyv .cluster-label text{fill:#333;}#mermaid-svg-ZDm8EnJAdMkNzoyv .cluster-label span{color:#333;}#mermaid-svg-ZDm8EnJAdMkNzoyv .label text,#mermaid-svg-ZDm8EnJAdMkNzoyv span{fill:#333;color:#333;}#mermaid-svg-ZDm8EnJAdMkNzoyv .node rect,#mermaid-svg-ZDm8EnJAdMkNzoyv .node circle,#mermaid-svg-ZDm8EnJAdMkNzoyv .node ellipse,#mermaid-svg-ZDm8EnJAdMkNzoyv .node polygon,#mermaid-svg-ZDm8EnJAdMkNzoyv .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZDm8EnJAdMkNzoyv .node .label{text-align:center;}#mermaid-svg-ZDm8EnJAdMkNzoyv .node.clickable{cursor:pointer;}#mermaid-svg-ZDm8EnJAdMkNzoyv .arrowheadPath{fill:#333333;}#mermaid-svg-ZDm8EnJAdMkNzoyv .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZDm8EnJAdMkNzoyv .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZDm8EnJAdMkNzoyv .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-ZDm8EnJAdMkNzoyv .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-ZDm8EnJAdMkNzoyv .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZDm8EnJAdMkNzoyv .cluster text{fill:#333;}#mermaid-svg-ZDm8EnJAdMkNzoyv .cluster span{color:#333;}#mermaid-svg-ZDm8EnJAdMkNzoyv div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZDm8EnJAdMkNzoyv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 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_light和relay_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_old和humidity_set_old保存当前的humidity和humidity_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 { //... }这样写出的程序显示时是没有明显问题的(如果继电器吸合是按照上面我的理解来说的话),如果你有别的看法或者发现了错误,请在评论区告诉我。
蓝桥杯单片机第16届4T模拟赛三思路讲解由讯客互联手机栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“蓝桥杯单片机第16届4T模拟赛三思路讲解”
下一篇
4-3自定义加载器,并添加功能