第十一届 蓝桥杯 嵌入式 省赛

一、分析 

本届的风格又变了一番,但是难度也降低了些。

又是考察了 PWM 和 ADC。

第八、九届也考察了 PWM。建议先复习这两届,再回来模拟。

LCD的显示也提了额外的要求。

1. 功能概述

  • 电位器 R37 输出的模拟电压信号
  • PA6输出频率固定,占空比可调节
  • PA7输出频率固定,占空比可调节
  • 完成 B1、B2、B3、B4 按键动作
  • 完成 LCD 显示数据和参数

2. 性能要求

  • 数据显示界面下电压值更新时间:<= 0.1 秒
  • PA6、PA7输出信号占空比跟随相应时间:<=1秒
  • 按键相应时间:<=0.1 秒
  • 输出频率精度:<=5%
  • 输出占空比精度:<=5%

本届把性能要求单独列出来,好看多了。

3. 运行模式

这部分是关键,和往届考察的PWM不同

1)自动模式:PA6 和 PA7 输出信号占空比相同,

当 R37_Volt = 0,PA6 和 PA7 持续输出低电平。

当 R37_Volt = 3.3,PA6 和 PA7 持续输出高电平。

2)手动模式:PA6、PA7 输出信号占空比通过按键控制,与 R37_Volt 无关

这部分的伪代码,先把下面的先搞定,再来写这里的。

伪代码


PWM_state_manu = 0;
PWM_state_auto = 0;
void Running_mode(){if(D_state == Data_Disp):if(mode == AUTO){if(Key_Down == 3){if(PWM_state_auto == 0){// 80M/(80*10K)=100TIM_AUTORELOAD(&htim3, 9999);// 80M/(80*5K) =200TIM_AUTORELOAD(&htim17, 4999);TIM_COMPARE(&htim3, Channel_1, (unsigned int)(10000*((R37_Volt)/3.3)));TIM_COMPARE(&htim17, Channel_1, (unsigned int)(5000*((R37_Volt)/3.3)));PWM_state_auto = 1;}else if(PWM_state_auto == 1){// 80M/(80*10K)=100TIM_AUTORELOAD(&htim17, 9999);// 80M/(80*5K) =200TIM_AUTORELOAD(&htim3, 4999);TIM_COMPARE(&htim17, Channel_1, (unsigned int)(10000*((R37_Volt)/3.3)));TIM_COMPARE(&htim3, Channel_1, (unsigned int)(5000*((R37_Volt)/3.3)));PWM_state_auto = 0;}}}else if(mode == MANU){//切换PA6和PA7的频率if(Key_Down == 3){if (PWM_state_manu == 0){// 80M/(80*10K)=100TIM_AUTORELOAD(&htim3, 9999);// 80M/(80*5K) =200TIM_AUTORELOAD(&htim17, 4999);//频率改变后,占空比也要跟随,毕竟跟周期有关TIM_COMPARE(&htim3, Channel_1, (100*PA6_Duty));TIM_COMPARE(&htim17, Channel_1, (50*PA6_Duty));PWM_state_manu = 1;}else if(PWM_state_manu == 1){// 80M/(80*10K)=100TIM_AUTORELOAD(&htim17, 9999);// 80M/(80*5K) =200TIM_AUTORELOAD(&htim3, 4999);//频率改变后,占空比也要跟随,毕竟跟周期有关TIM_COMPARE(&htim17, Channel_1, (100*PA6_Duty));TIM_COMPARE(&htim3, Channel_1, (50*PA6_Duty));PWM_state_manu = 0;}}}}

4. LCD 显示界面

本届直接把像素位置给标出来了,严格要求显示的细节。

1)数据显示界面

  • Data
  • 电压
  • 模式:自动或手动

2)参数显示界面

  • Para
  • PA6占空比
  • PA7占空比

3)显示颜色

  • 背景色:黑
  • 前景色:白

伪代码

typedef enum{Data_Disp,Para_Disp
} Disp_State;typedef enum{AUTO,MANU
} Mode;const char* ModeStrings[] = {"AUTO","MANU"
};Disp_State D_state = Data_Disp;
Mode mode = AUTO;
float PA6_Duty, PA7_Duty;
float R37_Volt;
void Led_Proc(){//数据显示界面if(D_state == Data_Disp){LCD_display("Data");LCD_display("V:%f",R37_Volt);LCD_display("Mode",ModeStrings[mode]);}else if(D_state == Para_Disp){LCD_Clear(Black);LCD_display("Para");LCD_display("PA6:%f%%", PA6_Duty);LCD_display("PA6:%f%%", PA7_Duty);}
}

5. 按键功能

1)B1:界面切换

2)B2:参数设置下,手动模式下,PA6占空比加10%,数值边界(10%-90%),需要设置参数循环。

3)B3:参数设置下,手动模式下,PA7占空比加10%,数值边界(10%-90%),需要设置参数循环。

4)B4:切换模式

5)B3:数据显示下,互换PA6和PA7输出频率

伪代码

unsigned int Key_Down;
Key_Proc(){//消抖不写了//按键模版不写了switch (Key_Down){case 1:if(D_state == Data_Disp){LCD_Clear(Black);D_state = Para_Disp;}else if(D_state == Para_Disp){LCD_Clear(Black);D_state = Data_Disp;}break;case 2:if(D_state == Para_Disp){if(mode == MANU){if(PA6_Duty < 90){PA6_Duty += 10;}else if(PA6_Duty = 90)PA6_Duty = 10;}}break;case 3:if(D_state == Para_Disp){if(mode == MANU){if(PA7_Duty < 90){PA7_Duty += 10;}else if(PA7_Duty = 90)PA7_Duty = 10;}}else if (D_state == Data_Disp){//切换频率这块单独写个函数}break;case 4:if(mode == AUTO)mode = MANU;else mode == AUTO;break;}
}

6. LED 指示灯

1)自动模式,LD1亮;手动模式,LD1灭。

2)数据界面,LD2亮;参数界面,LD2灭。

void Led_Proc(){if(mode == AUTO){ucled |= 0x01;}else if(mode == MANU){ucled &= ~0x01;}if(D_state == Data_Disp)ucled |= 0x02;else if(D_state == Para_Disp)ucled &= ~0x02;
}

7. 初始状态说明

1)自动模式

2)数据界面

3)10%占空比

4)PA6_f = 100Hz,PA7_f = 200Hz

占空比和频率在 CubeMx 调整。

二、CubeMx

Key 、LED 和 ADC 就不重复写了,重点是 PWM。

PWM

按图中配置的话,f=\frac{80M}{80\cdot 1000}=1000 Hz

那么此时改动 Pulse = 100,那么Duty = 100/999+1 = 10%

当然这些都是初始值,除了时钟频率和 PSC保持不变,其它都要在代码中改动。

当然 TIM17 和 TIM3 也一样。

三、完整代码编写

1. 全局变量

/* USER CODE BEGIN Includes */
#include "lcd.h"
#include "stdio.h"
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
typedef enum{Data_Disp,Para_Disp
} Disp_State;typedef enum{AUTO,MANU
} MODE;const char* ModeString[] = {"AUTO","MANU"
};Disp_State D_state = Data_Disp;
MODE mode = AUTO;
/* USER CODE END PTD *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV */uint16_t Lcd_Disp_Str[21];
float R37_Volt;
uint8_t PA6_Duty=10, PA7_Duty=10;
uint8_t Key_val, Key_up, Key_down, Key_old;
uint8_t ucled;uint8_t PWM_state_manu = 0;
uint8_t PWM_state_auto = 0;
__IO uint16_t uwTick_Set_Lcd = 0;
__IO uint16_t uwTick_Set_Key = 0;
__IO uint16_t uwTick_Set_Led = 0;
__IO uint16_t uwTick_Set_PWM = 0;/* USER CODE END PV */

2. 主函数

int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_ADC2_Init();MX_TIM3_Init();MX_TIM17_Init();/* USER CODE BEGIN 2 */LCD_Init();LCD_Clear(Black);LCD_SetBackColor(Black);LCD_SetTextColor(White);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */Lcd_Proc();Key_Proc();Led_Proc();Running_mode();/* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

3. 显示

void Lcd_Proc(){if((uwTick_Set_Lcd - uwTick) < 100)return;uwTick = uwTick_Set_Lcd;R37_Volt = (((float)(Get_ADC2())/4096)*3.3);if(D_state == Data_Disp){sprintf((char*) Lcd_Disp_Str, "      Data");LCD_DisplayStringLine(Line0, Lcd_Disp_Str);sprintf((char*) Lcd_Disp_Str, "    V:%4.2fV", R37_Volt);LCD_DisplayStringLine(Line2, Lcd_Disp_Str);sprintf((char*) Lcd_Disp_Str, "    Mode:%s", ModeString[mode]);LCD_DisplayStringLine(Line4, Lcd_Disp_Str);}else if(D_state == Para_Disp){sprintf((char*) Lcd_Disp_Str, "      Para");LCD_DisplayStringLine(Line0, Lcd_Disp_Str);sprintf((char*) Lcd_Disp_Str, "    PA6:%02d%%", (unsigned int)PA6_Duty);LCD_DisplayStringLine(Line2, Lcd_Disp_Str);sprintf((char*) Lcd_Disp_Str, "    PA7:%02d%%", (unsigned int)PA7_Duty);LCD_DisplayStringLine(Line4, Lcd_Disp_Str);}	
}

4. 按键

void Key_Proc(){if((uwTick_Set_Key - uwTick) < 100)return;uwTick = uwTick_Set_Key;Key_val = Key_Scan();Key_up = Key_val & (Key_val ^ Key_old);Key_down = ~Key_val & (Key_val ^ Key_old);Key_old = Key_val;switch(Key_down){case 1:if(D_state == Data_Disp){LCD_Clear(Black);D_state = Para_Disp;}else if(D_state == Para_Disp){LCD_Clear(Black);D_state = Data_Disp;}break;case 2:if(D_state == Para_Disp){if(mode == MANU){if(PA6_Duty < 90){PA6_Duty += 10;}else if(PA6_Duty == 90)PA6_Duty = 10;}}break;case 3:if(D_state == Para_Disp){if(mode == MANU){if(PA7_Duty < 90){PA7_Duty += 10;}else if(PA7_Duty == 90)PA7_Duty = 10;}}break;case 4:if(mode == AUTO)mode = MANU;else mode = AUTO;break;}
}

5. LED

void Led_Proc(){if((uwTick_Set_Led - uwTick) < 100)return;uwTick = uwTick_Set_Led;if(mode == AUTO){ucled |= 0x01;}else if(mode == MANU){ucled &= ~(0x01);}if(D_state == Data_Disp)ucled |= 0x02;else if(D_state == Para_Disp)ucled &= ~(0x02);Led_Disp(ucled);
}

6. PWM

void Running_mode(){if((uwTick_Set_PWM - uwTick) < 100)return;uwTick = uwTick_Set_PWM;if(D_state == Data_Disp){if(Key_down == 3){if(mode == AUTO){if(PWM_state_auto == 0){//80M/(80*10K)=100__HAL_TIM_SET_AUTORELOAD(&htim3, 9999);// 80M/(80*5K) =200__HAL_TIM_SET_AUTORELOAD(&htim17, 4999);__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, (unsigned int)(10000*((R37_Volt)/3.3)));__HAL_TIM_SET_COMPARE(&htim17, TIM_CHANNEL_1, (unsigned int)(5000*((R37_Volt)/3.3)));PWM_state_auto = 1;}if(PWM_state_auto == 1){//80M/(80*10K)=100__HAL_TIM_SET_AUTORELOAD(&htim17, 9999);// 80M/(80*5K) =200__HAL_TIM_SET_AUTORELOAD(&htim3, 4999);__HAL_TIM_SET_COMPARE(&htim17, TIM_CHANNEL_1, (unsigned int)(10000*((R37_Volt)/3.3)));__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, (unsigned int)(5000*((R37_Volt)/3.3)));PWM_state_auto = 0;}}切换PA6和PA7的频率else if(mode == MANU){if(PWM_state_manu == 0){__HAL_TIM_SET_AUTORELOAD(&htim3, 9999);__HAL_TIM_SET_AUTORELOAD(&htim17, 4999);//频率改变后,占空比也要跟随,毕竟跟周期有关__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, (100*PA6_Duty));__HAL_TIM_SET_COMPARE(&htim17, TIM_CHANNEL_1, (50*PA6_Duty));PWM_state_manu = 1;				}else if(PWM_state_manu == 1){__HAL_TIM_SET_AUTORELOAD(&htim17, 9999);__HAL_TIM_SET_AUTORELOAD(&htim3, 4999);//频率改变后,占空比也要跟随,毕竟跟周期有关__HAL_TIM_SET_COMPARE(&htim17, TIM_CHANNEL_1, (100*PA6_Duty));__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, (50*PA6_Duty));PWM_state_manu = 0;	}}}
}
}

7. BSP

这块不赘述了,背就完了

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小试牛刀-抽奖程序

编写抽奖程序 需求&#xff1a;设计一个抽奖程序&#xff0c;点击抽奖按钮随机抽取一个名字作为中奖者 目标&#xff1a;了解项目结构&#xff0c;简单UI布局&#xff0c;属性方法、事件方法&#xff0c;程序运行及调试 界面原型 ​ 待抽奖&#xff1a; 点击抽奖按钮&#x…

代码随想录算法训练营day2(数组)

华子目录 长度最小的子数组思路 螺旋矩阵思路总结 长度最小的子数组 https://leetcode.cn/problems/minimum-size-subarray-sum/ 思路 使用滑动窗口&#xff0c;left表示滑动窗口的起始点&#xff0c;right表示滑动窗口的终点 class Solution:def minSubArrayLen(self, targ…

6.1 GitHub亿级数据采集实战:双通道架构+三级容灾设计,破解API限制与反爬难题

GitHub 项目数据获取功能设计与实现 关键词:GitHub API 集成、网页爬虫开发、数据存储设计、定时任务调度、异常处理机制 1. 数据获取架构设计 采用双通道数据采集策略,同时使用 GitHub 官方 API 和网页爬虫技术确保数据完整性: #mermaid-svg-XUg7xhHrzFAozG4J {font-fami…

设计模式(结构型)-桥接模式

目录 摘要 定义 类图 角色 具体实现 优缺点 优点 缺点 使用场景 使用案例 JDBC 和桥接模式 总结 摘要 在软件开发领域&#xff0c;随着系统规模和复杂性的不断攀升&#xff0c;如何设计出具有良好扩展性、灵活性以及可维护性的软件架构成为关键挑战。桥接模式作为一…

Go 微服务框架 | 中间件

文章目录 定义中间件前置中间件后置中间件路由级别中间件 定义中间件 中间件的作用是给应用添加一些额外的功能&#xff0c;但是不会影响原有应用的编码方式&#xff0c;想用的时候直接添加&#xff0c;不想用的时候也可以轻松去除&#xff0c;实现所谓的可插拔。中间件的实现…

leetcode 198. House Robber

本题是动态规划问题。 第一步&#xff0c;明确并理解dp数组以及下标的含义 dp[i]表示从第0号房间一直到第i号房间(包含第i号房间)可以偷到的最大金额&#xff0c;具体怎么偷这里不考虑&#xff0c;第i1号及之后的房间也不考虑。换句话说&#xff0c;dp[i]也就是只考虑[0,i]号…

掌趣科技前端面试题及参考答案

你使用 Vue 的频率如何,用得比较多吗? 在前端开发工作中,我对 Vue 的使用较为频繁。Vue 作为一款轻量级、易于上手且功能强大的前端框架,在众多项目里都发挥着重要作用。 在日常的项目里,Vue 的组件化开发特性为我带来了极大的便利。组件化能够将页面拆分成多个小的、可复…

深入解析Python爬虫技术:从基础到实战的功能工具开发指南

一、引言:Python 爬虫技术的核心价值 在数据驱动的时代,网络爬虫作为获取公开数据的重要工具,正发挥着越来越关键的作用。Python 凭借其简洁的语法、丰富的生态工具以及强大的扩展性,成为爬虫开发的首选语言。根据 Stack Overflow 2024 年开发者调查,68% 的专业爬虫开发者…

CSS 笔记——Flexbox(弹性盒布局)

目录 1. Flex 容器与 Flex 项目 2. 主轴与交叉轴 3. Flex 容器的属性 display flex-direction justify-content align-items align-content flex-wrap 4. Flex 项目的属性 flex-grow flex-shrink flex-basis flex align-self 5. Flexbox 的优点 6. Flexbox 的…

Java学习手册:Java反射与注解

Java反射&#xff08;Reflection&#xff09;和注解&#xff08;Annotation&#xff09;是Java语言中两个强大的特性&#xff0c;它们在框架开发和复杂应用中扮演着重要角色。反射允许程序在运行时检查和操作类、对象、接口、字段和方法&#xff0c;而注解则提供了一种元数据形…

JavaWeb遇到的问题汇总

问题一&#xff1a;&#xff08;键值对最后一项没有逗号&#xff09; 在JSON字符串转自定义对象和自定义对象转JSON字符串时&#xff1a; 如图所示&#xff1a;若忘记删除键值对的最后一项没有逗号时&#xff0c;则下一句转换不会生效&#xff0c;应该删除最后一项的逗号。 解…

模板引擎语法-变量

模板引擎语法-变量 文章目录 模板引擎语法-变量&#xff08;一&#xff09;在Django框架模板中使用变量的代码实例&#xff08;二&#xff09;在Django框架模板中使用变量对象属性的代码实例&#xff08;三&#xff09;在Django框架模板中使用变量显示列表 &#xff08;一&…

AUTO-RAG: AUTONOMOUS RETRIEVAL-AUGMENTED GENERATION FOR LARGE LANGUAGE MODELS

Auto-RAG&#xff1a;用于大型语言模型的自主检索增强生成 单位&#xff1a;中科院计算所 代码&#xff1a; https://github.com/ictnlp/Auto-RAG 拟解决问题&#xff1a;通过手动构建规则或者few-shot prompting产生的额外推理开销。 贡献&#xff1a;提出一种以LLM决策为中…

Python 基础语法汇总

Python 语法 │ ├── 基本结构 │ ├── 语句&#xff08;Statements&#xff09; │ │ ├── 表达式语句&#xff08;如赋值、算术运算&#xff09; │ │ ├── 控制流语句&#xff08;if, for, while&#xff09; │ │ ├── 定义语句&#xff08;def…

一文详解ffmpeg环境搭建:Ubuntu系统ffmpeg配置nvidia硬件加速

在Ubuntu系统下安装FFmpeg有多种方式,其中最常用的是通过apt-get命令和源码编译安装。本文将分别介绍这两种方式,并提供安装过程。 一、apt-get安装 使用apt-get命令安装FFmpeg是最简单快捷的方式,只需要在终端中输入以下命令即可: # 更新软件包列表 sudo apt-get updat…

Android 14 、15动态申请读写权限实现 (Java)

在 Android 14、15 中&#xff0c;Google 进一步优化了存储权限系统&#xff0c;特别是写权限的管理。以下是完整的 Java 实现方案&#xff1a; 1. AndroidManifest.xml 声明权限 <!-- Android 14 存储权限 --> <uses-permission android:name"android.permiss…

小刚说C语言刷题——第23讲 字符数组

前面&#xff0c;我们学习了一维数组和二维数组的概念。今天我们学习一种特殊的数组&#xff0c;字符数组。 1.字符数组的概念 字符数组就是指元素类型为字符的数组。字符数组是用来存放字符序列或者字符串的。 2.字符数组的定义及语法 char ch[5]; 3.字符数组的初始化及赋…

用AI生成系统架构图

DeepSeek+Drawio+SVG绘制架构图-找到一种真正可行实用的方法和思路 1、使用DeepSeek生成SVG文件,导入drawio工具的方法 🔥 问题根源分析 错误现象: • 导入时报错包含 data:image/SVG;base64 和 %20 等 URL 编码字符 • 代码被错误转换为 Base64 格式(适用于网页嵌入,但…

免费干净!付费软件的平替款!

今天给大家分享一款超棒的电脑录屏软件&#xff0c;简直不要太好用&#xff01;它的界面特别干净&#xff0c;没有一点儿广告&#xff0c;看起来特别清爽。 电脑录屏 无广告的录屏软件 这个软件超方便&#xff0c;根本不用安装&#xff0c;打开就能直接用。 它功能也很强大&am…

【XCP实战】AUTOSAR架构下XCP从0到1开发配置实践

目录 前言 正文 1.CAN功能开发 1.1 DBC的制作及导入 1.2 CanTrcv模块配置 1.3 Can Controller模块配置 1.4 CanIf模块配置 2.XCP模块集成配置配置 2.1.XCP模块配置 2.2.XCP模块的Task Mapping 2.3.XCP模块的初始化 3.在链接文件中定义标定段 4.编写标定相关的测试…