STM32 CAN/CANFD软件快速配置(HAL库版本)

2023-11-14

STM32 CAN/CANFD软件快速配置(HAL库版本)

前言

控制器局域网总线(CAN,Controller Area Network)是一种用于实时应用的串行通讯协议总线,它可以使用双绞线来传输信号,是世界上应用最广泛的现场总线之一。CAN协议用于汽车中各种不同元件之间的通信,以此取代昂贵而笨重的配电线束。该协议的健壮性使其用途延伸到其他自动化和工业应用。CAN协议的特性包括完整性的串行数据通讯、提供实时支持、传输速率高达1Mb/s、同时具有11位的寻址以及检错能力。

特别说明:关于CAN总线协议和硬件电路,CANFD和CAN的区别等问题,这里不做介绍,网上的资料非常多,不懂的同学请自行查阅。

1 软件编程

1.1 建立工程

要建立一个HAL库版本的工程可以直接使用其他项目的HAL工程,也可以通过移植HAL固件库或者用STM32CubeMX生成。

我这里以STM32G0为例讲解一下如何用STM32CubeMX生成一个工程。
特别说明:如果不使用STM32CubeMX工具,可以跳过以下步骤,直接从1.2开始,把CANFD相关代码加入其他HAL工程即可。

1、配置时钟
我这里使用外部晶振时钟(HSE),8M晶振倍频到64M时钟。

在这里插入图片描述
在这里插入图片描述

2、配置引脚
选择自己实际使用的引脚作为CAN_TX和CAN_RX。

在这里插入图片描述

3、配置CAN参数
我这里用CAN1作为CANFD,CAN2作为普通CAN。

CAN1配置参考如下:
特别说明:以下数据仅供参考,请根据实际情况配置。
在这里插入图片描述

CAN2配置参考如下:
特别说明:以下数据仅供参考,请根据实际情况配置。
在这里插入图片描述

最后使能中断(注:CAN1和CAN2可以共用一个中断接口)。
在这里插入图片描述

4、生成工程
请添加图片描述

1.2 初始化

初始化主要分成三部分:引脚设置,CAN参数设置和CAN滤波器设置。

1.2.1 引脚设置

把CAN_H和CAN_L两个引脚配置成复用功能即可。
注:如果CAN控制芯片的S引脚连接到STM32的话,还得初始化这个引脚,S引脚可以配置成高速模式或静音模式。

参考代码:
注:该代码可以通过STM32CubeMX生成

static uint32_t HAL_RCC_FDCAN_CLK_ENABLED=0;

void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef* fdcanHandle)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  if(fdcanHandle->Instance==FDCAN1)
  {
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_FDCAN;
    PeriphClkInit.FdcanClockSelection = RCC_FDCANCLKSOURCE_PCLK1;

    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
      Error_Handler();
    }

    /* FDCAN1 clock enable */
    HAL_RCC_FDCAN_CLK_ENABLED++;
    if(HAL_RCC_FDCAN_CLK_ENABLED==1){
      __HAL_RCC_FDCAN_CLK_ENABLE();
    }

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**FDCAN1 GPIO Configuration
    PB8     ------> FDCAN1_RX
    PB9     ------> FDCAN1_TX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF3_FDCAN1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* FDCAN1 interrupt Init */
    HAL_NVIC_SetPriority(TIM16_FDCAN_IT0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM16_FDCAN_IT0_IRQn);
  }
  else if(fdcanHandle->Instance==FDCAN2)
  {
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_FDCAN;
    PeriphClkInit.FdcanClockSelection = RCC_FDCANCLKSOURCE_PCLK1;

    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
      Error_Handler();
    }

    /* FDCAN2 clock enable */
    HAL_RCC_FDCAN_CLK_ENABLED++;
    if(HAL_RCC_FDCAN_CLK_ENABLED==1){
      __HAL_RCC_FDCAN_CLK_ENABLE();
    }

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**FDCAN2 GPIO Configuration
    PB5     ------> FDCAN2_RX
    PB6     ------> FDCAN2_TX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF3_FDCAN2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* FDCAN2 interrupt Init */
    HAL_NVIC_SetPriority(TIM16_FDCAN_IT0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM16_FDCAN_IT0_IRQn);
  }
}
1.2.2 CAN基本参数设置

HAL库的CAN初始化有几个重要参数,都存放在几个结构体里面(如:CAN_HandleTypeDef,CAN_InitTypeDef),具体的结构体定义可以在HAL库查看。
说明:CAN参数需要根据自己实际的需求来配。

我这里着重讲解一下CAN波特率的配置。

CAN波特率 = CAN时钟频率 / 时钟分频 / 预分频系数 / (TimeSeg1 + TimeSeg2 + 1)。

其中,CAN时钟频率不是固定不变的,它取决于CAN所挂载的总线时钟。
比如STM32F1,系统时钟最大72M,APB1的总线时钟最大36M,而CAN控制器的时钟是挂在APB1的,所以CAN的时钟频率也等于APB1的时钟。
如果换作其他型号的MCU,CAN外设不一定是挂载到APB1上面的,时钟也不一定是36M,比如F4系列,APB1的时钟是可以配成42M的,因此,这个要根据实际情况来配置。

本例用的是STM32G0,CAN时钟频率配置为64MHz。
参考代码:
注:该代码可以通过STM32CubeMX生成

FDCAN_HandleTypeDef hfdcan1;
FDCAN_HandleTypeDef hfdcan2;

/* FDCAN1 init function */
void MX_FDCAN1_Init(void)
{
  /* USER CODE END FDCAN1_Init 1 */
  // CAN波特率 = 时钟频率 / 时钟分频  / 预分频系数 / (1 + TSG1 + TSG2) 
  // 仲裁段波特率 = 64M / 1 / 8 / (1 + 10 + 5) = 500k
  // 数据段波特率 = 64M / 1 / 2 / (1 + 10 + 5) = 2M
  hfdcan1.Instance = FDCAN1;                               // FDCAN1
  hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1;            // 时钟分频               
  hfdcan1.Init.FrameFormat = FDCAN_FRAME_FD_BRS;           // 配置为CANFD         
  hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;                   // 正常工作状态       
  hfdcan1.Init.AutoRetransmission = DISABLE;               // 关闭自动重传, 传统模式下需关闭           
  hfdcan1.Init.TransmitPause = DISABLE;                    // 关闭传输暂停      
  hfdcan1.Init.ProtocolException = DISABLE;                // 关闭协议异常处理          
  hfdcan1.Init.NominalPrescaler = 8;                       // 仲裁段时钟分频,传统CAN模式时只设置这一段即可   
  hfdcan1.Init.NominalSyncJumpWidth = 1;                   // 仲裁段同步跳转段的宽度                      
  hfdcan1.Init.NominalTimeSeg1 = 10;                       // 仲裁段时间段1                      
  hfdcan1.Init.NominalTimeSeg2 = 5;                        // 仲裁段时间段2                     
  hfdcan1.Init.DataPrescaler = 2;                          // 数据段时钟分频,若工作于传统模式,不需要设置数据段参数
  hfdcan1.Init.DataSyncJumpWidth = 1;                      // 数据段同步跳转段的宽度   
  hfdcan1.Init.DataTimeSeg1 = 10;                          // 数据段时间段1           
  hfdcan1.Init.DataTimeSeg2 = 5;                           // 数据段时间段2           
  hfdcan1.Init.StdFiltersNbr = 28;                         // 标准帧滤波器数量 
  hfdcan1.Init.ExtFiltersNbr = 8;                          // 扩展帧滤波器数量 
  hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;  // 发送模式:先入先出   
  if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK)
  {
    Error_Handler();
  }
}
/* FDCAN2 init function */
void MX_FDCAN2_Init(void)
{
  /* USER CODE END FDCAN2_Init 1 */
  // CAN波特率 = 时钟频率 / 时钟分频 / 预分频系数 / (1 + TSG1 + TSG2) = 64M / 1 / 8 / (1 + 10 + 5) = 500k
  hfdcan2.Instance = FDCAN2;                               // FDCAN2
  hfdcan2.Init.ClockDivider = FDCAN_CLOCK_DIV1;            // 时钟分频 
  hfdcan2.Init.FrameFormat = FDCAN_FRAME_CLASSIC;          // 配置为传统模式    
  hfdcan2.Init.Mode = FDCAN_MODE_NORMAL;                   // 正常工作状态
  hfdcan2.Init.AutoRetransmission = DISABLE;               // 关闭自动重传, 传统模式下需关闭
  hfdcan2.Init.TransmitPause = DISABLE;                    // 关闭传输暂停
  hfdcan2.Init.ProtocolException = DISABLE;                // 关闭协议异常处理
  hfdcan2.Init.NominalPrescaler = 8;                       // 仲裁段时钟分频,传统CAN模式时只设置这一段即可
  hfdcan2.Init.NominalSyncJumpWidth = 1;                   // 仲裁段同步跳转段的宽度               
  hfdcan2.Init.NominalTimeSeg1 = 10;                       // 仲裁段时间段1                   
  hfdcan2.Init.NominalTimeSeg2 = 5;                        // 仲裁段时间段2                   
  hfdcan2.Init.DataPrescaler = 8;                          // 数据段时钟分频,若工作于传统模式,不需要设置数据段参数
  hfdcan2.Init.DataSyncJumpWidth = 1;                      // 数据段同步跳转段的宽度
  hfdcan2.Init.DataTimeSeg1 = 10;                          // 数据段时间段1           
  hfdcan2.Init.DataTimeSeg2 = 5;                           // 数据段时间段2           
  hfdcan2.Init.StdFiltersNbr = 28;                         // 标准帧滤波器数量
  hfdcan2.Init.ExtFiltersNbr = 8;                          // 扩展帧滤波器数量
  hfdcan2.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;  // 发送模式:先入先出                  
  if (HAL_FDCAN_Init(&hfdcan2) != HAL_OK)
  {
    Error_Handler();
  }
}
1.2.3 CAN收发初始化设置

CAN接收需要设置CAN滤波器,它的主要作用是筛选CAN接收的数据,只有满足设定规则的数据才会被接收,否则会被过滤掉。
而CAN发送则需要在发送一条数据前,先配置好这条数据的信息,如CANID,发送长度,数据类型(CAN/CANFD)等等。

参考代码:

FDCAN_TxHeaderTypeDef TxHeader1;
FDCAN_RxHeaderTypeDef RxHeader1;
FDCAN_TxHeaderTypeDef TxHeader2;
FDCAN_RxHeaderTypeDef RxHeader2;
void FDCAN1_Config(void)
{
  FDCAN_FilterTypeDef sFilterConfig;
  /* Configure Rx filter */
  sFilterConfig.IdType = FDCAN_STANDARD_ID;
  sFilterConfig.FilterIndex = 1;
  sFilterConfig.FilterType = FDCAN_FILTER_RANGE;
  sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
  sFilterConfig.FilterID1 = 0x00000000;
  sFilterConfig.FilterID2 = 0x000007FF;
  if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sFilterConfig.IdType = FDCAN_EXTENDED_ID;
  sFilterConfig.FilterIndex = 0;
  sFilterConfig.FilterType = FDCAN_FILTER_RANGE;
  sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
  sFilterConfig.FilterID1 = 0x00000000;
  sFilterConfig.FilterID2 = 0x1FFFFFFF;
  if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }

  /* Configure global filter:
     Filter all remote frames with STD and EXT ID
     Reject non matching frames with STD ID and EXT ID */
  if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)
  {
    Error_Handler();
  }

  /* Activate Rx FIFO 0 new message notification on both FDCAN instances */
  if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
  {
    Error_Handler();
  }

  // if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_BUS_OFF, 0) != HAL_OK)
  // {
  //   Error_Handler();
  // }

  /* Tx Config*/
  TxHeader1.Identifier = 0x000000000;                 // CAN ID
  TxHeader1.IdType = FDCAN_STANDARD_ID;               // 标准ID
  TxHeader1.TxFrameType = FDCAN_DATA_FRAME;           
  TxHeader1.DataLength = FDCAN_DLC_BYTES_8;
  TxHeader1.ErrorStateIndicator = FDCAN_ESI_PASSIVE;
  TxHeader1.BitRateSwitch = FDCAN_BRS_OFF;
  TxHeader1.FDFormat = FDCAN_FD_CAN;                  // CANFD
  TxHeader1.TxEventFifoControl = FDCAN_NO_TX_EVENTS;  
  TxHeader1.MessageMarker = 0;

  /* Configure and enable Tx Delay Compensation, required for BRS mode.
        TdcOffset default recommended value: DataTimeSeg1 * DataPrescaler
        TdcFilter default recommended value: 0 */
  HAL_FDCAN_ConfigTxDelayCompensation(&hfdcan1, hfdcan1.Init.DataPrescaler * hfdcan1.Init.DataTimeSeg1, 0);
  HAL_FDCAN_EnableTxDelayCompensation(&hfdcan1);
  
  /* Start the FDCAN module */
  if (HAL_FDCAN_Start(&hfdcan1) != HAL_OK)
  {
    Error_Handler();
  }
}

void FDCAN2_Config(void)
{
  FDCAN_FilterTypeDef sFilterConfig;
  /* Configure Rx filter */
  sFilterConfig.IdType = FDCAN_STANDARD_ID;
  sFilterConfig.FilterIndex = 1;
  sFilterConfig.FilterType = FDCAN_FILTER_RANGE;
  sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
  sFilterConfig.FilterID1 = 0x00000000;
  sFilterConfig.FilterID2 = 0x000007FF;
  if (HAL_FDCAN_ConfigFilter(&hfdcan2, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sFilterConfig.IdType = FDCAN_EXTENDED_ID;
  sFilterConfig.FilterIndex = 0;
  sFilterConfig.FilterType = FDCAN_FILTER_RANGE;
  sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
  sFilterConfig.FilterID1 = 0x00000000;
  sFilterConfig.FilterID2 = 0x1FFFFFFF;
  if (HAL_FDCAN_ConfigFilter(&hfdcan2, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }

  /* Configure global filter:
     Filter all remote frames with STD and EXT ID
     Reject non matching frames with STD ID and EXT ID */
  if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan2, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)
  {
    Error_Handler();
  }

  /* Activate Rx FIFO 0 new message notification on both FDCAN instances */
  if (HAL_FDCAN_ActivateNotification(&hfdcan2, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
  {
    Error_Handler();
  }

  // if (HAL_FDCAN_ActivateNotification(&hfdcan2, FDCAN_IT_BUS_OFF, 0) != HAL_OK)
  // {
  //   Error_Handler();
  // }

  /* Tx Config*/
  TxHeader2.Identifier = 0x000000000;                 // CAN ID
  TxHeader2.IdType = FDCAN_STANDARD_ID;               // 标准ID
  TxHeader2.TxFrameType = FDCAN_DATA_FRAME;           
  TxHeader2.DataLength = FDCAN_DLC_BYTES_8;
  TxHeader2.ErrorStateIndicator = FDCAN_ESI_PASSIVE;
  TxHeader2.BitRateSwitch = FDCAN_BRS_OFF;
  TxHeader2.FDFormat = FDCAN_CLASSIC_CAN;             // CAN
  TxHeader2.TxEventFifoControl = FDCAN_NO_TX_EVENTS;  
  TxHeader2.MessageMarker = 0;

  /* Configure and enable Tx Delay Compensation, required for BRS mode.
        TdcOffset default recommended value: DataTimeSeg1 * DataPrescaler
        TdcFilter default recommended value: 0 */
  HAL_FDCAN_ConfigTxDelayCompensation(&hfdcan2, hfdcan2.Init.DataPrescaler * hfdcan2.Init.DataTimeSeg1, 0);
  HAL_FDCAN_EnableTxDelayCompensation(&hfdcan2);

  /* Start the FDCAN module */
  if (HAL_FDCAN_Start(&hfdcan2) != HAL_OK)
  {
    Error_Handler();
  }
}

1.2.4 中断设置

如果使用CAN接收,需要配置中断服务函数。

参考代码:

/**
  * @brief This function handles TIM16, FDCAN1_IT0 and FDCAN2_IT0 Interrupt.
  */
void TIM16_FDCAN_IT0_IRQHandler(void)
{
  HAL_FDCAN_IRQHandler(&hfdcan1);
  HAL_FDCAN_IRQHandler(&hfdcan2);
}

1.3 CAN发送

CAN发送需要先配置发送参数,我这里为了方便测试,直接固定发送标准帧,ID也是固定的。
实际使用时可以把CANID,数据长度等参数作为函数入参,这样会更灵活一点。

参考代码:

void canfd_tx_test(void)
{
  TxHeader1.Identifier = 0x123;                 // CAN ID
  TxHeader1.IdType = FDCAN_STANDARD_ID;         // 标准ID
  TxHeader1.TxFrameType = FDCAN_DATA_FRAME;           
  TxHeader1.DataLength = FDCAN_DLC_BYTES_8;     // 发送长度:8byte
  TxHeader1.ErrorStateIndicator = FDCAN_ESI_PASSIVE;
  TxHeader1.BitRateSwitch = FDCAN_BRS_OFF;
  TxHeader1.FDFormat = FDCAN_FD_CAN;            // CANFD
  TxHeader1.TxEventFifoControl = FDCAN_NO_TX_EVENTS;  
  TxHeader1.MessageMarker = 0;

  if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader1, can1_txbuf) != HAL_OK)
  {
    Error_Handler();
  }
}

1.4 CAN接收

接收部分只要开启了Rx中断,在CAN控制器收到消息时会调用RxFifo的回调函数,此时在这里读取数据并根据实际情况做相应的处理即可。我这里把收到的数据又发回去了,这样可以同时验证接收和发送。

参考代码:

void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
{
  if((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != RESET)
  {
    if(hfdcan->Instance == FDCAN1)
    {
      /* Retrieve Rx messages from RX FIFO0 */
      if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, can1_rxbuf) != HAL_OK)
      {
        Error_Handler();
      }
      /* 把接收到的数据以CANFD发送回去 */
      TxHeader1.DataLength = RxHeader1.DataLength;
      TxHeader1.Identifier = RxHeader1.Identifier;
      if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader1, can1_rxbuf) != HAL_OK)
      {
        Error_Handler();
      }
    }

    if(hfdcan->Instance == FDCAN2)
    {
      /* Retrieve Rx messages from RX FIFO0 */
      if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader2, can2_rxbuf) != HAL_OK)
      {
        Error_Handler();
      }
      /* 把接收到的数据以CAN发送回去 */
      TxHeader2.DataLength = RxHeader2.DataLength;
      TxHeader2.Identifier = RxHeader2.Identifier;
      if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan2, &TxHeader2, can2_rxbuf) != HAL_OK)
      {
        Error_Handler();
      }
    }
  }
}

2 运行测试

使用USB-CAN工具测试。

CAN1使用CANFD(仲裁域波特率500k,数据域波特率2M),上位机每发送一条数据,STM32收到后同样回一条一样的数据,CANID、数据长度和数据都是一致,说明STM32收到的数据没有问题。
在这里插入图片描述

CAN2使用普通CAN(仲裁域和数据域波特率均为500k),上位机每发送一条数据,STM32收到后同样回一条一样的数据,CANID、数据长度和数据都是一致,说明STM32收到的数据没有问题。
在这里插入图片描述

还有一些其他测试,比如切换扩展帧,远程帧等等,这里就不展示了,感兴趣的同学可以自己改参数试试。

结论:CAN收发正常。

结束语

好了,关于如何通过STM32如何配置和使用CANFD就讲到这里,如果你有什么问题或者有更好的方法,欢迎在评论区留言。

需要源码工程的同学可以自行下载:点击跳转下载链接

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32 CAN/CANFD软件快速配置(HAL库版本) 的相关文章

  • 拍照转文字的软件哪个好?这篇文分分钟告诉你答案

    上了大学之后 大家是不是就很少在上课的时候拿笔记记课堂笔记啦 也是 大学课堂上并不禁止我们使用手机 我们只需要在遇到需要记下的知识点时 掏出手机拍几张照片就好了 这样虽然解放了双手 但我们到了期末想要复习知识点的时候 图片形式的内容总是不太
  • Mac/Linux虚拟机CrossOver2024新版下载使用教程

    CrossOver不像Parallels或VMware的模拟器 而是实实在在Mac OS X系统上运行的一个软件 该软件可以让用户在mac是上直接运行windows软件 本文为大家带来的是CrossOver Mac版安装教程 CrossOv
  • 提升口才:掌握技巧,展现自信

    口才 是现代社会中不可或缺的一种能力 无论是在职场 社交场合还是日常生活中 良好的口才都能为我们带来更多的机会和成功 然而 很多人却因为缺乏自信或者技巧不足而无法充分发挥自己的口才 那么 如何提升口才呢 下面就让我们一起来探讨这个问题 如果
  • 职场生存能力最强的5类人:如何成为职场中的佼佼者?

    职场生存能力最强的5类人 如何成为职场中的佼佼者 在职场中 生存能力强的人往往更容易获得成功 他们具备各种能力和特质 使他们能够在激烈的竞争中脱颖而出 本文将介绍职场生存能力最强的5类人 看看你是否具备这些特点 一 适应能力强的人 在职场中
  • 如何避免过度努力带来的负面影响

    在快节奏的现代职场中 我们经常听到关于 努力 的话题 有些人认为 只有通过不断地努力和投入 才能够获得成功 然而 如果过度用力 可能会带来一些负面影响 本文将探讨职场中过度用力的负面影响以及如何避免这些问题 首先 让我们来看一下过度用力的负
  • Linux中的磁盘空间管理:df命令的详解与应用

    在Linux操作系统中 磁盘空间的管理是系统管理员和普通用户都需要面对的重要任务 为了帮助用户更好地理解和管理磁盘空间 Linux提供了一系列工具 其中最常用 最直观的莫过于df命令 df命令 全名为 disk free 它是一个用于显示磁
  • Win11熄屏,自动断开WiFi解决方法

    一 前言 由于 我需要使用自己的电脑 远程连接服务器跑代码 电脑息屏之后 wifi断开 代码也就自动停止了 非常生气 二 解决办法 网上的办法很多都是win10 而且别人的都有电源管理 而我的没有 下面是别人的 这是我的 就是没有电源管理
  • “性能压测揭密:关键指标分析!“

    在进行全链路压测和性能测试时 需要关注多个关键性能指标 KPIs 来评估系统的性能表现 以下是一些常见的性能测试指标 1 吞吐量 Throughput 系统在单位时间内能够处理的请求数量或事务数量 通常以每秒请求数 RPS TPS 来衡量
  • STM32F4XX的12位ADC采集数值超过4096&右对齐模式设置失败

    文章目录 一 前言 二 问题1 数值超过4096 三 问题1的排错过程 四 问题2 右对齐模式设置失败 五 问题2的解决方法 5 1 将ADC ExternalTrigConv设置为0 5 2 使用ADC StructInit 函数 一 前
  • 库函数点亮Led

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 pandas是什么 二 使用步骤 1 引入库 2 读入数据 总结 前言 提示 这里可以添加本文要记录的大概内容 例如 随着人工智能的不断发展 机器学习这门
  • 怎么把视频压缩变小?节约空间的工具推荐

    nbsp 我平时逛街的时候 看见有趣的事情就忍不住会用视频的方式记录下来 有时候还会拍给朋友看 但是 这些视频占据大量的存储空间 给我的手机带来不小的压力 所以有时候 为了方便分享或传输 我就会将视频文件压缩 以便更轻松地将其发送给朋友或发
  • 电脑操作系统的发展史:从初级到高级的演变

    自电脑诞生以来 操作系统作为其重要组成部分 不断推动着电脑技术的进步与发展 本文将带您回顾电脑操作系统的发展历程 探究其在不同阶段的特点与影响 一 早期操作系统 真空管与批处理 在电脑诞生初期 真空管技术占主导地位 此时的操作系统尚未形成完
  • 图片编辑软件有哪些好用的?这几款快收藏吧

    你有没有过这样的经历 精心拍摄了一组照片 却发现有些角度不对 光线不够好 或者想要给图片加上一些特别的滤镜效果来达到心目中的样子 这时 你就需要一款合适的图片编辑软件了 但是 市面上的图片编辑软件琳琅满目 哪一款才是适合自己的呢 别担心 今
  • 短视频时代:影响播放量的秘密与破解之道

    在当下这个信息爆炸的时代 短视频已经成为我们日常生活的一部分 无论是刷朋友圈 看新闻还是消磨时光 短视频都是我们的首选 正因为如此 许多自媒体人和内容创作者纷纷投身到这片热土 希望通过短视频实现自己的价值 然而 许多人在创作过程中都会遇到一
  • 如何正确下载激活NTFS for Mac2024最新版本?

    对于产品来说 更新换代是常有的事 很多软件在用户使用过后 会根据用户的使用需求以及一些客观需求 将软件进行改进 这样一个新的版本的软件就会出现 用户需要将软件进行更新才能享受最新的功能 使用更加完善的软件 所以我们一定要学会如何将软件进行更
  • Cortex-M3与M4权威指南

    处理器类型 所有的ARM Cortex M 处理器是32位的精简指令集处理器 它们有 32位寄存器 32位内部数据路径 32位总线接口 除了32位数据 Cortex M处理器也可以有效地处理器8位和16位数据以及支持许多涉及64位数据的操作
  • 通过JTAG恢复STM32 MCU磨掉的标记

    我有一块可能带有 STM32 MCU 的板 我想为该板制作定制固件 因为库存板有很多问题 不幸的是 电路板制造商很友善地磨掉了所有标记 有没有办法通过 jtag 获取设备 系列 ID 并将其交叉引用到型号 我能找到的一切都是关于获取芯片的唯
  • HAL_Delay() 陷入无限循环

    我被 HAL Delay 函数困住了 当我调用此函数 HAL Delay 时 控制陷入无限循环 在寻找问题的过程中 我发现了这个 http www openstm32 org forumthread2145 threadId2146 htt
  • 哪些变量类型/大小在 STM32 微控制器上是原子的?

    以下是 STM32 微控制器上的数据类型 http www keil com support man docs armcc armcc chr1359125009502 htm http www keil com support man d
  • STM32 传输结束时,循环 DMA 外设到存储器的行为如何?

    我想问一下 在以下情况下 STM32 中的 DMA SPI rx 会如何表现 我有一个指定的 例如 96 字节数组 名为 A 用于存储从 SPI 接收到的数据 我打开循环 SPI DMA 它对每个字节进行操作 配置为 96 字节 是否有可能

随机推荐

  • 10个高效的摸鱼神器,你错过几个?

    老话说的好 Chrome 没插件 香味少一半 作为使用过上百个插件的Chrome半资深用户 这儿极力推荐10个插件 除了摸鱼 还能让你的工作学习效率翻高好几倍 1 Global Speed 视频播放提高至16倍速 以往我们看的视频网站 也就
  • Redis - String内存开销问题以及基本/扩展数据类型的使用

    Redis String内存开销问题以及基本 扩展数据类型的使用 一 String 类型内存开销问题 1 1 SDS 结构 1 2 RedisObject 结构 1 3 String 类型的内存布局优化 1 4 压缩列表的优势 二 Redi
  • [安全攻防进阶篇] 二.如何学好逆向分析、逆向路线推荐及吕布传游戏逆向案例

    从2019年7月开始 我来到了一个陌生的专业 网络空间安全 初入安全领域 是非常痛苦和难受的 要学的东西太多 涉及面太广 但好在自己通过分享100篇 网络安全自学 系列文章 艰难前行着 感恩这一年相识 相知 相趣的安全大佬和朋友们 如果写得
  • PyCharm远程连接Spark

    PyCharm远程连接Spark 使用PyCharm连接远程服务器 总结一下完善的步骤 连接前一定要保证集群已经可以运行pyspark程序 1 添加SFTP连接 找到菜单Tool gt Deployment gt Configuration
  • Java学习资料

    Javadoop https javadoop com 公众号 Java学习录 https mp weixin qq com s xqDPttr53rxLBi8t8kIQDg bugstack 虫洞栈 https bugstack cn
  • IO学习系列之使用read和write复制文件内容

    read函数 功能 从文件fd中读取count个字节 存放进指针buf 具体内容 include
  • forest--声明式HTTP客户端框架-spring-b oot项目整合

    Forest 是一个开源的 Java HTTP 客户端框架 它能够将 HTTP 的所有请求信息 包括 URL Header 以及 Body 等信息 绑定到您自定义的 Interface 方法上 能够通过调用本地接口方法的方式发送 HTTP
  • 基于MATLAB的BP神经网络的数据分类

    1 BP神经网络的简介 BP神经网络是一种多层前馈神经网络 该网络的主要特点是信号前向传递 误差反向传播 在前向传递中 输入信号从输出层经隐含层逐层处理 直至输出层 每一层神经元状态只会影响下一层神经元状态 如果输出层得不到期望输出 则转入
  • 添加视频字幕后期制作Premiere Pro 2022中文

    Premiere Pro 2022是一款PR视频剪辑软件 同时支持M1 M2芯片和Intel芯片安装 可以帮助用户提升自己的创作能力和创作自由度 具有易学 高效 精确的优点 可为用户提供采集 剪辑 调色 美化音频 字幕添加 输出 DVD刻录
  • Google发布VS Code,支持Kubernetes应用开发

    VS Code以及IntelliJ适合用来开发本地端应用开发 但在开发云端应用的时候 Google提到 因为本地端与云端执行环境的差异 部分云端应用会抱错误 要在开发周期的后期才能被发现 而Cloud Codes能有效改善这个问题 由于是第
  • Ubuntu实时监控网速、CPU、内存

    Ubuntu实时监控网速 CPU 内存 sudo add apt repository ppa fossfreedom indicator sysmonitor sudo apt get update sudo apt get instal
  • 【Python】数据可视化-散点图绘制

    Python在数据科学中拥有十分重要的地位 numpy scipy pandas scikit learn这些高效易用 接口统一的科学计算包使其在数据分析处理过程更加方便快捷 其强大的数据可视化工具也是重要组成部分 在Python中 使用的
  • linux基本命令与终端操作、linux命令英文全称解释、ls clear cd pwd cat touch cp rm rmdir mkdir mv file find grep sudo su

    linux终端的命令提示符 命令提示符由四部分组成 当前登陆的用户名 主机名 当前所在目录 用户提示符 linux基本命令 查看目录下文件及文件夹 ls 英文全称 助记 list 命令参数 a all 输出所有文件及文件夹 包括隐藏文件 l
  • LoFTR配置运行: Detector-Free Local Feature Matching with Transformers ubuntu18.04 预训练模型分享

    刚装好系统的空白系统ubuntu18 04安装 首先进入 软件与更新 换到国内源 论文下载 代码下载 1 anaconda 3 5 3 安装 Index of anaconda archive 清华大学开源软件镜像站 Tsinghua Op
  • Redis进阶

    一 Redis集群和分布式锁 1 1 Redis集群的概念和优势 Redis集群是一种分布式系统架构 它将多个Redis实例组成一个逻辑集群 实现数据的分布式存储和高可用性 每个Redis实例负责存储集群中的一部分数据 通过节点之间的协调和
  • 【Git】Linux系统下Git的升级

    Git 在很多发行版的 Linux 系统里的版本都很低 比如说比 2 18 这个版本还低 这里比较的一般就是码农的本地环境 因为本地 Mac 系统等等大家经常用到的预装的 Git 的版本都比较深 Git 的版本太低有很多衍生问题 除了本身
  • ROS中使用VLP16激光雷达获取点云数据

    ROS中使用VLP16激光雷达获取点云数据 个人博客地址 本文测试环境为 Ubuntu20 04 ROS Noetic 需要将激光雷达与PC连接 然后在设置 gt 网络 gt 有线中将IPv4改为手动 并且地址为192 168 1 100
  • Linux----一条命令更改主机名(临时

    前言 看了些许关于更改主机名的博客 觉得不够简单 略为繁琐 现在介绍两种极其简单的方法来修改主机名 hostname 查看当前主机名 一 临时修改主机名 hostname kiosk kiosk为想要更改的主机名 示例 注意 重启后即失效
  • Java中的private、protected、public和default的区别

    这个问题 应该很老了 但是确实是重点中的重点 如果没有真正的都用过这些修饰符 其实对其的作用并不深刻 我也没用过默认的修饰符 所以有时候也总把friendly和protected搞混 还因为这个丢失了一次很好的工作机会 随意今天又重新弄了一
  • STM32 CAN/CANFD软件快速配置(HAL库版本)

    STM32 CAN CANFD软件快速配置 HAL库版本 目录 STM32 CAN CANFD软件快速配置 HAL库版本 前言 1 软件编程 1 1 建立工程 1 2 初始化 1 2 1 引脚设置 1 2 2 CAN基本参数设置 1 2 3