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

keil5使用c++编写stm32控制程序

keil5使用c++编写stm32控制程序

  • 一、前言
  • 二、配置图解
  • 三、std::cout串口重定向
  • 四、串口中断服务函数
  • 五、结尾废话

一、前言

想着搞个新奇的玩意玩一玩来着,想用c++编写代码来控制stm32,结果在keil5中,把踩给我踩闷了,这里简单记录一下。注意一定要按照如下流程进行操作,一步都不要跟丢了。

二、配置图解

所需要的一些文件放在百度网盘了。
先把最新的库函数和CMSIS安装好。
我这里为了方便就直接安装在了keil5的文件夹路径里。
在这里插入图片描述

废话不多说,直接上图解。
在这里插入图片描述
记得把use microlib的勾选去掉。配置和我图片上一样就没问题。

在这里插入图片描述
那这样配置过后会不会就好用了?当然不是,还要使用最新的标准库函数才行。
如何配置以后方便移植勒?当然是这样操作啦。
这里用的是普中科技32f103zet6板子的案例教程。
如图,找到你工程目录下的CMSIS把之前老版本的删除掉。
在这里插入图片描述
注意自己找到你最新的CMSIS的安装路径。
再把你Keil_v5\ARM\Packs\ARM\CMSIS\5.9.0\CMSIS\Core\Include里边的文件全部复制过去。
在这里插入图片描述
在把Keil_v5\ARM\Packs\Keil\STM32F1xx_DFP\2.4.0\Device\Include里边的system_stm32f10x.hKeil_v5\ARM\Packs\Keil\STM32F1xx_DFP\2.4.0\Device\Source里边的system_stm32f10x.c复制出来。 然后再继续在Keil_v5\ARM\Packs\Keil\STM32F1xx_DFP\2.4.0\Device\Source\ARM找到你对应单片机的后缀文件。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

最后你工程目录的CMSIS下边就应该是这些文件。
在这里插入图片描述
2.再把Libraries下的STM32F10x_StdPeriph_Driver里的inc和src文件替换为最新的固件库的。
安装的最新的固件库的文件位置在Keil_v5\ARM\Packs\Keil\STM32F1xx_DFP\2.4.0\Device\StdPeriph_Driver里。
在这里插入图片描述
3.替换user文件下的如下文件
在这里插入图片描述
找到文件路径在Keil_v5\ARM\Packs\Keil\STM32F1xx_DFP\2.4.0\Device\StdPeriph_Driver\templates文件下
在这里插入图片描述
在找打之前的Keil_v5\ARM\Packs\Keil\STM32F1xx_DFP\2.4.0\Device\Include里的这个文件在这里插入图片描述
用这些把之前的文件替换掉就行。
在这里插入图片描述
接下来先把你工程中的一些c结尾文件按如下配置
在这里插入图片描述

就可以编译运行了,但是直接运行会报错。
在这里插入图片描述
建议先进入stm32f10x_conf.h文件中把
”#include "RTE_Components.h"注释掉,因为我们按照做模板的配置操作的,没有进入之前的动态环境中去配置东西,如果选择了如下配置的东西就会在你的工程文件下生成RTE的一个文件夹。如果你选择了这样操作的话就不会报这个错误。如果要配置的话记得把依赖勾选完整,如果依赖勾选正确会显示绿色,如果不正确会显示黄色,这里不在赘述,纯粹是为你满足你们的好奇心。

当然现在也可以不用管,因为后边会配置自定义的串口输出,会勾选一些配置,到时候他就会自动生成这个RTE_Components.h所需要的环境。
在这里插入图片描述
在这里插入图片描述

这下配置好了,浅浅的点个灯吧,点灯大师已经准备上线了,直接操作。

写个led.h

/*  LED时钟端口、引脚定义 */
#ifndef _led_H
#define _led_H#include "system.h"#define LED_PORT 			GPIOC   
#define LED_PIN 			(GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7)
#define LED_PORT_RCC		RCC_APB2Periph_GPIOC//这里是stm32的管脚的按位操作。
#define led1 PCout(1)  	//D2指示灯连接的是PC1管脚
#define led2 PCout(2)  	//D2指示灯连接的是PC2管脚#ifdef __cplusplusclass Led{
public:Led(){LED_GPIO_Config();}void LED_GPIO_Config(void);void TurnOn( u16 port, bool status);~Led(){std::cout<<std::move("I am relased!")<<std::endl;};
private:};#endif

在写个led.cpp

#include "led.h"void Led::LED_GPIO_Config()
{GPIO_InitTypeDef GPIO_InitStructure;//定义结构体变量RCC_APB2PeriphClockCmd(LED_PORT_RCC, ENABLE);GPIO_InitStructure.GPIO_Pin = LED_PIN;  //选择你要设置的IO口GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	 //设置推挽输出模式GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	  //设置传输速率GPIO_Init(LED_PORT, &GPIO_InitStructure); 	   /* 初始化GPIO */GPIO_SetBits(LED_PORT, LED_PIN);   //将LED端口拉高,熄灭所有LED}void Led::TurnOn(u16 port, bool status)
{if(status){GPIO_ResetBits(LED_PORT, port);}  //将LED端口拉高,熄灭所有LEDelse{GPIO_SetBits(LED_PORT, port);}
}

再写个main.cpp

#include "system.h"int main(void)
{SysTick_Init(72);std::shared_ptr<Led> led = std::make_shared<Led>();while(1){led1 = !led1;delay_ms(500);led->TurnOn(GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7, false);delay_ms(500);led->TurnOn(GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7, true);delay_ms(500);}return 0;
}

啊哈,好了,恭喜你成功成为一名光荣的点灯工程师。

单纯点灯

三、std::cout串口重定向

既然都用到c++了,那么这个特色的输出肯定不能放过,那么怎么使用它把信息通过串口输出到上位机上啊,别急,一步一步来,showtime!

1.先点击这个运行环境配置图标在这里插入图片描述
2.依次进入Compiler->I/O,将里面的都勾选上,其实也不用就勾选个STDOUT我感觉就可以了,当然勾上也没有什么影响,并将variant列依次选择如下图所示:
在这里插入图片描述
这里配置完成后,需要你在你自己的usart.h文件中实现

#ifdef __cplusplus
extern "C"
{
#endifint stdout_putchar(int ch);int stderr_putchar(int ch);
#ifdef __cplusplus
}
#endif

usart.cpp函数中实现

//标准输出流
int stdout_putchar(int ch)
{USART_SendData(USART1,(u8)ch);while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET){};return ch;
}标准错误流
int stderr_putchar(int ch)
{while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE)==RESET);return (int)USART_ReceiveData(USART1);
}

这样你就可以直接在main.cpp中调用函数了。这次点灯加上串口通信。

#include "system.h"int main(void)
{SysTick_Init(72);Init_Usart();std::shared_ptr<Led> led = std::make_shared<Led>();while(1){led1 = !led1;delay_ms(500);led->TurnOn(GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7, false);delay_ms(500);led->TurnOn(GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7, true);delay_ms(500);std::cout<<std::move("================Usart_Test=================")<<std::endl;}return 0;
}

这里多说几句,这c++在这里keil里边有些特性和标准的c++不太一样,这里的我就不过多阐述,待你们使用的时候自然就明白了。

打开你的串口调试助手就可以得到如下的信息。
在这里插入图片描述
哇哦,不仅现在点灯成功了,还玩明白了这个c++重定向串口输出了。

四、串口中断服务函数

那么接下来再试一试串口中断服务函数咋样?
这个有个坑哈,坑了我一天多,给我人搞麻木了,注意这个c++的编译后的中断服务函数代码和原来stm32库函数开发的中断向量表对不上,导致无法进入中断服务函数。
只需要在前面加上extern "C"即可链接原来stm32库函数中的中断服务函数了。
在这里插入图片描述
这里咱们上点强度,使用GM65二维码扫描器来和控制小灯的亮和灭。并把读取到的二维码数据上传到pc。这里串口收发数据频繁的话可以使用DMA功能,我这里就不做演示了,为啥?因为我这数据接收并不频繁,又不用去搞什么优化,摸摸鱼啦。都很简单随便找个教程看一看就行了。我就不写了。
usart.h

#ifndef __usart_H
#define __usart_H#include "system.h" //串口1
#define USART1_GPIO_PORT      GPIOA
#define USART1_GPIO_CLK       RCC_APB2Periph_GPIOA
#define USART1_TX_GPIO_PIN    GPIO_Pin_9
#define USART1_RX_GPIO_PIN    GPIO_Pin_10//串口2
#define USART2_GPIO_PORT      GPIOA
#define USART2_GPIO_CLK       RCC_APB2Periph_GPIOA
#define USART2_TX_GPIO_PIN    GPIO_Pin_2
#define USART2_RX_GPIO_PIN    GPIO_Pin_3#define BUFFER_SIZE 32 // 定义数组缓冲的最大长度#ifdef __cplusplus
extern "C"
{
#endifint stdout_putchar(int ch);int stderr_putchar(int ch);void usart_init(unsigned int baud);void usart_init2(unsigned int baud);void Init_Usart(void);void USART_Send_Byte(USART_TypeDef* USARTx, uint16_t Data);void USART_Send_String(USART_TypeDef* USARTx, char *str);
#ifdef __cplusplus
}
#endif
#endif

usart.cpp

#include "usart.h"		 bool RxState{0};
u8 uart2_len{0}; //数据长度,uart2_len+1加上帧尾u8 RxCounter{0};u8 RxBuffer[BUFFER_SIZE]{0};u16 check; //标准输出流
int stdout_putchar(int ch)
{USART_SendData(USART1,(u8)ch);while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET){};return ch;
}标准错误流
int stderr_putchar(int ch)
{while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE)==RESET);return (int)USART_ReceiveData(USART1);
}void usart_init(unsigned int baud)
{GPIO_InitTypeDef GPIO_Init_Structure;                            //定义GPIO结构体USART_InitTypeDef USART_Init_Structure;                          //定义串口结构体NVIC_InitTypeDef  NVIC_Init_Structure;														//定义中断结构体NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);RCC_APB2PeriphClockCmd(USART1_GPIO_CLK,  ENABLE);                 //开启GPIOA时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,  ENABLE);            //开启APB2总线复用时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,  ENABLE);          //开启USART1时钟//配置PA9  TXGPIO_Init_Structure.GPIO_Mode  = GPIO_Mode_AF_PP;                //复用推挽GPIO_Init_Structure.GPIO_Pin   = USART1_TX_GPIO_PIN;GPIO_Init_Structure.GPIO_Speed = GPIO_Speed_50MHz;    GPIO_Init( USART1_GPIO_PORT, &GPIO_Init_Structure);//配置PA10 RXGPIO_Init_Structure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;                //复用推挽GPIO_Init_Structure.GPIO_Pin   = USART1_RX_GPIO_PIN;GPIO_Init( USART1_GPIO_PORT, &GPIO_Init_Structure);//串口相关配置USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);																					//串口中断配置USART_Init_Structure.USART_BaudRate = baud;                                          //波特率设置为9600USART_Init_Structure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;       //硬件流控制为无USART_Init_Structure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;                       //模式设为收和发USART_Init_Structure.USART_Parity = USART_Parity_No;                                   //无校验位USART_Init_Structure.USART_StopBits = USART_StopBits_1;                                //一位停止位USART_Init_Structure.USART_WordLength = USART_WordLength_8b;                           //字长为8位   USART_Init(USART1, &USART_Init_Structure);                                             //初始化	USART_Cmd(USART1, ENABLE);                                                            //串口使能//中断结构体配置NVIC_Init_Structure.NVIC_IRQChannel 			=   USART1_IRQn;NVIC_Init_Structure.NVIC_IRQChannelCmd   	=   ENABLE;NVIC_Init_Structure.NVIC_IRQChannelPreemptionPriority  =  0;NVIC_Init_Structure.NVIC_IRQChannelSubPriority         =  1;NVIC_Init(&NVIC_Init_Structure);}void usart_init2(unsigned int baud)
{GPIO_InitTypeDef GPIO_Init_Structure;                            //定义GPIO结构体USART_InitTypeDef USART_Init_Structure;                          //定义串口结构体NVIC_InitTypeDef  NVIC_Init_Structure;														//定义中断结构体NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);RCC_APB2PeriphClockCmd(USART2_GPIO_CLK,  ENABLE);                 //开启GPIOA时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,  ENABLE);            //开启APB2总线复用时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,  ENABLE);          //开启USART1时钟//配置PA2 TXGPIO_Init_Structure.GPIO_Mode  = GPIO_Mode_AF_PP;                //复用推挽GPIO_Init_Structure.GPIO_Pin   = USART2_TX_GPIO_PIN;GPIO_Init_Structure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init( USART2_GPIO_PORT, &GPIO_Init_Structure);//配置PA3 RXGPIO_Init_Structure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;                //复用推挽GPIO_Init_Structure.GPIO_Pin   = USART2_RX_GPIO_PIN;GPIO_Init( USART2_GPIO_PORT, &GPIO_Init_Structure);USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);	USART_Init_Structure.USART_BaudRate = 9600;                                          //波特率设置为9600USART_Init_Structure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;       //硬件流控制为无USART_Init_Structure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;                       //模式设为收和发USART_Init_Structure.USART_Parity = USART_Parity_No;                                   //无校验位USART_Init_Structure.USART_StopBits = USART_StopBits_1;                                //一位停止位USART_Init_Structure.USART_WordLength = USART_WordLength_8b;                           //字长为8位  USART_Init(USART2, &USART_Init_Structure);  USART_Cmd(USART2, ENABLE);//中断结构体配置NVIC_Init_Structure.NVIC_IRQChannel 			=   USART2_IRQn;NVIC_Init_Structure.NVIC_IRQChannelCmd   	=   ENABLE;NVIC_Init_Structure.NVIC_IRQChannelPreemptionPriority  =  0;NVIC_Init_Structure.NVIC_IRQChannelSubPriority         =  3;NVIC_Init(&NVIC_Init_Structure);
}//二个串口初始化函数
void Init_Usart(void)
{usart_init(9600);usart_init2(9600);
}/*** 功能:串口写字节函数* 参数1:USARTx :串口号* 参数2:Data   :需写入的字节* 返回值:None*/
void USART_Send_Byte(USART_TypeDef* USARTx, uint16_t Data)
{USART_SendData(USARTx, Data);while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE)==RESET);
}
/*** 功能:串口写字符串函数* 参数1:USARTx :串口号* 参数2:str    :需写入的字符串* 返回值:None*/
void USART_Send_String(USART_TypeDef* USARTx, char *str)
{uint16_t i=0;do{USART_Send_Byte(USARTx,  *(str+i));i++;}while(*(str + i) != '\0');while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);
}/*
void USART1_IRQHandler(void)
{volatile char temp;if(USART_GetITStatus(USART1,USART_IT_RXNE)!= RESET){temp = USART_ReceiveData(USART1);USART_ClearITPendingBit(USART1,USART_IT_RXNE);	//清空标志位}
}
*/unsigned short CRC16_XMODEM(unsigned char *puchMsg, unsigned int usDataLen)
{unsigned short wCRCin = 0x0000;unsigned short wCPoly= 0x1021;unsigned char wChar = 0;while (usDataLen--){wChar = *(puchMsg++);//4,1 3,2 3,3, 1,4 1,5wCRCin ^=(wChar << 8);for(auto i = 0; i< 8; ++i){	if(wCRCin & 0x8000){wCRCin =(wCRCin << 1) ^ wCPoly;}else{wCRCin = wCRCin << 1;}}}return(wCRCin);    
} extern "C" void USART2_IRQHandler(void)    		 
{if( USART_GetITStatus(USART2,USART_IT_RXNE)!=RESET)  	   //接收中断  {USART_ClearITPendingBit(USART2,USART_IT_RXNE);   //清除中断标志RxBuffer[RxCounter++] = USART_ReceiveData(USART2);}if(RxBuffer[RxCounter-1]==13) //0x0D{uart2_len=RxCounter-1;check=CRC16_XMODEM(&RxBuffer[RxCounter],uart2_len+1);   //校验和(crc)if(((check&0x00ff)==RxBuffer[uart2_len+1])&&(((check>>8)&0x00ff)==RxBuffer[uart2_len+1])){RxState=1;		}}if(USART_GetFlagStatus(USART2,USART_FLAG_ORE) == SET) //判断中断是否溢出{ USART_ClearFlag(USART2,USART_FLAG_ORE); USART_ReceiveData(USART2); } if(RxState){//find_key(RxBuffer,"on");if(strstr((const char*)RxBuffer, "on")){GPIO_ResetBits(LED_PORT, GPIO_Pin_4);}if(strstr((const char*)RxBuffer, "off")){GPIO_SetBits(LED_PORT, GPIO_Pin_4);}for(auto x=0;x<uart2_len+1;++x){USART_SendData(USART1,RxBuffer[x]);delay_ms(10);}RxState=0;RxCounter=0;}
}

main.cpp

#include "system.h"int main(void)
{SysTick_Init(72);Init_Usart();std::shared_ptr<Led> led = std::make_shared<Led>();while(1){delay_ms(500);led->TurnOn(GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7, false);delay_ms(500);led->TurnOn(GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7, true);delay_ms(500);}return 0;
}

接下里就是编译调试了。什么都好就是胖了点,不过问题不大,有的是方法减肥,这里我就不逼逼了。好在ZET6 512k的存储容量,这小小100k,还不够。
在这里插入图片描述
把编译好的hex文件下载到单片机上,就可以观测到结果了。
在这里插入图片描述
简单的一个演示视频;

扫描点灯

使用的gm65我接的二号串口,GPIOC使用的5号口,具体的文件代码我会分享给大家。因为有些东西我这上边没有写,不够你拿到我这弄好的模板,操作之后的就好弄了。

五、结尾废话

说着是使用c++快乐的,为啥感觉没用到多少,其实正常的,代码量不够的话,其实写C更方便点,还有就是这里边使用c++11的感觉没那爽,不够还行勉强够用了,搞好c pulspuls以后软硬通吃就行,那不香香啊。

啊,
什么?
你问我?
代码在哪?
别急马上给。

相关文章:

keil5使用c++编写stm32控制程序

keil5使用c编写stm32控制程序 一、前言二、配置图解三、std::cout串口重定向四、串口中断服务函数五、结尾废话 一、前言 想着搞个新奇的玩意玩一玩来着&#xff0c;想用c编写代码来控制stm32&#xff0c;结果在keil5中&#xff0c;把踩给我踩闷了&#xff0c;这里简单记录一下…...

中国社科院与美国杜兰大学金融管理硕士项目——在职读研的日子里藏着我们未来无限可能

人生充满期待&#xff0c;梦想连接着未来。每一天都可以看作新的一页&#xff0c;要努力去成为最好的自己。在职读研的光阴里藏着无限的可能&#xff0c;只有不断的努力&#xff0c;不断的强大自己&#xff0c;未来会因为你的不懈坚持而发生改变&#xff0c;纵使眼前看不到希望…...

hardhat 本地连接matemask钱包

Hardhat 安装 https://hardhat.org/hardhat-runner/docs/getting-started#quick-start Running a Local Hardhat Network Hardhat greatly simplifies the process of setting up a local network by having an in-built local blockchain which can be easily run through a…...

【华为OD机试真题】1001 - 在字符串中找出连续最长的数字串含-号(Java C++ Python JS)| 机试题+算法思路+考点+代码解析

文章目录 一、题目🔸题目描述🔸输入输出二、代码参考🔸Java代码🔸 C++代码🔸 Python代码🔸 JS代码作者:KJ.JK🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🍂个人博客首页: KJ.JK 💖系列专栏:华为OD机试(Java C++ Python JS)...

CrackMapExec 域渗透工具使用

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、CrackMapExec 是什么&#xff1f;二、简单使用1、获取帮助信息2、smb连接执行命令3、使用winrm执行命令&#xff08;躲避杀软&#xff09;4、smb 协议常用枚…...

Modbus协议学习

以下内容从参考文章学习提炼 [参考文章](https://www.cnblogs.com/The-explosion/p/11512677.html) ## 基本概念 Modbus用的是主从通讯技术&#xff0c;主设备操作查询从设备。可以通过物理接口&#xff0c;可选用串口&#xff08;RS232、RS485、RS422&#xff09;&#xff0c…...

camunda如何处理流程待办任务

在 Camunda 中处理流程任务需要使用 Camunda 提供的 API 或者用户界面进行操作。以下是两种常用的处理流程任务的方式&#xff1a; 1、通过 Camunda 任务列表处理任务&#xff1a;在 Camunda 任务列表中&#xff0c;可以看到当前需要处理的任务&#xff0c;点击任务链接&#…...

git部分文件不想提交解决方案

正确的做法应该是&#xff1a;git rm --cached logs/xx.log&#xff0c;然后更新 .gitignore 忽略掉目标文件&#xff0c;最后 git commit -m "We really dont want Git to track this anymore!" 具体的原因如下&#xff1a; 被采纳的答案虽然能达到&#xff08;暂…...

2023年全国最新道路运输从业人员精选真题及答案58

百分百题库提供道路运输安全员考试试题、道路运输从业人员考试预测题、道路安全员考试真题、道路运输从业人员证考试题库等&#xff0c;提供在线做题刷题&#xff0c;在线模拟考试&#xff0c;助你考试轻松过关。 69.根据《公路水路行业安全生产风险管理暂行办法》&#xff0c;…...

Zimbra 远程代码执行漏洞(CVE-2019-9670)漏洞分析

Zimbra 远程代码执行漏洞(CVE-2019-9670)漏洞分析 漏洞简介 Zimbra是著名的开源系统&#xff0c;提供了一套开源协同办公套件包括WebMail&#xff0c;日历&#xff0c;通信录&#xff0c;Web文档管理和创作。一体化地提供了邮件收发、文件共享、协同办公、即时聊天等一系列解决…...

【数据结构初阶】第七节.树和二叉树的性质

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 前言 一、树 1.1 树的概念 1.2 树的结点分类 1.3 结点之间的关系 1.4 树的存储结构 1.5 其他相关概念 二、 二叉树 2.1 二叉树的概念 2.2 特殊的二叉树 2.3 二叉树的性质 2.4…...

车载软件架构——闲聊几句AUTOSAR BSW(一)

我是穿拖鞋的汉子,魔都中坚持长期主义的工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 人生是用来体验的,不是用来演绎完美的。我慢慢能接受自己身上那些灰暗的部分,原谅自己的迟钝和平庸,允许自己出错,允许自己偶尔断电,带着缺憾拼命绽放,…...

我国元宇宙行业分析:政策、技术、资金助推行业探索多元化应用场景

1.元宇宙行业概述、特征及产业链图解 元宇宙是人类运用数字技术构建的&#xff0c;由现实世界映射或超越现实世界&#xff0c;可与现实世界交互的虚拟世界&#xff0c;具备新型社会体系的数字生活空间&#xff0c;主要具有沉浸式体验、开放性、虚拟身份、不断演化、知识互动、…...

都已经那么卷了,用户还需要开源的 API 管理工具么

关于 API 管理工具&#xff0c;如今的市场已经把用户教育的差不多了&#xff0c;毫不夸张地说&#xff0c;如果我随机抽取一位幸运读者&#xff0c;他都能给我罗列出一二三四款大家耳熟能详的工具。可说到开源的 API 管理工具&#xff0c;大家又能知道多少呢&#xff1f; 我们是…...

工信部教育与考试中心-软件测试工程师考试题A卷-答

软件测试工程师考试题 姓名________________ 学号_________________ 班级__________________ 题号 一 二 三 四 五 总分 分数 说明&#xff1a;本试卷分五部分&#xff0c;全卷满分100分。考试用时100分钟。 注 意 事 项&#xff1a;1、本此考试为闭卷…...

【设计模式】模板方法模式--让你的代码更具灵活性与可扩展性

文章目录 前言模板方法模式的定义核心组成模板方法模式与其他设计模式的区别 代码实现抽象类具体类Client 经典类图spring中的例子 总结 前言 在软件开发中&#xff0c;设计模式是一种经过实践检验的、可复用的解决方案&#xff0c;它们可以帮助我们解决某一特定领域的典型问题…...

搞明白Redis持久化机制

Redis是一种内存数据库&#xff0c;其内存中的数据存储在计算机的内存中&#xff0c;如果服务器发生崩溃或者重启&#xff0c;内存中的数据将会丢失。为了避免这种情况发生&#xff0c;Redis提供了两种持久化机制&#xff1a;RDB和AOF。 一、RDB持久化 Redis支持将当前数据状…...

C# 中的正则表达式,如何使用正则表达式进行字符串匹配和替换?

在 C# 中&#xff0c;可以使用正则表达式进行字符串匹配和替换。正则表达式是一种用来描述字符串模式的语言&#xff0c;可以用来检查一个字符串是否符合某种模式&#xff0c;或者从字符串中提取符合某种模式的子串。下面我们介绍一些常用的正则表达式操作&#xff1a; 创建正…...

7年时间,从功能测试到测试开发月薪30K,有志者事竟成

突破自己的技术瓶颈并不是一蹴而就&#xff0c;还是需要看清楚一些东西&#xff0c;这里也有一些经验和见解跟大家分享一下。同样是职场人士&#xff0c;我也有我的经历和故事。在工作期间&#xff0c;我有过2年加薪5次的小小“战绩”&#xff08;同期进入公司的员工&#xff0…...

ES6 块级作用域

ES6之前没有块级作用域&#xff0c;ES5的var没有块级作用域的概念&#xff0c;只有function有作用域的概念&#xff0c;ES6的let、const引入了块级作用域。 ​ ES5之前if和for都没有作用域&#xff0c;所以很多时候需要使用function的作用域&#xff0c;比如闭包。 1.1.1 什么…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

#Uniapp篇:chrome调试unapp适配

chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器&#xff1a;Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

vulnyx Blogger writeup

信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面&#xff0c;gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress&#xff0c;说明目标所使用的cms是wordpress&#xff0c;访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...

为什么要创建 Vue 实例

核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...

深入理解Optional:处理空指针异常

1. 使用Optional处理可能为空的集合 在Java开发中&#xff0c;集合判空是一个常见但容易出错的场景。传统方式虽然可行&#xff0c;但存在一些潜在问题&#xff1a; // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...

API网关Kong的鉴权与限流:高并发场景下的核心实践

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言 在微服务架构中&#xff0c;API网关承担着流量调度、安全防护和协议转换的核心职责。作为云原生时代的代表性网关&#xff0c;Kong凭借其插件化架构…...

基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)

引言 在嵌入式系统中&#xff0c;用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例&#xff0c;介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单&#xff0c;执行相应操作&#xff0c;并提供平滑的滚动动画效果。 本文设计了一个…...