第十二届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)(第一套)
一.题目分析
(1).题目
(2).题目分析
1.串口功能分析
a.串口接收车辆出入信息:通过查询车库的车判断车辆是进入/出去
b.串口输出计费信息:输出编号,时长和费用
c.计算停车时长是难点,需要将年月日时分秒全部都转换成秒
d.当接收到的字符串格式不正确或者逻辑错误就输出Error
e.数据库
22个字节构成一组,最多有八组,然后定义结构体变量,该结构体的数据结构为车类型+车编号+时间的数据格式,用该结构体变量,创造一个数组
(3).逻辑导图
二.CubeMX配置
由于蓝桥杯使用的板子都是STM32G431RBT6,配置都是相同的,模板已经在第六届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)-CSDN博客配置完成,大家可以前往学习
三.相关代码实现
(1)MAIN
1.全局变量声明
#include "main.h"
#include "RCC\bsp_rcc.h"
#include "KEY_LED\bsp_key_led.h"
#include "LCD\bsp_lcd.h"
#include "UART\bsp_uart.h"
#include "TIM\bsp_tim.h"
#include <string.h>//***全局变量声明区
//*减速变量
__IO uint32_t uwTick_Key_Set_Point = 0;//控制Key_Proc的执行速度
__IO uint32_t uwTick_Led_Set_Point = 0;//控制Led_Proc的执行速度
__IO uint32_t uwTick_Lcd_Set_Point = 0;//控制Lcd_Proc的执行速度
__IO uint32_t uwTick_Usart_Set_Point = 0;//控制Usart_Proc的执行速度//*按键扫描专用变量
uint8_t ucKey_Val, unKey_Down, ucKey_Up, ucKey_Old;//*LED专用变量
uint8_t ucLed;//*LCD显示专用变量
uint8_t Lcd_Disp_String[21];//最多显示20个字符//*串口专用变量
uint16_t counter = 0;
uint8_t str_str[40];
uint8_t rx_buffer;//***子函数声明区
void Key_Proc(void);
void Led_Proc(void);
void Lcd_Proc(void);
void Usart_Proc(void);//全局变量区
_Bool Disp_Num;//0-数据显示,1-费率设置
_Bool PWM_Output_Num;//0-低电平,1-PWMfloat VNBR_Price = 2.00;
float CNBR_Price = 3.50;uint8_t VNBR_Use_Num;
uint8_t CNBR_Use_Num;
uint8_t No_Use_Num = 8;uint8_t RX_BUF[200];//用于缓冲接收200个字节的数量
uint8_t Rx_Counter;//用于记录接收了多少个数据,同时可以索引RX_BUF中的数据位置typedef struct
{uint8_t type[5];uint8_t id[5];uint8_t year_in;uint8_t month_in;uint8_t day_in;uint8_t hour_in;uint8_t min_in;uint8_t sec_in;_Bool notEmpty;
} Car_Data_Storage_Type;Car_Data_Storage_Type Car_Data_Storage[8];//数据库构建完毕,用于存储8个进来的车的信息
2.系统主函数
int main(void)
{/* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* Configure the system clock */SystemClock_Config();/*bsp资源的初始化*/KEY_LED_Init();LCD_Init();LCD_Clear(Black);LCD_SetBackColor(Black);LCD_SetTextColor(White); UART1_Init();PWM_OUTPUT_TIM17_Init();//*串口接收中断打开HAL_UART_Receive_IT(&huart1, (uint8_t *)(&rx_buffer), 1); __HAL_TIM_SET_COMPARE(&htim17,TIM_CHANNEL_1, 0);//强制配置成低电平HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1); //PA7 while (1){Key_Proc();Led_Proc();Lcd_Proc();Usart_Proc();}}
3.按键扫描子函数
a. 逻辑框图
b. 程序源码
//***按键扫描子函数
void Key_Proc(void)
{if((uwTick - uwTick_Key_Set_Point)<50) return;//减速函数uwTick_Key_Set_Point = uwTick;ucKey_Val = Key_Scan();unKey_Down = ucKey_Val & (ucKey_Old ^ ucKey_Val); ucKey_Up = ~ucKey_Val & (ucKey_Old ^ ucKey_Val); ucKey_Old = ucKey_Val;switch(unKey_Down){case 1://B1Disp_Num ^= 0x1;LCD_Clear(Black);break;case 2://B2if(Disp_Num == 1)//费率设置界面{VNBR_Price += 0.5;CNBR_Price += 0.5; } break; case 3://B3if(Disp_Num == 1)//费率设置界面{if((VNBR_Price - 0.5)> 0){VNBR_Price -= 0.5;CNBR_Price -= 0.5; }} break; case 4://B4PWM_Output_Num ^= 0x1;if(PWM_Output_Num == 0)//低电平{__HAL_TIM_SET_COMPARE(&htim17,TIM_CHANNEL_1, 0);//强制配置成低电平}else//高电平 {__HAL_TIM_SET_COMPARE(&htim17,TIM_CHANNEL_1, 100);//强制配置成PWM电平 }break; }
}
4.LED扫描子函数
a. 逻辑框图
b. 程序源码
void Led_Proc(void)
{if((uwTick - uwTick_Led_Set_Point)<200) return;//减速函数uwTick_Led_Set_Point = uwTick;if(No_Use_Num > 0)//表示还有车位{ucLed |= 0x1; }else//如果空闲{ucLed &= (~0x1); }if(PWM_Output_Num == 0)//低电平{ucLed &= (~0x2); }else//PWM{ ucLed |= 0x2; }LED_Disp(ucLed);
}
5. LCD扫描
a. 程序框图
b. 程序源码
void Lcd_Proc(void)
{if((uwTick - uwTick_Lcd_Set_Point)<100) return;//减速函数uwTick_Lcd_Set_Point = uwTick;//用户代码if(Disp_Num == 0)//数据界面{sprintf((char *)Lcd_Disp_String, " Data");LCD_DisplayStringLine(Line1, Lcd_Disp_String); sprintf((char *)Lcd_Disp_String, " CNBR:%1d",(unsigned int)CNBR_Use_Num);LCD_DisplayStringLine(Line3, Lcd_Disp_String); sprintf((char *)Lcd_Disp_String, " VNBR:%1d",(unsigned int)VNBR_Use_Num);LCD_DisplayStringLine(Line5, Lcd_Disp_String); sprintf((char *)Lcd_Disp_String, " IDLE:%1d",(unsigned int)No_Use_Num);LCD_DisplayStringLine(Line7, Lcd_Disp_String); }else//参数界面{sprintf((char *)Lcd_Disp_String, " Para");LCD_DisplayStringLine(Line1, Lcd_Disp_String); sprintf((char *)Lcd_Disp_String, " CNBR:%4.2f",CNBR_Price);LCD_DisplayStringLine(Line3, Lcd_Disp_String); sprintf((char *)Lcd_Disp_String, " VNBR:%4.2f",VNBR_Price);LCD_DisplayStringLine(Line5, Lcd_Disp_String); }
}
6. 判别接收到22个字符是否合法函数
a. 逻辑框图
b. 程序源码
_Bool CheckCmd(uint8_t* str)//用于判别接受的22个字符是否合法
{if(Rx_Counter != 22)return 0;//表示还不够22个数据if(((str[0]=='C')||(str[0]=='V'))&&(str[1]=='N')&&(str[2]=='B')&&(str[3]=='R')&&(str[4]==':')&&(str[9]==':')){uint8_t i;for(i = 10; i< 22;i++){if((str[i]>'9')||(str[i]<'0'))return 0;}return 1;//表示接收到的数据没问题}
}
7. 从长字符串提取一段给短字符串函数
a. 逻辑分析
传入参数为(数据的类型,提取的位置,从第几位开始提取,提取的个数)
b. 程序源码
void substr(uint8_t* d_str, uint8_t* s_str, uint8_t locate, uint8_t length)//从长字符串里边提取出一段给短字符串
{ uint8_t i = 0;for(i=0; i<length; i++){d_str[i] = s_str[locate + i];}d_str[length] = '\0';
}
8.判别车是否在车库里面
a.逻辑分析
使用到了strcmp函数比较字符串是否相同,相同就返回0
【函数原型】 int strcmp(const char *s1, const char *s2);
【参数】s1, s2 为需要比较的两个字符串。
【返回值】若参数s1 和s2 字符串相同则返回0,s1 若大于s2 则返回大于0 的值,s1 若小于s2 则返回小于0 的值
b.程序源码
//判别车的id是否在库里边
uint8_t isExist(uint8_t* str)
{uint8_t i = 0; for(i=0; i<8; i++){if((strcmp((const char*)str,(const char*)Car_Data_Storage[i].id)) == 0)//表示字符串匹配,有这个字符串 {return i;//如果该id在数据库存着,返回这个id在数据库当中的位置}} return 0xFF;//如果没有,返回oxff
}
9.判断0-7号,哪个位置有空挡
a.逻辑分析
轮询数据库里面的空档标志位,当标志位为0说明没有被使用,则返回第i号位置
b.程序源码
uint8_t findLocate(void)
{uint8_t i = 0;for(i = 0;i <= 7; i++ ){if(Car_Data_Storage[i].notEmpty == 0)return i;//0-7号位}return 0XFF;
}
10.串口扫描子函数
a.逻辑框图
b.程序源码
void Usart_Proc(void)
{if((uwTick - uwTick_Usart_Set_Point)<100) return;//减速函数uwTick_Usart_Set_Point = uwTick; if(CheckCmd(RX_BUF))//粗糙的判断,第一步,判别数据个数以及数据格式是否合法{uint8_t car_id[5];uint8_t car_type[5]; uint8_t year_temp,month_temp,day_temp,hour_temp,min_temp,sec_temp;year_temp = (((RX_BUF[10] - '0')*10) + (RX_BUF[11] - '0')); month_temp = (((RX_BUF[12] - '0')*10) + (RX_BUF[13] - '0')); day_temp = (((RX_BUF[14] - '0')*10) + (RX_BUF[15] - '0')); hour_temp = (((RX_BUF[16] - '0')*10) + (RX_BUF[17] - '0')); min_temp = (((RX_BUF[18] - '0')*10) + (RX_BUF[19] - '0')); sec_temp = (((RX_BUF[20] - '0')*10) + (RX_BUF[21] - '0')); if((month_temp>12)||(day_temp>31)||(hour_temp>23)||(min_temp>59)||(sec_temp>59))//验证日期和时间是否合法{goto SEND_ERROR;}substr(car_id, RX_BUF, 5, 4);//提取车的idsubstr(car_type, RX_BUF, 0, 4); //提取车的类型//**********************车还没有进入******if(isExist(car_id) == 0xFF)//表示库里边没有这辆车的ID,表示这个车还没进入{uint8_t locate = findLocate();//找到哪个地方是空的if(locate == 0xFF)//没有找到哪个地方是空的{goto SEND_ERROR;}//准备存储substr(Car_Data_Storage[locate].type, car_type, 0, 4);//把当前车的类型存入 substr(Car_Data_Storage[locate].id, car_id, 0, 4);//把当前车的id存入Car_Data_Storage[locate].year_in = year_temp;Car_Data_Storage[locate].month_in = month_temp; Car_Data_Storage[locate].day_in = day_temp; Car_Data_Storage[locate].hour_in = hour_temp; Car_Data_Storage[locate].min_in = min_temp; Car_Data_Storage[locate].sec_in = sec_temp; Car_Data_Storage[locate].notEmpty = 1;if(Car_Data_Storage[locate].type[0] == 'C')CNBR_Use_Num++;else if(Car_Data_Storage[locate].type[0] == 'V')VNBR_Use_Num++;No_Use_Num--; }//**********************如果车已经进来了,现在是出去****** else if(isExist(car_id) != 0xFF)//表示数据库里有他的信息,返回他在数据库的位置{int64_t Second_derta;//用于核算小时的差值 uint8_t in_locate = isExist(car_id);//记住在数据库中的位置if(strcmp((const char*)car_type,(const char*)Car_Data_Storage[in_locate].type) != 0)//说明不匹配{goto SEND_ERROR; }//2000 2001 2002 //1 2 3Second_derta = (year_temp - Car_Data_Storage[in_locate].year_in)*365*24*60*60 + (month_temp - Car_Data_Storage[in_locate].month_in)*30*24*60*60+\(day_temp - Car_Data_Storage[in_locate].day_in)*24*60*60 + (hour_temp - Car_Data_Storage[in_locate].hour_in)*60*60 + \(min_temp - Car_Data_Storage[in_locate].min_in)*60 + (sec_temp - Car_Data_Storage[in_locate].sec_in);if(Second_derta < 0)//说明出去的时间超前进去的时间{goto SEND_ERROR; }Second_derta = (Second_derta + 3599)/3600; //小时数据已经核算出来sprintf(str_str, "%s:%s:%d:%.2f\r\n",Car_Data_Storage[in_locate].type,Car_Data_Storage[in_locate].id,(unsigned int)Second_derta,(Second_derta*(Car_Data_Storage[in_locate].id[0]=='C'?CNBR_Price:VNBR_Price)));HAL_UART_Transmit(&huart1,(unsigned char *)str_str, strlen(str_str), 50); if(Car_Data_Storage[in_locate].type[0] == 'C')CNBR_Use_Num--;else if(Car_Data_Storage[in_locate].type[0] == 'V')VNBR_Use_Num--;No_Use_Num++; memset(&Car_Data_Storage[in_locate],0,sizeof(Car_Data_Storage[in_locate]));//清空该位置所有内容,为0}goto CMD_YES;SEND_ERROR: sprintf(str_str, "Error\r\n");HAL_UART_Transmit(&huart1,(unsigned char *)str_str, strlen(str_str), 50);CMD_YES:memset(&RX_BUF[0],0,sizeof(RX_BUF));//清空该位置所有内容,为0Rx_Counter = 0;}
}
11.串口接收中断回调函数
a.逻辑分析
实现将字符数据保存到环形缓冲区里面
b. 程序源码
//串口接收中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{RX_BUF[Rx_Counter] = rx_buffer;Rx_Counter++;HAL_UART_Receive_IT(&huart1, (uint8_t *)(&rx_buffer), 1);
}
(2)BSP
在第六届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)-CSDN博客里面有详细的讲解,大家可前往此链接学习
相关文章:

第十二届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)(第一套)
一.题目分析 (1).题目 (2).题目分析 1.串口功能分析 a.串口接收车辆出入信息:通过查询车库的车判断车辆是进入/出去 b.串口输出计费信息:输出编号,时长和费用 c.计算停车时长是难点&#x…...

MongoDB入门:安装及环境变量配置
一、安装MonggoDB Windows系统安装MongoDB 1、下载MongoDB安装包 访问MongoDB官方网站,选择与Windows系统相匹配的MongoDB Community Server版本进行下载。 Download MongoDB Community Server | MongoDB 2、安装MongoDB 双击下载好的安装包文件,根…...
利用 notepad++ 初步净化 HaE Linkfinder 规则所提取的内容(仅留下接口行)
去掉接口的带参部分 \?.*去掉文件行 .*\.(docx|doc|xlsx|xls|txt|xml|html|pdf|ppt|pptx|odt|ods|odp|rtf|md|epub|css|scss|less|sass|styl|png|jpg|jpeg|gif|svg|ico|bmp|tiff|webp|heic|dds|raw|vue|js|ts|mp4|avi|mov|wmv|mkv|flv|webm|mp3|wav|aac|flac|ogg|m4a).*(\r\…...
RCE(remote command/code execute)远程命令注入
远程命令注入RCE RCE(remote command/code execute,远程命令执行)漏洞,一般出现这种漏洞,是因为应用系统从设计上需要给用户提供指定的远程命令操作的接口,比如我们常见的路由器、防火墙、入侵检测等设备的web管理界面上。一般会给…...
一篇关于密码学的概念性文章
文章目录 1. 引言2. 加密学基本概念3. 加密算法的类型3.1 对称密钥加密(SKC)3.2 公钥密码学3.3 哈希函数3.4. 为什么需要三种加密技术?3.5 密钥长度的重要性4. 信任模型4.1 PGP信任网络4.2 Kerberos4.3 公钥证书和证书颁发机构4.4 总结5. 密码算法的实际应用5.1 密码保护5.2…...
什么是汽车中的SDK?
无论是在家里使用预制菜包做一顿大厨级别的晚餐,还是使用IKEA套组装配出时尚的北欧风桌子,我们都熟悉这样一种概念:比起完全从零开始,使用工具包可以帮助我们更快、更高效地完成一件事。 在速度至关重要的商业软件领域࿰…...

利用CRITIC客观权重赋权法进行数值评分计算——算法过程
1、概述 CRITIC客观评价法是一种基于指标的对比强度和指标之间的冲突性来确定指标客观权数的方法。 该方法适用于判断数据稳定性,并且适合分析指标或因素之间有着一定的关联的数据。 CRITIC方法的基本原理包括两个主要概念:对比强度和指标之间的…...

一个月学会Java 第4天 运算符和数据转换
Day4 运算符和数据转换 今天来讲运算符,每个运算符的作用和现象,首先我们先复习一下数据类型, day2讲过基本数据类型有八种,int、short、long、byte、char、boolean、float、double,分别为四个整型、一个字符型、一个布…...

Stream流的终结方法(一)
1.Stream流的终结方法 2.forEach 对于forEach方法,用来遍历stream流中的所有数据 package com.njau.d10_my_stream;import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.function.Consumer; import java.util…...

GO网络编程(二):客户端与服务端通信【重要】
本节是新知识,偏应用,需要反复练习才能掌握。 目录 1.C/S通信示意图2.服务端通信3.客户端通信4.通信测试5.进阶练习:客户端之间通信 1.C/S通信示意图 客户端与服务端通信的模式也称作C/S模式,流程图如下 其中P是协程调度器。可…...

快速熟悉Nginx
一、Nginx是什么? Nginx是一款高性能、轻量级的Web服务器和反向代理服务器。 特点:Nginx采用事件驱动的异步非阻塞处理框架,内存占用少,并发能力强,资源消耗低。功能:Nginx主要用作静态文件服…...
VikParuchuri/marker 学习简单总结
核心代码 VikParuchuri/marker 的核心是使用https://github.com/VikParuchuri/surya的 pdf 模型,注意不仅仅是ocr,在marker的代码里面有标注ocr 是option的。强制OCR 要设置:OCR_ALL_PAGES=true核心代码就是convert.py def convert_single_pdf(fname: str,model_lst: List,…...
【AI知识点】词嵌入(Word Embedding)
词嵌入(Word Embedding)是自然语言处理(NLP)中的一种技术,用于将词语或短语映射为具有固定维度的实数向量。这些向量(嵌入向量)能够捕捉词语之间的语义相似性,即将语义相近的词映射到…...

Python从入门到高手5.1节-Python简单数据类型
目录 5.1.1 理解数据类型 5.1.2 Python中的数据类型 5.1.3 Python简单数据类型 5.1.4 特殊的空类型 5.1.5 Python变量的类型 5.1.6 广州又开始变热 5.1.1 理解数据类型 数据类型是根据数据本身的性质和特征来对数据进行分类,例如奇数与偶数就是一种数据类型。…...

Hbase要点简记
Hbase要点简记 Hbase1、底层架构2、表逻辑结构 Hbase HBase是一个分布式的、列式的、实时查询的、非关系型数据库,可以处理PB级别的数据,吞吐量可以到的百万查询/每秒。主要应用于接口等实时数据应用需求,针对具体需求,设计高效率…...

RabbitMQ的各类工作模式介绍
简单模式 P: ⽣产者, 也就是要发送消息的程序 C: 消费者,消息的接收者 Queue: 消息队列, 图中⻩⾊背景部分. 类似⼀个邮箱, 可以缓存消息; ⽣产者向其中投递消息, 消费者从其中取出消息.特点: ⼀个⽣产者P,⼀个消费者C, 消息只能被消费⼀次. 也称为点对点(Point-to-…...

李宏毅深度学习-图神经网络GNN
图卷积的开源代码网站DGL 好用的还是 GAT, GIN(指出最好的卷积 就是 hi 邻居特征(而且只能用 sum)) Introduction GNN 可以理解为是由 Graph(图) Nerual Networks 组合而成的,图结构应该都在数据结构与…...

Redis篇(缓存机制 - 分布式缓存)(持续更新迭代)
目录 一、单点 Redis 的问题 1. 数据丢失问题 2. 并发能力问题 3. 故障恢复问题 4. 存储能力问题 5. 四种问题的解决方案 二、Redis持久化(两种方案) 1. RDB持久化 1.1. 简介 1.2. 执行时机 save命令 bgsave命令 停机时 触发RDB条件 1.3. …...

python交互式命令时如何清除
在交互模式中使用Python,如果要清屏,可以import os,通过os.system()来调用系统命令clear或者cls来实现清屏。 [python] view plain copy print? >>> import os >>> os.system(clear) 但是此时shell中的状态是:…...
Token,Cookie,Session,JWT详解
这四个技术虽然在功能上有所不同,但在web应用中常常一起使用,已实现用户身份验证,授权和会话管理。 Token:指的是用于身份验证,授权成信息交换的令牌,可以有不同的实现方式,例如JWT。 Cookie&…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...

AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化
是不是受够了安装了oracle database之后sqlplus的简陋,无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话,配置.bahs_profile后也能解决上下翻页这些,但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可,…...

STM32标准库-ADC数模转换器
文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)1.4.2 信号 “调度站”:多路开关1.4.3 信号 “加工厂”:ADC 转换器(规则组 注入…...