第十二届蓝桥杯嵌入式省赛程序设计题解析(基于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&…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
