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

STM32开发printf函数支持

1、printf函数支持

1、避免使用半主机模式:两种方法:微库法、代码法
2、实现fputc函数:实现单个字符输出

2、半主机模式简介

用于 ARM 目标的一种机制,可将来自应用程序代码的输入/输出请求传送至运行调试器的主机
简单说:就是通过仿真器实现开发板在电脑上的输入和输出
一般我们:不使用半主机模式!!!

方法一:微库法
在魔术棒→Target选项卡,勾选:Use Micro LlB,即可避免半主机模式
在这里插入图片描述
方法二:代码法
1个预处理、2个定义、3个函数
1、#pragmaimport(__use_no_semihosting),确保不从C库中使用半主机函数
2,定义:_FILE结构体,避免HAL库某些情况下报错
3,定义:FILE__stdout,避免编译报错
4,实现:_ttywrch_sys_exit_sys_command_string等三个函数
在这里插入图片描述
AC5和AC6不使用半主机模式稍有差异,详见源码
在这里插入图片描述

3、C语言中printf函数输出流程

在这里插入图片描述

代码实现printf

usart.h

/******************************************************************************************************* @file        usart.h* @author      正点原子团队(ALIENTEK)* @version     V1.1* @date        2023-06-05* @brief       串口初始化代码(一般是串口1),支持printf* @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司***************************************************************************************************** @attention** 实验平台:正点原子 STM32F103开发板* 在线视频:www.yuanzige.com* 技术论坛:www.openedv.com* 公司网址:www.alientek.com* 购买地址:openedv.taobao.com** 修改说明* V1.0 20211103* 第一次发布* V1.1 20230605* 删除USART_UX_IRQHandler()函数的超时处理和修改HAL_UART_RxCpltCallback()******************************************************************************************************/#ifndef __USART_H
#define __USART_H#include "stdio.h"
#include "./SYSTEM/sys/sys.h"/******************************************************************************************/
/* 引脚 和 串口 定义 * 默认是针对USART1的.* 注意: 通过修改这几个宏定义,可以支持USART1~UART5任意一个串口.*/
#define USART_TX_GPIO_PORT                  GPIOA
#define USART_TX_GPIO_PIN                   GPIO_PIN_9
#define USART_TX_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)   /* PA口时钟使能 */#define USART_RX_GPIO_PORT                  GPIOA
#define USART_RX_GPIO_PIN                   GPIO_PIN_10
#define USART_RX_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)   /* PA口时钟使能 */#define USART_UX                            USART1
#define USART_UX_IRQn                       USART1_IRQn
#define USART_UX_IRQHandler                 USART1_IRQHandler
#define USART_UX_CLK_ENABLE()               do{ __HAL_RCC_USART1_CLK_ENABLE(); }while(0)  /* USART1 时钟使能 *//******************************************************************************************/#define USART_REC_LEN               200         /* 定义最大接收字节数 200 */
#define USART_EN_RX                 1           /* 使能(1)/禁止(0)串口1接收 */
#define RXBUFFERSIZE   1                        /* 缓存大小 */extern UART_HandleTypeDef g_uart1_handle;       /* HAL UART句柄 */extern uint8_t  g_usart_rx_buf[USART_REC_LEN];  /* 接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 */
extern uint16_t g_usart_rx_sta;                 /* 接收状态标记 */
extern uint8_t g_rx_buffer[RXBUFFERSIZE];       /* HAL库USART接收Buffer */void usart_init(uint32_t bound);                /* 串口初始化函数 */#endif

usart.c

/******************************************************************************************************* @file        usart.c* @author      正点原子团队(ALIENTEK)* @version     V1.1* @date        2023-06-05* @brief       串口初始化代码(一般是串口1),支持printf* @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司***************************************************************************************************** @attention** 实验平台:正点原子 STM32F103开发板* 在线视频:www.yuanzige.com* 技术论坛:www.openedv.com* 公司网址:www.alientek.com* 购买地址:openedv.taobao.com** 修改说明* V1.0 20211103* 第一次发布* V1.1 20230605* 删除USART_UX_IRQHandler()函数的超时处理和修改HAL_UART_RxCpltCallback()******************************************************************************************************/#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"/* 如果使用os,则包括下面的头文件即可. */
#if SYS_SUPPORT_OS
#include "os.h" /* os 使用 */
#endif/******************************************************************************************/
/* 加入以下代码, 支持printf函数, 而不需要选择use MicroLIB */#if 1#if (__ARMCC_VERSION >= 6010050)            /* 使用AC6编译器时 */
__asm(".global __use_no_semihosting\n\t");  /* 声明不使用半主机模式 */
__asm(".global __ARM_use_no_argv \n\t");    /* AC6下需要声明main函数为无参数格式,否则部分例程可能出现半主机模式 */#else
/* 使用AC5编译器时, 要在这里定义__FILE 和 不使用半主机模式 */
#pragma import(__use_no_semihosting)struct __FILE
{int handle;/* Whatever you require here. If the only file you are using is *//* standard output using printf() for debugging, no file handling *//* is required. */
};#endif/* 不使用半主机模式,至少需要重定义_ttywrch\_sys_exit\_sys_command_string函数,以同时兼容AC6和AC5模式 */
int _ttywrch(int ch)
{ch = ch;return ch;
}/* 定义_sys_exit()以避免使用半主机模式 */
void _sys_exit(int x)
{x = x;
}char *_sys_command_string(char *cmd, int len)
{return NULL;
}/* FILE 在 stdio.h里面定义. */
FILE __stdout;/* MDK下需要重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 */
int fputc(int ch, FILE *f)
{while ((USART_UX->SR & 0X40) == 0);     /* 等待上一个字符发送完成 */USART_UX->DR = (uint8_t)ch;             /* 将要发送的字符 ch 写入到DR寄存器 */return ch;
}
#endif
/******************************************************************************************/#if USART_EN_RX /*如果使能了接收*//* 接收缓冲, 最大USART_REC_LEN个字节. */
uint8_t g_usart_rx_buf[USART_REC_LEN];/*  接收状态*  bit15,      接收完成标志*  bit14,      接收到0x0d*  bit13~0,    接收到的有效字节数目
*/
uint16_t g_usart_rx_sta = 0;uint8_t g_rx_buffer[RXBUFFERSIZE];  /* HAL库使用的串口接收缓冲 */UART_HandleTypeDef g_uart1_handle;  /* UART句柄 *//*** @brief       串口X初始化函数* @param       baudrate: 波特率, 根据自己需要设置波特率值* @note        注意: 必须设置正确的时钟源, 否则串口波特率就会设置异常.*              这里的USART的时钟源在sys_stm32_clock_init()函数中已经设置过了.* @retval      无*/
void usart_init(uint32_t baudrate)
{/*UART 初始化设置*/g_uart1_handle.Instance = USART_UX;                                       /* USART_UX */g_uart1_handle.Init.BaudRate = baudrate;                                  /* 波特率 */g_uart1_handle.Init.WordLength = UART_WORDLENGTH_8B;                      /* 字长为8位数据格式 */g_uart1_handle.Init.StopBits = UART_STOPBITS_1;                           /* 一个停止位 */g_uart1_handle.Init.Parity = UART_PARITY_NONE;                            /* 无奇偶校验位 */g_uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;                      /* 无硬件流控 */g_uart1_handle.Init.Mode = UART_MODE_TX_RX;                               /* 收发模式 */HAL_UART_Init(&g_uart1_handle);                                           /* HAL_UART_Init()会使能UART1 *//* 该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 */HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE); 
}/*** @brief       UART底层初始化函数* @param       huart: UART句柄类型指针* @note        此函数会被HAL_UART_Init()调用*              完成时钟使能,引脚配置,中断配置* @retval      无*/
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{GPIO_InitTypeDef gpio_init_struct;if (huart->Instance == USART_UX)                            /* 如果是串口1,进行串口1 MSP初始化 */{USART_TX_GPIO_CLK_ENABLE();                             /* 使能串口TX脚时钟 */USART_RX_GPIO_CLK_ENABLE();                             /* 使能串口RX脚时钟 */USART_UX_CLK_ENABLE();                                  /* 使能串口时钟 */gpio_init_struct.Pin = USART_TX_GPIO_PIN;               /* 串口发送引脚号 */gpio_init_struct.Mode = GPIO_MODE_AF_PP;                /* 复用推挽输出 */gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* IO速度设置为高速 */HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init_struct);gpio_init_struct.Pin = USART_RX_GPIO_PIN;               /* 串口RX脚 模式设置 */gpio_init_struct.Mode = GPIO_MODE_AF_INPUT;    HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct);   /* 串口RX脚 必须设置成输入模式 */#if USART_EN_RXHAL_NVIC_EnableIRQ(USART_UX_IRQn);                      /* 使能USART1中断通道 */HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3);              /* 组2,最低优先级:抢占优先级3,子优先级3 */
#endif}
}/*** @brief       串口数据接收回调函数数据处理在这里进行* @param       huart:串口句柄* @retval      无*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if (huart->Instance == USART_UX)                    /* 如果是串口1 */{if ((g_usart_rx_sta & 0x8000) == 0)             /* 接收未完成 */{if (g_usart_rx_sta & 0x4000)                /* 接收到了0x0d(即回车键) */{if (g_rx_buffer[0] != 0x0a)             /* 接收到的不是0x0a(即不是换行键) */{g_usart_rx_sta = 0;                 /* 接收错误,重新开始 */}else                                    /* 接收到的是0x0a(即换行键) */{g_usart_rx_sta |= 0x8000;           /* 接收完成了 */}}else                                        /* 还没收到0X0d(即回车键) */{if (g_rx_buffer[0] == 0x0d)g_usart_rx_sta |= 0x4000;else{g_usart_rx_buf[g_usart_rx_sta & 0X3FFF] = g_rx_buffer[0];g_usart_rx_sta++;if (g_usart_rx_sta > (USART_REC_LEN - 1)){g_usart_rx_sta = 0;             /* 接收数据错误,重新开始接收 */}}}}HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);}
}/*** @brief       串口1中断服务函数* @param       无* @retval      无*/
void USART_UX_IRQHandler(void)
{
#if SYS_SUPPORT_OS                          /* 使用OS */OSIntEnter();    
#endifHAL_UART_IRQHandler(&g_uart1_handle);   /* 调用HAL库中断处理公用函数 */#if SYS_SUPPORT_OS                          /* 使用OS */OSIntExit();
#endif}#endif

解析:
1、重定义fputc函数(单字符输出函数), printf函数最终会通过调用fputc输出字符串到串口

/* MDK下需要重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 */
int fputc(int ch, FILE *f)
{while ((USART_UX->SR & 0X40) == 0);     /* 等待上一个字符发送完成 */USART_UX->DR = (uint8_t)ch;             /* 将要发送的字符 ch 写入到DR寄存器 */return ch;
}

1、USART_UX->SR就是状态寄存器USART_SR,这个寄存器的第6位变为1的时候表示这一帧发送完成,第6位为0的时候表示这一帧还未发送完成,表示当前的这个字符发送成功没有
在这里插入图片描述

while ((USART_UX->SR & 0X40) == 0);     /* 等待上一个字符发送完成 */

2、USART_UX->DR就是数据寄存器,将数据写入这个寄存器,然后串口将这个寄存器的数据发送出去

USART_UX->DR = (uint8_t)ch;             /* 将要发送的字符 ch 写入到DR寄存器 

3、屏蔽掉状态寄存器监测,会是啥样的
在这里插入图片描述
会出现乱码,因为printf是发送字符串,fputc是发送单个字符,如果不检测状态寄存器,printf会一直调用fputc,这是fputc中的数据一直变化,无法正确发出去

微库法实现

usart.c

/******************************************************************************************************* @file        usart.c* @author      正点原子团队(ALIENTEK)* @version     V1.1* @date        2023-06-05* @brief       串口初始化代码(一般是串口1),支持printf* @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司***************************************************************************************************** @attention** 实验平台:正点原子 STM32F103开发板* 在线视频:www.yuanzige.com* 技术论坛:www.openedv.com* 公司网址:www.alientek.com* 购买地址:openedv.taobao.com** 修改说明* V1.0 20211103* 第一次发布* V1.1 20230605* 删除USART_UX_IRQHandler()函数的超时处理和修改HAL_UART_RxCpltCallback()******************************************************************************************************/#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"/* 如果使用os,则包括下面的头文件即可. */
#if SYS_SUPPORT_OS
#include "os.h" /* os 使用 */
#endif/******************************************************************************************/
/* 加入以下代码, 支持printf函数, 而不需要选择use MicroLIB */#if 1// #if (__ARMCC_VERSION >= 6010050)            /* 使用AC6编译器时 */
// __asm(".global __use_no_semihosting\n\t");  /* 声明不使用半主机模式 */
// __asm(".global __ARM_use_no_argv \n\t");    /* AC6下需要声明main函数为无参数格式,否则部分例程可能出现半主机模式 */// #else
// /* 使用AC5编译器时, 要在这里定义__FILE 和 不使用半主机模式 */
// #pragma import(__use_no_semihosting)// struct __FILE
// {
//     int handle;
//     /* Whatever you require here. If the only file you are using is */
//     /* standard output using printf() for debugging, no file handling */
//     /* is required. */
// };// #endif// /* 不使用半主机模式,至少需要重定义_ttywrch\_sys_exit\_sys_command_string函数,以同时兼容AC6和AC5模式 */
// int _ttywrch(int ch)
// {
//     ch = ch;
//     return ch;
// }// /* 定义_sys_exit()以避免使用半主机模式 */
// void _sys_exit(int x)
// {
//     x = x;
// }// char *_sys_command_string(char *cmd, int len)
// {
//     return NULL;
// }// /* FILE 在 stdio.h里面定义. */
// FILE __stdout;/* MDK下需要重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 */
int fputc(int ch, FILE *f)
{while ((USART_UX->SR & 0X40) == 0);     /* 等待上一个字符发送完成 */USART_UX->DR = (uint8_t)ch;             /* 将要发送的字符 ch 写入到DR寄存器 */return ch;
}
#endif
/******************************************************************************************/#if USART_EN_RX /*如果使能了接收*//* 接收缓冲, 最大USART_REC_LEN个字节. */
uint8_t g_usart_rx_buf[USART_REC_LEN];/*  接收状态*  bit15,      接收完成标志*  bit14,      接收到0x0d*  bit13~0,    接收到的有效字节数目
*/
uint16_t g_usart_rx_sta = 0;uint8_t g_rx_buffer[RXBUFFERSIZE];  /* HAL库使用的串口接收缓冲 */UART_HandleTypeDef g_uart1_handle;  /* UART句柄 *//*** @brief       串口X初始化函数* @param       baudrate: 波特率, 根据自己需要设置波特率值* @note        注意: 必须设置正确的时钟源, 否则串口波特率就会设置异常.*              这里的USART的时钟源在sys_stm32_clock_init()函数中已经设置过了.* @retval      无*/
void usart_init(uint32_t baudrate)
{/*UART 初始化设置*/g_uart1_handle.Instance = USART_UX;                                       /* USART_UX */g_uart1_handle.Init.BaudRate = baudrate;                                  /* 波特率 */g_uart1_handle.Init.WordLength = UART_WORDLENGTH_8B;                      /* 字长为8位数据格式 */g_uart1_handle.Init.StopBits = UART_STOPBITS_1;                           /* 一个停止位 */g_uart1_handle.Init.Parity = UART_PARITY_NONE;                            /* 无奇偶校验位 */g_uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;                      /* 无硬件流控 */g_uart1_handle.Init.Mode = UART_MODE_TX_RX;                               /* 收发模式 */HAL_UART_Init(&g_uart1_handle);                                           /* HAL_UART_Init()会使能UART1 *//* 该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 */HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE); 
}/*** @brief       UART底层初始化函数* @param       huart: UART句柄类型指针* @note        此函数会被HAL_UART_Init()调用*              完成时钟使能,引脚配置,中断配置* @retval      无*/
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{GPIO_InitTypeDef gpio_init_struct;if (huart->Instance == USART_UX)                            /* 如果是串口1,进行串口1 MSP初始化 */{USART_TX_GPIO_CLK_ENABLE();                             /* 使能串口TX脚时钟 */USART_RX_GPIO_CLK_ENABLE();                             /* 使能串口RX脚时钟 */USART_UX_CLK_ENABLE();                                  /* 使能串口时钟 */gpio_init_struct.Pin = USART_TX_GPIO_PIN;               /* 串口发送引脚号 */gpio_init_struct.Mode = GPIO_MODE_AF_PP;                /* 复用推挽输出 */gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* IO速度设置为高速 */HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init_struct);gpio_init_struct.Pin = USART_RX_GPIO_PIN;               /* 串口RX脚 模式设置 */gpio_init_struct.Mode = GPIO_MODE_AF_INPUT;    HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct);   /* 串口RX脚 必须设置成输入模式 */#if USART_EN_RXHAL_NVIC_EnableIRQ(USART_UX_IRQn);                      /* 使能USART1中断通道 */HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3);              /* 组2,最低优先级:抢占优先级3,子优先级3 */
#endif}
}/*** @brief       串口数据接收回调函数数据处理在这里进行* @param       huart:串口句柄* @retval      无*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if (huart->Instance == USART_UX)                    /* 如果是串口1 */{if ((g_usart_rx_sta & 0x8000) == 0)             /* 接收未完成 */{if (g_usart_rx_sta & 0x4000)                /* 接收到了0x0d(即回车键) */{if (g_rx_buffer[0] != 0x0a)             /* 接收到的不是0x0a(即不是换行键) */{g_usart_rx_sta = 0;                 /* 接收错误,重新开始 */}else                                    /* 接收到的是0x0a(即换行键) */{g_usart_rx_sta |= 0x8000;           /* 接收完成了 */}}else                                        /* 还没收到0X0d(即回车键) */{if (g_rx_buffer[0] == 0x0d)g_usart_rx_sta |= 0x4000;else{g_usart_rx_buf[g_usart_rx_sta & 0X3FFF] = g_rx_buffer[0];g_usart_rx_sta++;if (g_usart_rx_sta > (USART_REC_LEN - 1)){g_usart_rx_sta = 0;             /* 接收数据错误,重新开始接收 */}}}}HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);}
}/*** @brief       串口1中断服务函数* @param       无* @retval      无*/
void USART_UX_IRQHandler(void)
{
#if SYS_SUPPORT_OS                          /* 使用OS */OSIntEnter();    
#endifHAL_UART_IRQHandler(&g_uart1_handle);   /* 调用HAL库中断处理公用函数 */#if SYS_SUPPORT_OS                          /* 使用OS */OSIntExit();
#endif}#endif

屏蔽掉代码法实现的部分,然后设置Use MicroLIB
在这里插入图片描述

相关文章:

STM32开发printf函数支持

1、printf函数支持 1、避免使用半主机模式:两种方法:微库法、代码法 2、实现fputc函数:实现单个字符输出 2、半主机模式简介 用于 ARM 目标的一种机制,可将来自应用程序代码的输入/输出请求传送至运行调试器的主机 简单说:就是通过仿真器实…...

解决 Chrome 与 Chromedriver 版本不一致问题的方法

目录 常见错误处理 处理方案: 1. 自动版本匹配方法 使用 webdriver-manager 库(推荐) 2. 手动版本管理方法 检查并匹配版本 3. 版本兼容性解决方案 使用兼容性表 4. 自动更新策略 定期检查更新脚本 5. Docker 容器化方案 最佳实践建…...

CPU的基本认识

为大家介绍CPU的基本概念,例如:CPU的型号认识、什么是时钟周期、物理核和逻辑核、缓存、TLB缓存的概念,可以帮助大家对cpu有个概念性的认识,选择电脑的时候可以看懂CPU的参数和理解基本原理。 CPU的基本认识 个人CPU型号介绍工作频…...

UGUI如何使用EventTrigger

前言 在 Unity 的 UGUI 系统中,EventTrigger 是一个强大的组件,允许开发者监听和处理多种 UI 交互事件。以下是详细的使用方法、示例代码、优缺点分析以及注意事项。 一、EventTrigger 基本用法 1. 添加 EventTrigger 组件 在 Unity 编辑器中选中 UI 对象(如 But…...

101alpha_第4个

(-1 * ts_rank(rank(low), 9)) 这里的low是每日的最低价。 各函数及整体含义解释 1. rank(low) 在金融分析场景里,low 通常代表股票在每个交易日中的最低价。rank(low) 会对一段时间内的最低价数据进行排序,并为每个数据赋予一个排名。比如,…...

5月13日观测云发布会:这一次,我们不只是发布产品

01|为什么举办这场发布会? 在生成式 AI 席卷一切、业务系统愈发复杂的时代,我们发现: 传统的监控观测已经无法满足企业对性能、安全、智能的统一诉求;每一个企业,都在经历从“看得到”到“看得懂”的跃迁&…...

【IP101】图像分割技术全解析:从传统算法到深度学习的进阶之路

图像分割详解 ✂️ 欢迎来到图像处理的"手术室"!在这里,我们将学习如何像外科医生一样精准地"切割"图像。让我们一起探索这个神奇的图像"手术"世界吧!🏥 目录 📑 1. 图像分割简介2. 阈…...

华为设备链路聚合实验:网络工程实战指南

链路聚合就像为网络搭建 “并行高速路”,既能扩容带宽,又能保障链路冗余,超实用! 一、实验拓扑速览 图中两台交换机 LSW1 和 LSW2,PC1、PC2 归属 VLAN 10,PC3 归属 VLAN 30。LSW1 与 LSW2 通过 GE0/0/1、…...

C24-数组

数组的引入:方便对同一类型的数据进行管理(一个班级里的45个同学、一个篮子里的12个苹果)数组的定义: 数据类型 数组名[常量表达式(也就是元素的个数)];int a[10]; //这里定义了一个能存放10个元素的整形数组数组初始化 完全初始化 int arr[3]{5,6,8};部分初始化 int arr[10]{…...

Vue 项目中长按保存图片功能实现指南

在移动互联网应用中,用户常常有保存页面特定内容为图片的需求,比如保存二维码、海报等。在 Vue 项目开发中,如何实现长按保存图片的功能?本文将结合具体代码,详细讲解在 Vue 项目中通过长按操作保存图片的技术实现与应…...

行业先锋:六款产品的实战表现

行业先锋:六款产品的实战表现  北京先智先行科技有限公司,销售着“先知大模型”、“先行AI商学院”“先知AIGC超级工场”这三个旗舰产品,在行业内崭露头角。旗下的先知A1、先知大模型等更是备受关注。  先知大模型,作为核心产…...

RS485与Profibus网关自由口数据互换技巧

RS485与Profibus网关自由口数据互换技巧 兴达易控RS485转Profibus网关在自由口模式下的数据互换,是工业自动化领域内一项关键的技术应用,它实现了不同通信协议设备之间的有效连接与数据交换。在现代工业生产中,众多设备和系统往往采用不同的…...

java复杂度,包装类,泛型解析

如何衡量代码的好坏? 评价代码的好坏我们使用算法效率来判断,而算法效率分两种: 算法效率: 第一种是时间效率,第二种是空间效率,时间效率被称为时间复杂度,⽽空间效率被称作空间复杂度。 时间…...

K8S安装部署(v1.27.6)

一、机器配置 系统版本主机名IP基于服务centos 7.9k8s-master192.168.163.104dockerk8s-node1192.168.163.105k8s-node2192.168.163.106注:以上3台机器都是2C4G的虚拟机,仅供测试使用 docker部署可以参考:docker 部署 二、其他环境配置 #1、关闭防火墙 systemctl stop fir…...

Debezium BinaryLogClient详解

Debezium BinaryLogClient详解 1. 类的作用与功能 1.1 核心作用 BinaryLogClient是Debezium中负责与MySQL服务器建立和维护Binlog连接的核心类,主要功能包括: 连接管理:建立和维护与MySQL服务器的Binlog连接事件监听:接收和处理Binlog事件心跳保活:维护连接活跃状态断线…...

Leetcode 刷题记录 09 —— 链表第三弹

本系列为笔者的 Leetcode 刷题记录,顺序为 Hot 100 题官方顺序,根据标签命名,记录笔者总结的做题思路,附部分代码解释和疑问解答,01~07为C语言,08及以后为Java语言。 01 合并 K 个升序链表 /*** Definitio…...

加速项目落地(Trae编辑器)

目录 vscode安装python支持 vscode常用插件 Trae编辑器 两个界面合成 补充(QT开发的繁琐) AI编程哪家强?Cursor、Trae深度对比,超详细! - 知乎 Trae兼容vscode的插件,我们可以先在vscode里面装好再一…...

vue3的页面跳转方法汇总(路由跳转,组件跳转)

1.组件跳转 使用router-link组件进行组件导航&#xff08;无需引入该组件&#xff0c;可直接使用&#xff09;&#xff0c;to后面跟组件路由。如果想要在当前页显示跳转的组件&#xff0c;可以通过<router-view>来显示当前路由匹配到的组件&#xff0c;也可以不使用<r…...

C++回顾 Day5

自实现string完整版 my_string.h using namespace std; class mystr{public://mystr();mystr(const char * new_str nullptr);mystr(const mystr & another);char * c_str();~mystr();mystr& operator(const mystr & another);mystr operator(const mystr &…...

OpenMVS 的编译与运行

Title: OpenMVS 的编译与运行 文章目录 I. 编译与准备1. 获得源码2. wiki3. 退出 Conda 环境4. 编译5. 数据准备 II. 命令了解1. 稠密重建 DensifyPointCloud2. 曲面重建 ReconstructMesh3. 网格优化 RefineMesh4. 纹理贴图 TextureMesh III. 命令运行1. 运行稠密重建2. 运行网…...

@Transactional注解的使用

目录 一.介绍 1.使用Transactional注解的位置 2.Transactional注解的作用 二.举例 1.需求场景 2.做法 3.效果展示 三.简单总结 一.介绍 1.使用Transactional注解的位置 我们在Java开发中&#xff0c;一般在service层的方法上&#xff0c;使用Transactional注解&#x…...

路由器NAT回流踩坑

路由器 H3C GR-3000AX-U 不支持NAT回流 核心问题定位 外网访问 ✅ 非Docker服务&#xff08;直接运行在宿主机上的服务&#xff09;可以访问❌ Docker服务 无法访问 内网访问 ✅ 内网IP访问&#xff08;无论Docker还是非Docker&#xff09;正常❌ 内网通过公网IP访问 全部失败…...

如何创建RDD

创建RDD&#xff08;Resilient Distributed Dataset&#xff09;主要有以下三种方法&#xff1a; 1. 从集合创建RDD 通过将本地集合&#xff08;如列表、数组&#xff09;传递给SparkContext的parallelize方法&#xff0c;可以将本地数据转换为RDD。这种方式通常用于测试或开…...

PTS-G5K13M RF Generator 5kW / 13MHz 射频电源User s Manual

PTS-G5K13M RF Generator 5kW / 13MHz 射频电源User s Manual...

vue3父组件调用子组件方法

需求&#xff1a;在vue3中需要在父组件调用子组件的方法 思路&#xff1a;通过ref和defineExpose直接暴露给父组件 1.子组件暴露表单验证方法 <template><a-form ref"formRef" :model"formState" :rules"rules"><a-form-item …...

Python小酷库系列:5个常用的dict属性化访问扩展库

5个常用的dict属性化访问扩展库 嵌套结构高级功能性能综合建议 在前面我们详细讲解了 Box和 Munch这两个dict属性化访问的扩展库&#xff0c;总体而言它们主要用于提升配置文件数据、JSON对象数据的可读性&#xff0c;减少了代码中双引号。在这一领域中还有dotmap、addict 和…...

day009-用户管理专题

文章目录 1. 创建包含时间的文件2. 与用户相关的文件3. 用户分类4. 与用户相关的命令4.1 添加用户4.2 删除用户4.3 查看用户4.4 修改用户密码 5. sudo6. 思维导图7. 老男孩思想-学习方法 1. 创建包含时间的文件 或$()是替换符号&#xff0c;可以将命令的结果作为字符串或变量的…...

微信小程序pinia的应用

情景&#xff1a;院校列表的关注状态的实时更新 新建一个ts文件存储关注状态&#xff0c;用于集中管理用户“已关注院校”的相关状态和操作 import {definStore} from pinia; import type { College_records } from /types/university;export const useFocusCollegeStore de…...

LWIP的超时事件笔记

那个马蜂佬&#xff0c;刚发就给我两个赞 lwIP超时事件处理简介 为每个与外界网络连接的任务都设定了timeout属性&#xff0c;即等待超时时间&#xff0c;例如TCP建立连接超时、ARP缓存表项的时间管理等&#xff0c;都需要超时操作来处理 lwIP超时事件机制 一共有四种 2.1&a…...

如何避免项目结束后知识流失

避免项目结束后知识流失的方法包括&#xff1a;建立项目知识库、实施定期知识回顾与总结、强化团队内部知识共享机制、利用合适的知识管理工具。项目知识库的建设尤其关键&#xff0c;它可帮助团队保留核心经验和方法&#xff0c;确保知识沉淀在组织内部。通过知识库&#xff0…...

【MCP】客户端配置(ollama安装、qwen2.5:0.5b模型安装、cherry-studio安装配置)

【MCP】客户端配置&#xff08;ollama安装、qwen2.5:0.5b模型安装、cherry-studio安装配置&#xff09; 客户端配置&#xff08;1&#xff09;下载安装ollama&#xff08;2&#xff09;安装qwen2.5:0.5b模型&#xff08;3&#xff09;安装配置cherry-studio 客户端配置 &#…...

Media3 中 Window 的时间相关属性详解

AndroidX Media3 的 Timeline.Window 类中&#xff0c;与时间相关的属性描述了媒体播放窗口&#xff08;window&#xff09;在时间维度上的关键信息。这些属性帮助开发者理解媒体的播放范围、起始点、持续时间以及与设备时间或直播流的同步关系。 Timeline.Window 的时间相关属…...

C 语言编码规范

在 C 语言开发过程中&#xff0c;遵循编码规范不仅能提高代码的可读性、可维护性&#xff0c;还能减少潜在的错误&#xff0c;提升团队协作效率。以下从多个维度详细阐述 C 语言编码过程中需要注意的规范要点。 一、命名规范 变量命名 变量命名应做到见名知意&#xff0c;采用…...

嵌入式开发学习日志Day15

一、指针指向字符型数组 &#xff08;1&#xff09;【const】&#xff1a;在指针变量中使用时&#xff0c;无法通过该指针修改被指向的变量&#xff1b; &#xff08;2&#xff09;【const】&#xff1a;关键字&#xff0c;在C和C中&#xff0c;能加就加&#xff0c;加了一定…...

从人脸扫描到实时驱动,超写实数字分身技术解析

在元宇宙浪潮中&#xff0c;数字人、虚拟数字人等新兴概念逐渐走进大众视野&#xff0c;其中数字分身作为虚拟数字人的细分领域&#xff0c;正引发广泛关注。数字分身依托人工智能与虚拟现实技术&#xff0c;能基于真人信息进行1:1复刻&#xff0c;具备与真人高度相似的外貌、声…...

Vue3 自定义指令的原理,以及应用

文章目录 前言一、原理说明二、注册与使用1. 全局注册2. 局部注册3. 使用方式 三、典型应用场景四、案例&#xff1a;权限控制指令五、注意事项 v-draggable✅ 目标效果&#xff1a;&#x1f9e9; 1. 自定义指令定义&#x1f9f1; 2. 在项目中注册&#x1f9ea; 3. 使用示例&am…...

306.检查是否所有A都在B之前

2124. 检查是否所有 A 都在 B 之前 - 力扣&#xff08;LeetCode&#xff09; class Solution {public boolean checkString(String s) {return !s.contains("ba");} } class Solution(object):def checkString(self, s):return s.find("ba")-1...

适合java程序员的Kafka消息中间件实战

创作的初心&#xff1a; 我们在学习kafka时&#xff0c;都是基于大数据的开发而进行的讲解&#xff0c;这篇文章为java程序员为核心&#xff0c;助力大家掌握kafka实现。 什么是kafka: 历史&#xff1a; 诞生与开源&#xff08;2010 - 2011 年&#xff09; 2010 年&#xf…...

当体育数据API遇上WebSocket:一场技术互补的「攻防战」

在世界杯决赛的最后一分钟&#xff0c;你正通过手机观看直播。突然&#xff0c;解说员大喊“球进了&#xff01;”&#xff0c;但你的屏幕却卡在对方半场的回放画面——这种「延迟乌龙」的尴尬&#xff0c;正是实时体育应用面临的终极挑战。 在体育数字化浪潮下&#xff0c;用…...

1:点云处理—三种显示方法(自建点云)

1.彩色显示 *读取三维点云 dev_get_window(WindowHandle)dev_open_window(0, 0, 512, 512, black, WindowHandle1) read_object_model_3d(./19-12-26/t.ply, m, [], [], ObjectModel3D, Status)Instructions[0] : Rotate: Left button Instructions[1] : Zoom: Shift left…...

SCADA|KingSCADA运行报错:加载实时库服务失败

哈喽,你好啊,我是雷工! 最近在绵阳出差,在现场调试时遇到报错问题,翻了下以往记录没有该错误的相关笔记。 于是将问题过程及处理办法记录下来。 01 问题描述 昨天还好好的,可以正常运行的程序今天再次运行时报错: “加载 实时库服务 失败” 查看日志中错误信息如下: …...

k8s | Kubernetes 服务暴露:NodePort、Ingress 与 YAML 配置详解

CodingTechWork 引言 在 Kubernetes 集群中&#xff0c;服务暴露是将集群内部的服务对外部网络提供访问的关键环节。NodePort 和 Ingress 是两种常用的服务暴露方式&#xff0c;它们各有特点和适用场景。本文将详细介绍这两种方式的原理、配置方法以及如何通过 YAML 文件实现服…...

upload-labs靶场通关详解:第一关

一、一句话木马准备 新建一个文本文档&#xff0c;写入php代码&#xff0c;修改文件后缀名为php&#xff0c;保存。 phpinfo() 是 PHP 里的一个内置函数&#xff0c;其功能是输出关于当前 PHP 环境的详细信息。这些信息涵盖 PHP 版本、服务器配置、编译选项、PHP 扩展、环境变…...

SSA-CNN+NSGAII+熵权TOPSIS,附相关气泡图!

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 经典麻雀搜索算法深度学习多目标优化多属性决策&#xff01;SSA-CNNNSGAII熵权TOPSIS&#xff0c;附相关气泡图&#xff01;本文旨在通过优化卷积神经网络&#xff08;CNN&#xff09;以及采用NSGAII多目标优化与熵权…...

数据结构之栈与队列

一&#xff0c;栈和队列的区别 1、核心定义与特性 特性栈&#xff08;Stack&#xff09;队列&#xff08;Queue&#xff09;定义仅允许在栈顶&#xff08;表尾&#xff09;进行插入和删除的线性表&#xff0c;遵循 后进先出&#xff08;LIFO&#xff09;。允许在队尾插入、队…...

SSHv2 密钥交换(Key Exchange)详解

1. 算法协商 在密钥交换开始前&#xff0c;客户端和服务端会协商确定本次会话使用的算法组合。具体过程如下&#xff1a; 交换算法列表 客户端和服务端各自发送支持的算法列表&#xff0c;包括&#xff1a; 密钥交换算法&#xff08;如 diffie-hellman-group14-sha256&#xf…...

从零开始学习three.js(15):一文详解three.js中的纹理映射UV

1. UV 映射基础概念 1.1 什么是 UV 坐标&#xff1f; 在三维计算机图形学中&#xff0c;UV 坐标是将二维纹理映射到三维模型表面的坐标系统。UV 中的 U 和 V 分别代表2D纹理空间的水平&#xff08;X&#xff09;和垂直&#xff08;Y&#xff09;坐标轴&#xff0c;与三维空间…...

解锁 Postgres 扩展日!与瀚高共探 C/Java 跨语言扩展技术的边界与未来

2025 年 5 月 13 日至 16 日&#xff08;蒙特利尔时间&#xff09;&#xff0c;一年一度的 PostgreSQL 开发者大会 PGConf.dev&#xff08;原 PGCON 会议&#xff09;将在加拿大蒙特利尔盛大举行。同去年一样&#xff0c;在本次大会开幕的前一天同样会举办另外一个专场活动——…...

【Hive入门】Hive增量数据导入:基于Sqoop的关系型数据库同步方案深度解析

目录 引言 1 增量数据导入概述 1.1 增量同步与全量同步对比 1.2 增量同步技术选型矩阵 2 Sqoop增量导入原理剖析 2.1 Sqoop架构设计 2.2 增量同步核心机制 3 Sqoop增量模式详解 3.1 append模式&#xff08;基于自增ID&#xff09; 3.2 lastmodified模式&#xff08;基…...

✍️【TS类型体操进阶】挑战类型极限,成为类型魔法师!♂️✨

哈喽类型战士们&#xff01;今天我们要玩转TS类型体操&#xff0c;让你的类型系统像体操运动员一样灵活优雅~ 学会这些绝招&#xff0c;保准你的代码类型稳如老狗&#xff01;&#xff08;文末附类型体操段位表&#xff09;&#x1f680; 一、什么是类型体操&#xff1f; &…...