Stm32串口搭配DMA实现自定义printf、scanf

前言:本文仅供学习参考使用,主要目的是让大家快速使用串口调试,文章所提及的GCC适用于Clion,Vscode等第三方编辑器的用户。作者有时间会继续更新^_^

一、GCC环境

1、标准库

(1)、使用方法

在主函数while(1)初始化中,添加Serial_Init();

int main(void) {
    Serial_Init();

    while (1) {

    }
}

在代码目录下创建USART文件夹,新建syscalls.c,sysmem.c,usart.c,usart.h四个文件,工程目录结构如下:
在这里插入图片描述
在CMakeLists中添加如下代码:

# include_directories(Core/USART) 根据USART文件夹实际路径进行修改
set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-u_printf_float")
add_link_options( -specs=nosys.specs -specs=nano.specs)

使用u_scanf,u_printf来替代scanf,printf函数,用法一致。

(2)代码部分

syscalls.c
/**
 ******************************************************************************
 * @file      syscalls.c
 * @author    Auto-generated by STM32CubeIDE
 * @brief     STM32CubeIDE Minimal System calls file
 *
 *            For more information about which c-functions
 *            need which of these lowlevel functions
 *            please consult the Newlib libc-manual
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2020-2024 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */

/* Includes */
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>


/* Variables */
extern int __io_putchar(int ch) __attribute__((weak));
extern int __io_getchar(void) __attribute__((weak));


char *__env[1] = { 0 };
char **environ = __env;


/* Functions */
void initialise_monitor_handles()
{
}

int _getpid(void)
{
  return 1;
}

int _kill(int pid, int sig)
{
  (void)pid;
  (void)sig;
  errno = EINVAL;
  return -1;
}

void _exit (int status)
{
  _kill(status, -1);
  while (1) {}    /* Make sure we hang here */
}

__attribute__((weak)) int _read(int file, char *ptr, int len)
{
  (void)file;
  int DataIdx;

  for (DataIdx = 0; DataIdx < len; DataIdx++)
  {
    *ptr++ = __io_getchar();
  }

  return len;
}

__attribute__((weak)) int _write(int file, char *ptr, int len)
{
  (void)file;
  int DataIdx;

  for (DataIdx = 0; DataIdx < len; DataIdx++)
  {
    __io_putchar(*ptr++);
  }
  return len;
}

int _close(int file)
{
  (void)file;
  return -1;
}


int _fstat(int file, struct stat *st)
{
  (void)file;
  st->st_mode = S_IFCHR;
  return 0;
}

int _isatty(int file)
{
  (void)file;
  return 1;
}

int _lseek(int file, int ptr, int dir)
{
  (void)file;
  (void)ptr;
  (void)dir;
  return 0;
}

int _open(char *path, int flags, ...)
{
  (void)path;
  (void)flags;
  /* Pretend like we always fail */
  return -1;
}

int _wait(int *status)
{
  (void)status;
  errno = ECHILD;
  return -1;
}

int _unlink(char *name)
{
  (void)name;
  errno = ENOENT;
  return -1;
}

int _times(struct tms *buf)
{
  (void)buf;
  return -1;
}

int _stat(char *file, struct stat *st)
{
  (void)file;
  st->st_mode = S_IFCHR;
  return 0;
}

int _link(char *old, char *new)
{
  (void)old;
  (void)new;
  errno = EMLINK;
  return -1;
}

int _fork(void)
{
  errno = EAGAIN;
  return -1;
}

int _execve(char *name, char **argv, char **env)
{
  (void)name;
  (void)argv;
  (void)env;
  errno = ENOMEM;
  return -1;
}

sysmem.c
/**
 ******************************************************************************
 * @file      sysmem.c
 * @author    Generated by STM32CubeIDE
 * @brief     STM32CubeIDE System Memory calls file
 *
 *            For more information about which C functions
 *            need which of these lowlevel functions
 *            please consult the newlib libc manual
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2024 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */

/* Includes */
#include <errno.h>
#include <stdint.h>

/**
 * Pointer to the current high watermark of the heap usage
 */
static uint8_t *__sbrk_heap_end = NULL;

/**
 * @brief _sbrk() allocates memory to the newlib heap and is used by malloc
 *        and others from the C library
 *
 * @verbatim
 * ############################################################################
 * #  .data  #  .bss  #       newlib heap       #          MSP stack          #
 * #         #        #                         # Reserved by _Min_Stack_Size #
 * ############################################################################
 * ^-- RAM start      ^-- _end                             _estack, RAM end --^
 * @endverbatim
 *
 * This implementation starts allocating at the '_end' linker symbol
 * The '_Min_Stack_Size' linker symbol reserves a memory for the MSP stack
 * The implementation considers '_estack' linker symbol to be RAM end
 * NOTE: If the MSP stack, at any point during execution, grows larger than the
 * reserved size, please increase the '_Min_Stack_Size'.
 *
 * @param incr Memory size
 * @return Pointer to allocated memory
 */
void *_sbrk(ptrdiff_t incr)
{
  extern uint8_t _end; /* Symbol defined in the linker script */
  extern uint8_t _estack; /* Symbol defined in the linker script */
  extern uint32_t _Min_Stack_Size; /* Symbol defined in the linker script */
  const uint32_t stack_limit = (uint32_t)&_estack - (uint32_t)&_Min_Stack_Size;
  const uint8_t *max_heap = (uint8_t *)stack_limit;
  uint8_t *prev_heap_end;

  /* Initialize heap end at first call */
  if (NULL == __sbrk_heap_end)
  {
    __sbrk_heap_end = &_end;
  }

  /* Protect heap from growing into the reserved MSP stack */
  if (__sbrk_heap_end + incr > max_heap)
  {
    errno = ENOMEM;
    return (void *)-1;
  }

  prev_heap_end = __sbrk_heap_end;
  __sbrk_heap_end += incr;

  return (void *)prev_heap_end;
}
usart.c

#include "usart.h"

uint8_t rx_buffer[BUFF_SIZE];
uint8_t tx_buffer[1];
volatile uint8_t Serial_RxFlag;

void GPIO_Init_Config(void) {
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void USART_Init_Config(void) {
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    USART_InitTypeDef USART_InitStructure;
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_HardwareFlowControl =
        USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_Init(USART1, &USART_InitStructure);
    USART_Cmd(USART1, ENABLE);
}

void DMA_Init_Config(DMA_Channel_TypeDef *DMA_Channel, uint32_t buffer,
                     uint32_t direction, uint32_t bufferSize) {
    DMA_InitTypeDef DMA_InitStructure;
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // Enable DMA1 clock
    DMA_DeInit(DMA_Channel);                           // Reset DMA channel
    DMA_InitStructure.DMA_PeripheralBaseAddr =
        (u32)(&USART1->DR);                        // Peripheral base address
    DMA_InitStructure.DMA_MemoryBaseAddr = buffer; // Memory base address
    DMA_InitStructure.DMA_DIR = direction;         // DMA transmit direction
    DMA_InitStructure.DMA_BufferSize = bufferSize; // DMA Channel buffer size
    DMA_InitStructure.DMA_PeripheralInc =
        DMA_PeripheralInc_Disable; // Peripheral address incremented
    DMA_InitStructure.DMA_MemoryInc =
        DMA_MemoryInc_Enable; // Memory address incremented
    DMA_InitStructure.DMA_PeripheralDataSize =
        DMA_PeripheralDataSize_Byte; // Peripheral data width
    DMA_InitStructure.DMA_MemoryDataSize =
        DMA_MemoryDataSize_Byte;                        // Memory data width
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;       // DMA Channel mode
    DMA_InitStructure.DMA_Priority = DMA_Priority_High; // DMA Channel priority
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // Memory-to-memory transfer
    DMA_Init(DMA_Channel, &DMA_InitStructure);   // DMA init
    DMA_Cmd(DMA_Channel, ENABLE);                // Enable DMA channel
}

void NVIC_Init_Config(void) {
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; // IRQ Channel
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =
        3;                                             // Preemption Priority
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // SubPriority Priority
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    // Enable IRQ Channel
    NVIC_Init(&NVIC_InitStructure);                    // Init NVIC
}

void Serial_Init(void) {
    GPIO_Init_Config();
    USART_Init_Config();
    DMA_Init_Config(DMA1_Channel5, (u32)rx_buffer, DMA_DIR_PeripheralSRC,
                    BUFF_SIZE);
    DMA_Init_Config(DMA1_Channel4, (u32)tx_buffer, DMA_DIR_PeripheralDST, 1);
    NVIC_Init_Config();
    USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); // Enables Idle interrupt
    USART_GetFlagStatus(USART1, USART_FLAG_IDLE);  // Get Idle flag
    USART_ReceiveData(USART1);                     // Get receive data
    USART_Cmd(USART1, ENABLE);                     // Enable USART1
    USART_DMACmd(USART1, USART_DMAReq_Rx | USART_DMAReq_Tx,
                 ENABLE); // Enable DMA receive/transmit request
}

void Usart_SendByte(uint8_t ch) {
    tx_buffer[0] = ch;
    DMA_Cmd(DMA1_Channel4, DISABLE); //关闭 USART1 TX DMA1 所指示的通道
    DMA_SetCurrDataCounter(DMA1_Channel4, 1); //设置 DMA 缓存的大小
    DMA_Cmd(DMA1_Channel4, ENABLE); //使能 USART1 TX DMA1 所指示的通道
    //等待发送结束
    while (!DMA_GetFlagStatus(DMA1_FLAG_TC4))
        ;
    DMA_ClearFlag(DMA1_FLAG_TC4);
}
void USART_SendString(const char *str) {
    unsigned int i = 0;
    while (*(str + i) != '\0') {
        Usart_SendByte(*(str + i));
        i++;
    }
    while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
        ;
}

void USART1_IRQHandler(void) {
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        USART_ClearFlag(USART1, USART_FLAG_RXNE);
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }

    if (USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) // Idle interrupt set
    {
        USART_GetITStatus(USART1, USART_IT_IDLE); // Get idle interrupt state
        USART_ReceiveData(USART1);                // Get USARTx received data
        DMA_Cmd(DMA1_Channel5, DISABLE);          // Disable DMA channel
        DMA_SetCurrDataCounter(DMA1_Channel5, BUFF_SIZE); // Set data count
        DMA_Cmd(DMA1_Channel5, ENABLE);                  // Enable DMA channel
        Serial_RxFlag = 1;
    }
}
char *find_next_space_or_end(char *str) {
    while (*str != ' ' && *str != '\0') {
        str++;
    }
    return str;
}

int str_to_num(char *start, char *end) {
    char temp[50];
    strncpy(temp, start, end - start);
    temp[end - start] = '\0';
    return atoi(temp);
}

double str_to_double(char *start, char *end) {
    char temp[50];
    strncpy(temp, start, end - start);
    temp[end - start] = '\0';
    return atof(temp);
}

void u_scanf(char *fmt, ...) {
    va_list ap;
    va_start(ap, fmt);
    char *start = rx_buffer;
    char *end;
    while (Serial_RxFlag == 0) {
    }
    Serial_RxFlag = 0;
    while (*fmt != '\0') {
        if (*fmt == '%') {
            fmt++;
            end = find_next_space_or_end(start);
            switch (*fmt) {
            case 'd': {
                int *ip = va_arg(ap, int *);
                *ip = str_to_num(start, end);
            } break;
            case 'l': {
                ++fmt;
                if (*fmt == 'f') {
                    double *fp = va_arg(ap, double *);
                    *fp = str_to_double(start, end);
                }
            } break;
            case 'f': {
                float *fp = va_arg(ap, float *);
                *fp = (float)str_to_double(start, end);
            } break;
            case 'c': {
                int *cp = va_arg(ap, int *);
                *cp = start[0];
            } break;
            case 's': {
                char *sp = va_arg(ap, char *);
                strcpy(sp, rx_buffer);
            } break;
            }
            start = end + 1;
        }
        fmt++;
    }
    va_end(ap);
}
void u_printf(const char *format, ...) {
    va_list args;
    uint8_t buff[BUFF_SIZE];
    va_start(args, format);
    vsprintf(buff, format, args);
    USART_SendString(buff);
    va_end(args);
}
usart.h
#ifndef __USART_H
#define __USART_H
#include "stdlib.h"
#include "stm32f10x.h"
#include "stm32f10x_dma.h"
#include "string.h"
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/types.h>
#define BUFF_SIZE 256
void Serial_Init(void);
void u_printf(const char *format, ...);
void u_scanf(char *fmt, ...);
#endif

(3)总结

可以看出在代码中u_scanf比较繁琐,使用自定义函数来实现,并未使用自带的vsscanf来重构,如果你想要使用vsscanf的话,还需要添加-u_scanf_float链接标志(同上),但是vsscanf函数会导致输入字符串时无法正常读取空格.


以上版本存在问题,请替换usart.c,usart.h为如下代码,使用方法直接使用printf以及scanf,注意在CMakeLists中添加-u_scanf_float链接标志

usart.c

#include "usart.h"

/*根据需要取消注释对应宏定义*/
#define DBUG_1
//#define DBUG_2

#if defined(DBUG_1)
#define DBUG_USART USART1
#define DBUG_PORT GPIOA
#define RX_PIN GPIO_Pin_10
#define TX_PIN GPIO_Pin_9
#define RCC_APB2Periph_DBUG_PORT RCC_APB2Periph_GPIOA
#define DBUG_RX_CHANNEL DMA1_Channel5
#define DBUG_TX_CHANNEL DMA1_Channel4
#define DBUG_RX_FLAG DMA1_FLAG_TC5
#define DBUG_TX_FLAG DMA1_FLAG_TC4
#elif defined(DBUG_2)
#define DBUG_USART USART2
#define DBUG_PORT GPIOA
#define RX_PIN GPIO_Pin_3
#define TX_PIN GPIO_Pin_2
#define RCC_APB2Periph_DBUG_PORT RCC_APB2Periph_GPIOA
#define DBUG_RX_CHANNEL DMA1_Channel6
#define DBUG_TX_CHANNEL DMA1_Channel7
#define DBUG_RX_FLAG DMA1_FLAG_TC6
#define DBUG_TX_FLAG DMA1_FLAG_TC7
#endif

uint8_t rx_buffer[1];
uint8_t tx_buffer[1];
volatile uint8_t Serial_RxFlag;

void GPIO_Init_Config(void) {
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_DBUG_PORT, ENABLE);
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin = TX_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DBUG_PORT, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = RX_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DBUG_PORT, &GPIO_InitStructure);
}

void USART_Init_Config(void) {
#if defined(DBUG_1)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
#elif defined(DBUG_2)
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
#endif
    USART_InitTypeDef USART_InitStructure;
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_HardwareFlowControl =
        USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_Init(DBUG_USART, &USART_InitStructure);
    USART_Cmd(DBUG_USART, ENABLE);
}

void DMA_Init_Config(DMA_Channel_TypeDef *DMA_Channel, uint32_t buffer,
                     uint32_t direction, uint32_t bufferSize) {
    DMA_InitTypeDef DMA_InitStructure;
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    DMA_DeInit(DMA_Channel);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&DBUG_USART->DR);
    DMA_InitStructure.DMA_MemoryBaseAddr = buffer;
    DMA_InitStructure.DMA_DIR = direction;
    DMA_InitStructure.DMA_BufferSize = bufferSize;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA_Channel, &DMA_InitStructure);
    DMA_Cmd(DMA_Channel, ENABLE);
}

void Serial_Init(void) {
    GPIO_Init_Config();
    USART_Init_Config();
    DMA_Init_Config(DBUG_RX_CHANNEL, (u32)rx_buffer, DMA_DIR_PeripheralSRC, 1);
    DMA_Init_Config(DBUG_TX_CHANNEL, (u32)tx_buffer, DMA_DIR_PeripheralDST, 1);
    USART_Cmd(DBUG_USART, ENABLE);
    USART_DMACmd(DBUG_USART, USART_DMAReq_Rx | USART_DMAReq_Tx, ENABLE);
    setvbuf(stdin, NULL, _IONBF, 0);
}

#if (defined(__GNUC__) && !defined(__CC_ARM))
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#define GETCHAR_PROTOTYPE int __io_getchar(void)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#define GETCHAR_PROTOTYPE int fgetc(FILE *f)
#endif /* __GNUC__ */

PUTCHAR_PROTOTYPE {
    *tx_buffer = ch;
    while (DMA_GetCurrDataCounter(DBUG_TX_CHANNEL) != 0) {
    };
    DMA_Cmd(DBUG_TX_CHANNEL, DISABLE);
    DMA_SetCurrDataCounter(DBUG_TX_CHANNEL, 1);
    DMA_Cmd(DBUG_TX_CHANNEL, ENABLE);
    while (!DMA_GetFlagStatus(DBUG_TX_FLAG))
        ;
    DMA_ClearFlag(DBUG_TX_FLAG);
    return ch;
}
GETCHAR_PROTOTYPE {
    DMA_Cmd(DBUG_RX_CHANNEL, DISABLE);
    DMA_SetCurrDataCounter(DBUG_RX_CHANNEL, 1);
    DMA_Cmd(DBUG_RX_CHANNEL, ENABLE);
    while (!DMA_GetFlagStatus(DBUG_RX_FLAG))
        ;
    DMA_ClearFlag(DBUG_RX_FLAG);
    return *rx_buffer;
}
usart.h
#ifndef __USART_H
#define __USART_H
#include "delay.h"
#include "stdlib.h"
#include "stm32f10x.h"
#include "stm32f10x_dma.h"
#include "string.h"
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/types.h>
void Serial_Init(void);

#endif

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【复试分数线】综合性985历年分数线汇总(第四弹)

国家线和34所自划线 可以看作是考研上岸最最最基础的门槛。真正决定你能不能进入复试的还要看院线&#xff08;复试分数线&#xff09;&#xff01;今天我将分析考信号的除C9、工科类985的其他7所985近三年复试分数线&#xff08;不包括2024&#xff09;&#xff0c;大家可以参…

Web前端开发 - 4 - CSS3动画

CSS3动画 一、 设计2D变换二、 设计3D变换三、 设计过渡动画四、设计帧动画 一、 设计2D变换 transform : none | <transform-function> /* <transform-function> 设置变换函数&#xff0c;可以是一个或多个变换函数列表。函数包括: martrix(x缩放,x倾斜,y倾斜,y…

玩转Matlab-Simscape(初级)-01-从一个简单模型开始学习之旅

** 玩转Matlab-Simscape&#xff08;初级&#xff09;- 01 - 从一个简单模型开始学习之旅 ** 目录 玩转Matlab-Simscape&#xff08;初级&#xff09;- 01 - 从一个简单模型开始学习之旅 前言一、从模板开始建模二、建模一个简单的连杆2.1 建模2.2 生成子系统 总结 前言 在产…

如何在 Windows 11/10 中恢复已删除的分区

在将重要数据存储在计算机上之前&#xff0c;许多用户会创建分区以更好地组织和管理他们的文件。此分区可以在内部硬盘驱动器或外部存储设备上创建。但是&#xff0c;有时可能会意外删除分区。如果发生这种情况&#xff0c;您可能想知道是否可以在不丢失任何信息的情况下恢复已…

适用于 Windows 8/10/11 的 10 大 PC 迁移工具:电脑克隆迁移软件

当您发现自己拥有一台新的 PC 或笔记本电脑时&#xff0c;PC 迁移变得至关重要。将数据从旧计算机传输到新计算机的过程似乎令人生畏&#xff0c;尤其是如果您是第一次这样做。迁移过程中数据丢失的潜在风险加剧了焦虑。为确保文件和系统设置的无缝无忧传输&#xff0c;使用专为…

初识C语言——第二十天

do while ()循环 do 循环语句; while(表达式); 句式结构&#xff1a; 执行过程&#xff1a; do while循环的特点&#xff1a; 代码练习&#xff1a; 二分法算法&#xff1a; int main() {int arr[] { 0,1,2,3,4,5,6,7,8,9};int k 7;//查找数字7&#xff0c;在arr这个数组…

prompt工程策略(三:使用 LLM 防护围栏创建系统提示)

原文&#xff1a;我是如何赢得GPT-4提示工程大赛冠军的 原文的原文&#xff1a; How I Won Singapore’s GPT-4 Prompt Engineering Competition &#xff01;&#xff01;本内容仅适用于具有 System Prompt&#xff08;系统提示&#xff09;功能的 LLM。具有这一功能的最著名 …

Python sort() 和 sorted() 的区别应用实例详解

大家好&#xff0c;今天针对 Python 中 sort() 和 sorted() 之间的区别&#xff0c;来一个实例详细解读。sort — 顾名思义就是排序的意思&#xff0c;它可以接收的对象为可迭代的数据类型。今天以列表为例子演示两者的不同点、相同点&#xff0c;以及其中一些常用的高级参数使…

【3dmax笔记】022:文件合并、导入、导出

文章目录 一、合并二、导入三、导出四、注意事项一、合并 只能合并 max 文件(高版本能够合并低版本模型,低版本不能合并高版本的模型)。点击【文件】→【导入】→【合并】: 选择要合并的文件,后缀名为3dmax默认的格式,max文件。 二、导入 点击【文件】→【导入】→【导…

NSSCTF中的1zjs、作业管理系统、finalrce、websign、简单包含、Http pro max plus

目录 [LitCTF 2023]1zjs [LitCTF 2023]作业管理系统 [SWPUCTF 2021 新生赛]finalrce exec()函数&#xff1a;php中exec介绍及使用_php exec-CSDN博客​​​​​​ 资料参考&#xff1a;RCE(远程命令执行)绕过总结_rce绕过-CSDN博客 [UUCTF 2022 新生赛]websign [鹏城杯 …

【校园论坛系统】分站式后台,多城市圈子论坛,校园圈子交流平台,二手发布市场,校园圈子论坛系统

简述 校园论坛系统是为学生们提供一个交流、分享信息、互相帮助的平台。它通常包括了各种分类的版块&#xff0c;例如学习交流、社团活动、二手交易、失物招领等等。用户可以在论坛上发帖&#xff0c;回复他人的帖子&#xff0c;也可以私信其他用户。此外&#xff0c;管理员还…

只用了三天就入门了Vue3?

"真的我学Vue3&#xff0c;只是为了完成JAVA课设" 环境配置 使用Vue3要去先下载Node.js。 就像用Python离不开pip包管理器一样。 Node.js — Run JavaScript Everywhere (nodejs.org) 下完Node.js去学习怎么使用npm包管理器&#xff0c;放心你只需要学一些基础的…

【数据结构】数据结构大汇总 {数据结构的分类总结:定义和特性、实现方式、操作与复杂度、适用场景、相关算法、应用实例}

一、线性结构 1.1 顺序表 定义和特性&#xff1a;顺序表是一种线性表的存储结构&#xff0c;它采用一段地址连续的存储单元依次存储线性表中的元素。顺序表具有随机访问的特性&#xff0c;即可以通过元素的下标直接访问元素。 实现方式&#xff1a;顺序表可以通过数组来实现&…

React Native 之 原生组件和核心组件(二)

原生组件 在 Android 开发中是使用 Kotlin 或 Java 来编写视图&#xff1b;在 iOS 开发中是使用 Swift 或 Objective-C 来编写视图。在 React Native 中&#xff0c;则使用 React 组件通过 JavaScript 来调用这些视图。在运行时&#xff0c;React Native 为这些组件创建相应的 …

第1章 初始Spring Boot【仿牛客网社区论坛项目】

第1章 初始Spring Boot【仿牛客网社区论坛项目】 前言推荐项目总结第1章初识Spring Boot&#xff0c;开发社区首页1.课程介绍2.搭建开发环境3.Spring入门体验IOC容器体验Bean的生命周期体验配置类体验依赖注入体验三层架构 4.SpringMVC入门配置体验响应数据体验响应Get请求体验…

Java应用程序的本地内存跟踪分析

本文将讨论本机内存跟踪 (NMT)&#xff0c;我们可以使用它来隔离在 VM 级别增长的任何异常内存。 1.什么是本机内存&#xff1f; 本机内存是指计算机系统上运行的应用程序或程序可直接访问的内存空间。它是程序在执行期间存储和操作数据的内存区域。本机内存不同于托管内存&a…

实物仿真平台设计方案:927-8路GMSL视频注入回灌的自动驾驶半实物仿真平台

8路GMSL视频注入回灌的自动驾驶半实物仿真平台 一、平台介绍 产品基于8路GMSL视频注入回灌的自动驾驶半实物仿真平台旨在提高实验室及研究生院师生在基础软件层开发、计算机视觉和深度学习方面的专业知识学习和实践能力&#xff0c;为师生提供一个稳定软件开发和多精度框…

【C++】认识C++(上)

目录 从C到C命名空间同名冲突命名空间的定义命名空间的使用 C的输入和输出缺省参数&#xff08;默认参数&#xff09; 从C到C C语言的出现是计算机科学和工程史上的一个重要里程碑&#xff0c;许多现代计算机语言都受C语言的影响。C语言是面向过程的&#xff0c;结构化和模块化…

优选算法——双指针2

题目一——有效三角形的个数 思路 先审题 举个例子&#xff0c;下面一个序列可分成4个三元组 然后我们论证哪个可以组成三角形即可 判断三个数能不能组成三角形&#xff1a;任意两边之和大于第三边 注意第一个和第四个&#xff0c;有人说&#xff0c;这不是两个相同的吗&#…

【opencv】opencv透视变换和ocr识别实验

实验环境&#xff1a;anaconda、jupyter notebook 实验用到的包opencv、numpy、matplotlib、tesseract 一、opencv透视变换 原图 图片是我拍的耳机说明书&#xff0c;哈哈哈哈&#xff0c;你也可以使用自己拍的照片&#xff0c;最好是英文内容&#xff0c;tesseract默认识别英…