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

CanFestival移植到STM32 F4芯片(基于HAL库)

本文讲述如何通过简单操作就可以把CanFestival库移植到STM32 F4芯片上,作为Slave设备。使用启明欣欣的工控板来做实验。


一 硬件连接

观察CAN报文需要专门的设备,本人从某宝上买了一个兼容PCAN的开源小板子,二十几块钱,通过USB接到电脑后就可以使用PCAN-View打开进行监控,非常方便,同时还带开关控制的120欧姆终端电阻,缺点是有时不太稳定,

![[Pasted image 20240831172709.png]]

这个小板子还需要通过CAN线和启明欣欣板子上的CAN口进行连接,如下图,这里连接的是CAN2,

![[Pasted image 20240831173148.png]]

工控板需要单独供电,不能依靠下载器的电,否则无法正常运行。最后打开小板子上的120欧姆电阻,开关拨到ON那一端就可以了。

PS:PCAN-View可以去PeakCAN官网下载,是免费软件;CAN线得是双绞线,H对H,L对L进行连接。


二 搭建CAN基础工程

硬件搭建好之后,先搭建一个CAN的基础工程,验证是否可以收发CAN消息,为后续移植打下基础。这里使用STM32CubeMX来操作。

打开STM32CubeMX,芯片选择STM32F407ZGT6,选好后创建工程。

配置时钟

在新界面里的Pinout & Configuration里选择RCC,然后高速时钟和低速时钟都选择Crystal/Ceramic Resonator

![[Pasted image 20240831181308.png]]

PS:启明欣欣的板子,其外部接了2个晶振,一个8M,一个32.768K,前者用于高速时钟,后者用于低速时钟,如果低速时钟没有外接晶振,那么就选disable。

此时点击Clock Configuration

![[Pasted image 20240831181611.png]]

然后按照红框里的步骤一个个更改,

![[Pasted image 20240831181644.png]]

第4步输入频率168后回车,CubeMX会自动调整,非常方便。另外,可以看到低速时钟LSE的输入频率是32.768K,这个也可以修改,需要结合实际。

这里要注意一下:配置完毕后APB1外设时钟是42M,APB1定时器时钟是84M,后面要用到。

设置SYS

回到Pinout & Configuration,然后点击SYS,右侧的选项按照如下进行选择,

![[Pasted image 20240831181843.png]]

PS:由于没有使用操作系统,所以这里的Timebase Source选择SysTick

开启CAN2

启明欣欣的CAN2对应的是PB12和PB13,其中PB12是RX,PB13是TX,先在Pinout view里右下角的搜索框中输入PB12,然后回车,就可以找到PB12,会闪烁,

![[Pasted image 20240831182433.png]]

点击该引脚,功能选择CAN2_RX,

![[Pasted image 20240831182632.png]]

同理找到PB13,将其设置为CAN2_TX,设置OK后会发现CAN2已经自动使能了。

![[Pasted image 20240831185148.png]]

这里设置一下CAN的通信速率,本教程使用500K,设置如上图红框,

  • Prescaler设置为6
  • Time Quanta in Bit Segment 1设置为7
  • Time Quanta in Bit Segment 2设置为6
  • ReSynchronization Jump Width设置为1

经过上述设置后,CAN的波特率就变成500K了。

设置原理:前面配置时钟时,APB1的外设时钟是42M,而CAN是属于APB1的外设,这样经过Prescaler的变频后就变成42M/6=7M,也就是7000K,然后除以(Time Quanta in Bit Segment 1 + Time Quanta in Bit Segment 2 + ReSynchronization Jump Width * 1),也就是7000K/14=500K

芯片手册上的波特率的计算原理如下,

![[Pasted image 20240831185438.png]]

可以看出上述配置并不是唯一选择,只要根据原理让波特率是500K就可以了。

最后是开启CAN2的接收中断,如下红框,勾选CAN2 RX0中断,

![[Pasted image 20240831185918.png]]

PS:RX0和RX1分别对应2个内部接收FIFO,这里选择FIFO0,后面会讲到如何设置

生成Keil工程

配置完毕,最后生成工程。

点击Project Manager,然后在Project里对红框标注的地方进行自定义修改

![[Pasted image 20240818090956.png]]

接着是Code Generator,按照如下勾选,也可以根据自己需要进行修改

![[Pasted image 20240818091151.png]]

设置完毕后点击右上角的GENERATE CODE来生成Keil工程

PS:Keil现在有社区版,个人使用是免费的,不用去破解了。

验证CAN通信

打开生成的Keil工程,然后先做以下配置,

  • 编译器使用V6版本

    ![[Pasted image 20240831190813.png]]

    如果使用的是老版的Keil,可能还得用V5版本的编译器

  • 取消勾选Browse Information,节约编译时间

    ![[Pasted image 20240831190907.png]]

  • 编译优化选项选择O1或O0,优化选项过高可能会造成调试时无法打断点

    ![[Pasted image 20240831190940.png]]

配置好之后,编译一下,保证工程可以顺利编译完成。

剩下是修改代码,主要参考这篇文章,不过该作者用的CAN1,这里再写一遍,在USER CODE BEGIN 4下面添加函数CANFilter_Config(),用于配置CAN2的过滤器,

void CANFilter_Config(void)
{CAN_FilterTypeDef  sFilterConfig;sFilterConfig.FilterBank = 0;                       // CAN过滤器编号,范围0-27sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;   // CAN过滤器模式,掩码模式或列表模式,这里选择掩码模式sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;  // CAN过滤器尺度,16位或32位,这里选择32位sFilterConfig.FilterIdHigh = 0x0000;                // 32位下,存储要过滤ID的高16位sFilterConfig.FilterIdLow  = 0x0000;                // 32位下,存储要过滤ID的低16位sFilterConfig.FilterMaskIdHigh = 0x0000;            // 掩码模式下,存储的是过滤器掩码的高16位sFilterConfig.FilterMaskIdLow  = 0x0000;            // 掩码模式下,存储的是过滤器掩码的低16位sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 报文通过过滤器的匹配后,存储到哪个FIFO,这里选择FIFO0sFilterConfig.FilterActivation = CAN_FILTER_ENABLE; // 激活过滤器sFilterConfig.SlaveStartFilterBank = 0;if (HAL_CAN_ConfigFilter(&hcan2, &sFilterConfig) != HAL_OK) {Error_Handler();}
}

选择FilterBank 0,配置成掩码模式,选择FIFO0来接收CAN报文(这个和前面选择RX0中断保持一致,如果使用FIFO1,那么前面就要勾选RX1中断)。掩码ID是全0,表示允许接收所有报文,芯片手册介绍如下,

![[Pasted image 20240831224249.png]]

PS:如果只想接收指定报文,那么就要配置掩码ID为非0,具体可以参考芯片手册。

然后添加CAN2的使能函数,

void CAN_Start_Init(void)
{if (HAL_CAN_Start(&hcan2) != HAL_OK) {Error_Handler();}if (HAL_CAN_ActivateNotification(&hcan2, CAN_IT_RX_FIFO0_MSG_PENDING) !=  HAL_OK){Error_Handler();}
}

还有发送函数,这个用来测试发送,

void CAN2_Send_Test(void)
{uint32_t TxMailbox;uint8_t data[4] = {0x01, 0x02, 0x03, 0x04};CAN_TxHeaderTypeDef TxMessage;TxMessage.IDE = CAN_ID_STD;     // 设置ID类型,标准帧还是扩展帧,这里选择标准帧TxMessage.StdId = 0x111;        // 设置ID号TxMessage.RTR = CAN_RTR_DATA;   // 设置传输数据帧TxMessage.DLC = 4;              // 设置数据长度if (HAL_CAN_AddTxMessage(&hcan2, &TxMessage, data, &TxMailbox) != HAL_OK){Error_Handler();}
}

最后是CAN2接收中断的回调函数,用来测试接收,

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{uint8_t data[8] = {0, 0, 0, 0, 0, 0, 0, 0};HAL_StatusTypeDef  status;CAN_RxHeaderTypeDef RxMessage;if (hcan == &hcan2) {  status = HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxMessage, data);if (HAL_OK == status){; // to do something}}
}

添加好之后,在USER CODE BEGIN PFP下添加函数声明,接收中断的回调函数不用声明,

/* USER CODE BEGIN PFP */void CANFilter_Config(void);
void CAN_Start_Init(void);
void CAN2_Send_Test(void);/* USER CODE END PFP */

然后在main函数里调用这些函数,每隔1s发送一次CAN报文,

![[Pasted image 20240831225340.png]]

再次编译并烧录到板子里,然后重启运行,此时在PCAN-View上可以看到CAN报文,说明发送没问题,

![[Pasted image 20240831230812.png]]

接着验证接收,此时先进入debug模式,然后在CAN接收中断里打个断点,

![[Pasted image 20240831231041.png]]

使用PCAN-View来创建一条随意报文,数据是0x9988,

![[Pasted image 20240831231158.png]]

然后点击OK进行保存,最后选中创建的报文按空格进行发送,此时会进入断点,

![[Pasted image 20240831231403.png]]

把data数组添加到Keil的Watch窗口中,然后单步走一步,可以看到data数组里有数据了,如下,正是之前发送的报文数据,

![[Pasted image 20240831231533.png]]


三 移植CanFestival

有了第二节的基础工程后,本节讲述如何移植CanFestival,适用于STM32 F4系列芯片。

对象字典的配置

首先规划一下Slave设备的对象字典,具体如下,

  • 每隔3s发送一次心跳报文
  • 添加对象0x2000_00 (u8类型), 0x2001_00 (u16类型), 0x2002_00 (u32类型), 0x2003_00 (i32类型),0x2004_00 (i16类型),0x2005_00 (Visible String类型),总共6个对象
  • RPDO1:对应0x2000_00,0x2001_00和0x2002_00
  • TPDO1:对应0x2003_00,每隔500ms发一次

这里使用objdictgen来进行编辑,其地址是https://github.com/happybruce/objdictgen,经过本人优化后可以使用Python3启动。
PS:这个编辑器原本是在CanFestival里自带的,本人把其独立出来了。

双击objdictedit.py打开编辑器,然后在File下点击New,在弹出的界面里进行以下设置,
![[Pasted image 20241201214413.png]]

点击OK,进入新的主界面,然后根据下述步骤进行配置,

配置心跳报文

接着在0x1000-0x1029里找到0x1017,将其值设置为3000 (其单位是毫秒,16进制是0xBB8)
![[Pasted image 20241201214707.png]]

添加对象

在0x2000-0x5FFF里添加之前提到的6个对象,
![[Pasted image 20241202230355.png]]

配置RPDO1

设置RPDO1的映射,该对象索引是0x1600,如下,对应0x2000_00, 0x2001_00和0x2002_00
![[Pasted image 20241202225034.png]]

设置RPDO1的通信参数,该对象索引是0x1400,这里只配置COB ID和Inhibit Time (10ms)
![[Pasted image 20241202225258.png]]

当设备收到COB ID的为NodeId+0x200的报文,就会把报文里包含的值存入对应的对象里。

配置TPDO1

设置TPDO1的映射,该对象索引是0x1A00,如下,对应0x2003_00
![[Pasted image 20241202225614.png]]

设置TPDO1的通信参数,该对象索引是0x1800,如下,
![[Pasted image 20241202225824.png]]

COB ID是nodeid+0x180,传输类型是254,即0xFE,定时时间是500ms,即0x1F4

这样对象字典就配置好了。最后保存工程,并生成对应的代码,点击File->Build Dictionary生成slavedic.c和slavedic.h
![[Pasted image 20241202230906.png]]

这2个文件暂时留着备用

开启定时器

打开CubeMX工程,然后开启TIM3,时钟源选择内部时钟,预分频系数输入839,

![[Pasted image 20240901133442.png]]

为什么是839呢?CanFestival对定时器的要求是counter每隔10us加1,也就是100KHz,而前面配置时钟时定时器的时钟频率是84MHz,如果以100KHz为单位,那么84M就等于840x100K, 那么为了达到100KHz的频率,预分频系数就是840-1=839

最后打开定时器中断,
![[Pasted image 20240901134020.png]]

移植

首先使用git clone下载CanFestival,

git clone https://github.com/happybruce/CanFestival.git
cd CanFestival
git checkout develop

这个Github地址是本人的仓库,已经对代码进行了优化。

在工程目录Core下添加以下目录结构,

![[Pasted image 20240901125648.png]]

然后做以下拷贝,

  • 把CanFestival/src目录下的红框标注的文件拷贝到Core/CanFestival/src/下,红叉的不要拷贝

    在这里插入图片描述

  • 把CanFestival/include目录下的以下文件拷贝到Core/CanFestival/inc/下,还有cm4目录也拷贝过来,

    在这里插入图片描述

  • 把CanFestival/drivers/cm4目录下的cm4.h和cm4.c拷贝到Core/CanFestival/drv下

  • 把CanFestival/examples/CM4/od/下的slavedic.c和slavedic.h拷贝到Core/CanFestival/slavedic下

拷贝完毕后打开Keil工程,点击以下按钮,

在这里插入图片描述

然后添加三个组及其对应的源文件,注意这里不需要添加头文件,后面给头文件设置搜索目录即可

在这里插入图片描述

添加完毕后点击OK,然后添加搜索目录,如下图2个步骤,
在这里插入图片描述
在弹出界面里填入以下目录,
在这里插入图片描述
最后点击OK,这样工程就配置好了。

main.c内容如下,

/* USER CODE BEGIN Header */
/********************************************************************************* @file           : main.c* @brief          : Main program body******************************************************************************* @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.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "can.h"
#include "tim.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "canfestival.h"
#include "slavedic.h"
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */void CANFilter_Config(void);
void CAN_Start_Init(void);
void CAN1_Send_Test(void);/* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_CAN2_Init();MX_TIM3_Init();/* USER CODE BEGIN 2 */initTimer(); // 初始化定时器canInit(&slavedic_ObjDictData, 500000); // 设置速率为500KHAL_TIM_Base_Start_IT(&htim3);CANFilter_Config();CAN_Start_Init();setNodeId(&slavedic_ObjDictData, 1); // 设置Canopen id为1setState(&slavedic_ObjDictData, Initialisation); // NMT状态设置为InitialisationsetState(&slavedic_ObjDictData, Pre_operational); // NMT状态设置为Pre_operationalsetState(&slavedic_ObjDictData, Operational); // NMT状态设置为Operational/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){HAL_Delay(1000);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** Configure the main internal regulator output voltage*/__HAL_RCC_PWR_CLK_ENABLE();__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLM = 4;RCC_OscInitStruct.PLL.PLLN = 168;RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;RCC_OscInitStruct.PLL.PLLQ = 4;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK){Error_Handler();}
}/* USER CODE BEGIN 4 */// static CAN_TxHeaderTypeDef TxMessage; //CAN发�?�的消息的消息头
// static CAN_RxHeaderTypeDef RxMessage; //CAN接收的消息的消息�???void CANFilter_Config(void)
{CAN_FilterTypeDef  sFilterConfig;sFilterConfig.FilterBank = 0;                       //CAN过滤器编号,范围0-27sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;   //CAN过滤器模式,掩码模式或列表模�???sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;  //CAN过滤器尺度,16位或32�???sFilterConfig.FilterIdHigh = 0x000 << 5;      //32位下,存储要过滤ID的高16�???sFilterConfig.FilterIdLow = 0x0000;          //32位下,存储要过滤ID的低16�???sFilterConfig.FilterMaskIdHigh = 0x0000;      //掩码模式下,存储的是掩码sFilterConfig.FilterMaskIdLow = 0x0000;sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;        //报文通过过滤器的匹配后,存储到哪个FIFOsFilterConfig.FilterActivation = CAN_FILTER_ENABLE;        //�???活过滤器sFilterConfig.SlaveStartFilterBank = 0;if (HAL_CAN_ConfigFilter(&hcan2, &sFilterConfig) != HAL_OK) {Error_Handler();}}void CAN_Start_Init(void)
{if (HAL_CAN_Start(&hcan2) != HAL_OK) {Error_Handler();}if (HAL_CAN_ActivateNotification(&hcan2, CAN_IT_RX_FIFO0_MSG_PENDING) !=  HAL_OK){Error_Handler();}
}void CAN1_Send_Test(void)
{uint32_t TxMailbox;CAN_TxHeaderTypeDef TxMessage;uint8_t data[4] = {0x01, 0x02, 0x03, 0x04};TxMessage.IDE = CAN_ID_STD;     //设置ID类型TxMessage.StdId = 0x111;        //设置ID�???TxMessage.RTR = CAN_RTR_DATA;   //设置传�?�数据帧TxMessage.DLC = 4;              //设置数据长度if (HAL_CAN_AddTxMessage(&hcan2, &TxMessage, data, &TxMailbox) != HAL_OK){Error_Handler();}  
}// void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
// {
//   uint8_t  data[8] = {0, 0, 0, 0, 0, 0, 0, 0};
//   HAL_StatusTypeDef  status;
//   CAN_RxHeaderTypeDef RxMessage;//   if (hcan == &hcan2)
//   {  
//     status = HAL_CAN_GetRxMessage(&hcan2, CAN_RX_FIFO0, &RxMessage, data);
//     if (HAL_OK == status)
//     {
//         // printf("--->Data Receieve!\r\n");
//         // printf("RxMessage.StdId is %#x\r\n",  RxMessage.StdId);
//         // printf("data[0] is 0x%02x\r\n", data[0]);
//         // printf("data[1] is 0x%02x\r\n", data[1]);
//         // printf("data[2] is 0x%02x\r\n", data[2]);
//         // printf("data[3] is 0x%02x\r\n", data[3]);
//         // printf("<---\r\n");//         __nop();//     }
//   }
// }/* USER CODE END 4 *//*** @brief  This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */
}#ifdef  USE_FULL_ASSERT
/*** @brief  Reports the name of the source file and the source line number*         where the assert_param error has occurred.* @param  file: pointer to the source file name* @param  line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

然后编译,烧录到板子上运行,如下,可以看到TPDO1每隔500毫秒发一次
在这里插入图片描述
由前面配置可知,TPDO1对应0x2003_00,这里通过PCAN view来发送SDO去修改这个对象值,
在这里插入图片描述
发送完后,可以看出TPDO1发出的值就变了,变成我们通过SDO写的值
在这里插入图片描述
然后通过PCAN View发一个RPDO1给板子,
在这里插入图片描述
发完之后通过SDO去读取0x2000_00, 0x2001_00和0x2002_00的值,如下,可以看出与RPDO1发出的值相等
在这里插入图片描述


四 总结

本文讲述了如何把CanFestival移植到STM32 F4系列芯片上,由于本人优化了CanFestival库,所以移植起来比较简单。

了解过程后,对于master或移植到CM3、CM0都很容易了。

相关文章:

CanFestival移植到STM32 F4芯片(基于HAL库)

本文讲述如何通过简单操作就可以把CanFestival库移植到STM32 F4芯片上&#xff0c;作为Slave设备。使用启明欣欣的工控板来做实验。 一 硬件连接 观察CAN报文需要专门的设备&#xff0c;本人从某宝上买了一个兼容PCAN的开源小板子&#xff0c;二十几块钱&#xff0c;通过USB接…...

构建安全的数据库环境:群晖NAS安装MySQL和phpMyAdmin详细步骤

文章目录 前言1. 安装MySQL2. 安装phpMyAdmin3. 修改User表4. 本地测试连接MySQL5. 安装cpolar内网穿透6. 配置MySQL公网访问地址7. 配置MySQL固定公网地址8. 配置phpMyAdmin公网地址9. 配置phpmyadmin固定公网地址 前言 本文将详细讲解如何在群晖NAS上安装MySQL及其数据库管理…...

相机(Camera)硬件组成详解

简介&#xff1a;个人学习分享&#xff0c;如有错误&#xff0c;欢迎批评指正。 写在前面&#xff1a;可以去B站观看一些相机原理的视频来配合学习&#xff0c;这里推荐&#xff1a;推荐1&#xff0c;推荐2&#xff0c;推荐3 相机&#xff08;Camera&#xff09;是一种复杂的光…...

【Linux———基础IO】

每一滴眼泪&#xff0c;每一次心碎&#xff0c;什么爱能无疚无悔.......................................................................... 文章目录 前言 一、【认识文件I/O】 1.1、【回顾C语言文件I/O】 1.2、【操作系统文件I/O】 1.2.1、【open函数】 1、【open函数的三…...

WebRTC服务质量(03)- RTCP协议

一、前言&#xff1a; RTCP&#xff08;RTP Control Protocol&#xff09;是一种控制协议&#xff0c;与RTP&#xff08;Real-time Transport Protocol&#xff09;一起用于实时通信中的控制和反馈。RTCP负责监控和调节实时媒体流。通过不断交换RTCP信息&#xff0c;WebRTC应用…...

[python SQLAlchemy数据库操作入门]-10.性能优化:提升 SQLAlchemy 在股票数据处理中的速度

哈喽,大家好,我是木头左! 当处理大量数据时,如股票数据,默认的ORM操作可能会显得效率低下。本文将探讨如何通过一些技巧和策略来优化SQLAlchemy ORM的性能,从而提升其在股票数据处理中的速度。 1. 选择合适的数据类型 在定义模型时,选择合适的数据类型对于性能至关重要…...

23种设计模式之中介者模式

目录 1. 简介2. 代码2.1 Mediator &#xff08;中介者接口&#xff09;2.2 ChatRoom &#xff08;具体中介者类&#xff09;2.3 User &#xff08;同事接口&#xff09;2.4 ChatUser &#xff08;具体同事类&#xff09;2.5 Test &#xff08;测试&#xff09;2.6 运行结果 3. …...

MySQL:GROUP_CONCAT分组合并

目录 一、概述二、用法三、分组去重 一、概述 GROUP_CONCAT函数要配合group by才能发挥作用&#xff0c;主要用于分组之后合并某一字段。 二、用法 SELECT GROUP_CONCAT(age) FROM tb_user GROUP BY banner;三、分组去重 SELECT GROUP_CONCAT(DISTINCT age) FROM tb_user GRO…...

递归方式渲染嵌套的菜单项

1. 递归组件 递归方式渲染嵌套的菜单项&#xff0c;这个是非常好的做法。为了避免在每个子菜单上都渲染一个新的 <ul> 标签&#xff0c;可以使用 v-if 来判断是否有子菜单&#xff0c;再决定是否渲染子菜单的部分。 2. 提高性能 对于递归渲染组件&#xff0c;Vue 可能…...

常用Vim操作

vimrc配置 ctags -R * 生成tags文件 set number set ts4 set sw4 set autoindent set cindent set tag~/tmp/log/help/tags 自动补全&#xff1a; ctrln&#xff1a;自动补全 输入&#xff1a; a&#xff1a;从当前文字后插入i&#xff1a;从当前文字前插入s: 删除当前字…...

spark3 sql优化:同一个表关联多次,优化方案

目录 1.合并查询2.使用 JOIN 条件的过滤优化3.使用 Map-side Join 或 Broadcast Join4.使用 Partitioning 和 Bucketing5.利用 DataFrame API 进行优化假设 A 和 B 已经加载为 DataFramePerform left joins with specific conditions6.使用缓存或持久化7.避免笛卡尔积总结 1.合…...

XML 在线格式化 - 加菲工具

XML 在线格式化 打开网站 加菲工具 选择“XML 在线格式化” 输入XML&#xff0c;点击左上角的“格式化”按钮 得到格式化后的结果...

陪玩系统小程序源码/游戏陪玩APP系统用户端有哪些功能?游戏陪玩小程序APP源码开发

多客陪玩系统-游戏陪玩线下预约上门服务等陪玩圈子陪玩社区系统源码 陪玩系统源码&#xff0c;高质量的陪玩系统源码&#xff0c;游戏陪玩APP源码开发&#xff0c;语音陪玩源码搭建: 线上陪玩活动组局与线下家政服务系统的部署需要综合考虑技术选型、开发流程、部署流程、功能实…...

力扣-图论-9【算法学习day.59】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向和记录学习过程&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非…...

ViT学习笔记(三) RepViT和TransNext简介

标准ViT的其他模块的功能以及源码解读&#xff0c;在CSDN上有很多优秀文章&#xff0c;参考文章将代码大致过一遍。像我这种只做工程不写论文的&#xff0c;个人认为大致明白就好&#xff0c;用不着特别细究。下面跟踪两个ViT比较新的变种继续深入学习一下&#xff1a;RepViT和…...

大华DSS数字监控系统 attachment_downloadAtt.action 任意文件下载漏洞复现

0x01 产品描述: 大华 DSS 数字监控系统是大华开发的一款安防视频监控系统,拥有实时监视、云台操作、录像回放、报警处理、设备管理等功能。0x02 漏洞描述: 大华DSS数字监控系统 attachment_downloadAtt.action接口存在任意文件读取漏洞,未经身份验证攻击者可通过该漏洞读取…...

Dockerfile容器镜像构建技术

文章目录 1、容器回顾1_容器与容器镜像之间的关系2_容器镜像分类3_容器镜像获取的方法 2、其他容器镜像获取方法演示1_在DockerHub直接下载2_把操作系统的文件系统打包为容器镜像3_把正在运行的容器打包为容器镜像 3、Dockerfile介绍4、Dockerfile指令1_FROM2_RUN3_CMD4_EXPOSE…...

LabVIEW实现MQTT通信

目录 1、MQTT通信原理 2、硬件环境部署 3、云端环境部署 4、程序架构 5、前面板设计 6、程序框图设计 7、测试验证 本专栏以LabVIEW为开发平台,讲解物联网通信组网原理与开发方法,覆盖RS232、TCP、MQTT、蓝牙、Wi-Fi、NB-IoT等协议。 结合实际案例,展示如何利用LabVIEW和常用…...

分布式事物XA、BASE、TCC、SAGA、AT

分布式事务——Seata 一、Seata的架构&#xff1a; 1、什么是Seata&#xff1a; 它是一款分布式事务解决方案。官网查看&#xff1a;Seata 2.执行过程 在分布式事务中&#xff0c;会有一个入口方法去调用各个微服务&#xff0c;每一个微服务都有一个分支事务&#xff0c;因…...

[创业之路-182]:《华为战略管理法-DSTE实战体系》-1-华为的发展历程和战略管理演变

目录 前言、华为在战略管理上做对了什么&#xff1f; 1、前瞻性的战略眼光 2、有效的战略解码 3、灵活的战略调整 4、注重创新和研发 5、以客户为中心的战略导向 6、完善的内部管理体系 一、华为不同时期的战略选择 1.1 华为不同时期的战略选择 1、创业初期&#xff…...

python爬虫--小白篇【爬取B站视频】

目录 一、任务分析 二、网页分析 三、任务实现 一、任务分析 将B站视频爬取并保存到本地&#xff0c;经过分析可知可以分为四个步骤&#xff0c;分别是&#xff1a; 爬取视频页的网页源代码&#xff1b;提取视频和音频的播放地址&#xff1b;下载并保存视频和音频&#x…...

web 自动化 selenium

1、下载Chrome对应的driver版本 我的chrome是 131.0.6778.109&#xff0c;我下载的driver是131.0.6778.69&#xff08;想找一模一样的&#xff0c;但是没有&#xff09; https://googlechromelabs.github.io/chrome-for-testing/ chromedriver下载 2、配置Chrome deriver及 …...

【OpenCV】Canny边缘检测

理论 Canny 边缘检测是一种流行的边缘检测算法。它是由 John F. Canny 在 1986 年提出。 这是一个多阶段算法&#xff0c;我们将介绍算法的每一个步骤。 降噪 由于边缘检测易受图像中的噪声影响&#xff0c;因此第一步是使用 5x5 高斯滤波器去除图像中的噪声。我们在前面的章…...

D94【python 接口自动化学习】- pytest进阶之fixture用法

day94 pytest的fixture详解 学习日期&#xff1a;20241210 学习目标&#xff1a;pytest基础用法 -- pytest的fixture详解 学习笔记&#xff1a; fixture的介绍 fixture是 pytest 用于将测试前后进行预备、清理工作的代码处理机制。 fixture相对于setup和teardown来说有以…...

关于idea-Java-servlet-Tomcat-Web开发中出现404NOT FOUND问题的解决

在做web项目时&#xff0c;第一次使用servlet开发链接前端和后端的操作&#xff0c;果不其然&#xff0c;遇到了诸多问题&#xff0c;而遇到最多的就是运行项目打开页面时出现404NOT FOUND的情况。因为这个问题我也是鼓捣了好久&#xff0c;上网查了许多资料才最终解决&#xf…...

SpringBoot Maven快速上手

文章目录 一、Maven 1.1 Maven 简介&#xff1a;1.2 Maven 的核心功能&#xff1a; 1.2.1 项目构建&#xff1a;1.2.2 依赖管理&#xff1a; 1.3 Maven 仓库&#xff1a; 1.3.1 本地仓库&#xff1a;1.3.2 中央仓库&#xff1a;1.3.3 私服&#xff1a; 二、第一个 SpringBoot…...

全面解析MySQL底层概念

mysql的概念 &#xff08;1&#xff09;mysql的架构 客户端请求--->连接器&#xff08;验证用户身份&#xff0c;给予权限&#xff09;--->查询缓存&#xff08;存在则直接返回&#xff0c;不存在则执行后续操作 --->分析器&#xff08;对SQL进行词法分析和语法分析…...

【C++】string类

一、C 标准库中的string类 1、string类 string类的文档介绍 首先string并不是STL中的&#xff0c;而是一个类string比STL出现的早 从上面可以看出string是从一个类模板中实例化出来的一个对象 在使用string类是必须要包头文件#include< string > 又因为是std中的类…...

《Python制作动态爱心粒子特效》

一、实现思路 粒子效果&#xff1a; – 使用Pygame模拟粒子运动&#xff0c;粒子会以爱心的轨迹分布并运动。爱心公式&#xff1a; 爱心的数学公式&#xff1a; x16sin 3 (t),y13cos(t)−5cos(2t)−2cos(3t)−cos(4t) 参数 t t 的范围决定爱心形状。 动态效果&#xff1a; 粒子…...

ssd202d-badblock-坏块检测

这边文章讲述的是坏快检测功能 思路: 1.第一次烧录固件会实现跳坏块,但是后续使用会导致坏块的产生; 于是我在uboot环境变量添加了两个变量来控制坏快 lb_badnum = //坏块个数 lb_badoff = //坏块所在位置 2.第一次开机会根据lb_badnum是否存在判断,如果不存在则保存上…...

使用html 和javascript 实现微信界面功能1

1.功能说明&#xff1a; 搜索模块: 提供一个搜索框&#xff0c;但目前没有实现具体的搜索功能。 好友模块: 在左侧的“好友”部分有一个“查看好友”按钮。点击左侧的“查看好友”按钮时&#xff0c;会在右侧显示所有好友的列表。列表中每个好友可以点击查看详情&#xff0c;包…...

趣味编程:猜拳小游戏

1.简介 这个系列的第一篇以猜拳小游戏开始&#xff0c;这是源于我们生活的灵感&#xff0c;在忙碌的时代中&#xff0c;我们每个人都在为自己的生活各自忙碌着&#xff0c;奔赴着自己所走向的那条路上&#xff0c;即使遍体鳞伤。 但是&#xff0c;生活虽然很苦&#xff0c;也不…...

图形化界面MySQL(MySQL)(超级详细)

目录 1.官网地址 1.1在Linux直接点击NO thanks..... 1.2任何远端登录&#xff0c;再把jj数据库给授权 1.3建立新用户 优点和好处 示例代码&#xff08;MySQL Workbench&#xff09; 示例代码&#xff08;phpMyAdmin&#xff09; 总结 图形化界面 MySQL 工具大全及其功…...

JavaScript技巧方法总结

技巧总结 字符串字符串首字母大写翻转字符串字符串过滤 数字十进制转换二进制、八进制、十六进制获取随机数字符串转数字指数幂运算 数组从数组中过滤出虚假值数组查找检测是否为一个安全数组数组清空实现并集、交集、和差集 对象检查对象是否为空从对象中选择指定数据动态属性…...

【Web】2023安洵杯第六届网络安全挑战赛 WP

目录 Whats my name easy_unserialize signal Swagger docs 赛题链接&#xff1a;GitHub - D0g3-Lab/i-SOON_CTF_2023: 2023 第六届安洵杯 题目环境/源码 Whats my name 第一段正则用于匹配以 include 结尾的字符串&#xff0c;并且在 include 之前&#xff0c;可以有任…...

【VUE2】纯前端播放海康视频录像回放,视频格式为rtsp格式,插件使用海康视频插件[1.5.4版本]

一、需求 1、后端从海康平台拉流视频回放数据&#xff0c;前端进行页面渲染播放&#xff0c;视频格式为rtsp eg&#xff1a; 基本格式&#xff1a;rtsp://<username>:<password><ip_addr>:<port>/<path>参数说明&#xff1a; username&#xff…...

mysql程序介绍,选项介绍(常用选项,指定选项的方式,特性),命令介绍(查看,部分命令),从sql文件执行sql语句的两种方法

目录 mysql程序 介绍 选项 介绍 常用选项 指定选项的方式 ​编辑配置文件 环境变量 选项特性 指定选项 选项名 选项值 命令 介绍 查看客户端命令 tee/notee prompt source system help contents 从.sql文件执行sql语句 介绍 方式 source 从外部直接导入…...

3D 生成重建032-Find3D去找到它身上的每一份碎片吧

3D 生成重建032-Find3D去找到它身上的每一份碎片吧 文章目录 0 论文工作1 论文方法2 实验结果 0 论文工作 该论文研究三维开放世界部件分割问题&#xff1a;基于任何文本查询分割任何物体中的任何部件。以往的方法在物体类别或部件词汇方面存在局限性。最近人工智能的进步在二…...

树莓派4B android 系统添加led灯 Hal 层

本文内容需要用到我上一篇文章做的驱动&#xff0c;可以先看文章https://blog.csdn.net/ange_li/article/details/136759249 一、Hal 层的实现 1.Hal 层的实现一般放在 vendor 目录下&#xff0c;我们在 vendor 目录下创建如下的目录 aosp/vendor/arpi/hardware/interfaces/…...

LLama系列模型简要概述

LLama-1&#xff08;7B, 13B, 33B, 65B参数量&#xff1b;1.4T tokens训练数据量&#xff09; 要做真正Open的AI Efficient&#xff1a;同等预算下&#xff0c;增大训练数据&#xff0c;比增大模型参数量&#xff0c;效果要更好 训练数据&#xff1a; 书、Wiki这种量少、质量高…...

Elasticsearch使用(2):docker安装es、基础操作、mapping映射

1 安装es 1.1 拉取镜像 docker pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/elasticsearch:7.17.3 1.2 运行容器 运行elasticsearch容器&#xff0c;挂载的目录给更高的权限&#xff0c;否则可能会因为目录权限问题导致启动失败&#xff1a; docker r…...

Python跳动的爱心

系列文章 序号直达链接表白系列1Python制作一个无法拒绝的表白界面2Python满屏飘字表白代码3Python无限弹窗满屏表白代码4Python李峋同款可写字版跳动的爱心5Python流星雨代码6Python漂浮爱心代码7Python爱心光波代码8Python普通的玫瑰花代码9Python炫酷的玫瑰花代码10Python多…...

安卓手机怎么轻松转换更新ip网络地址

随着移动互联网的快速发展&#xff0c;IP地址作为网络身份标识的重要性日益凸显。对于安卓手机用户来说&#xff0c;但有时候我们希望能够轻松转更换ip地址&#xff0c;以提高网络安全性或访问特定内容的需要。那么&#xff0c;安卓手机如何更换IP地址呢&#xff1f;本文将为您…...

socket UDP 环路回显的服务端

基于socket通讯的方式&#xff0c;无论用http或者udp或者自定义的协议&#xff0c;程序结构都是类似的。这个以UDP协议为例简要说明。 #include <stdio.h> // 标准输入输出库 #include <sys/types.h> // 提供了一些数据类型&#xff0c;如ssize_t #include <sy…...

单例模式的缺点

1. 违反单一职责原则 单例模式不仅管理对象的实例化&#xff0c;还负责提供对该实例的全局访问。这使得单例类承担了过多的职责。复杂的单例类可能变得难以维护和扩展。 2. 难以进行单元测试 单例模式引入了全局状态&#xff0c;使得测试环境中的依赖关系难以隔离。在测试中…...

如何通过看板进行跨境电商的圣诞商品数据分析与优化选品流程?

引言 随着圣诞季的临近&#xff0c;跨境电商迎来了重要的销售时机。选品工作对于跨境电商的成功至关重要&#xff0c;直接关系到销售业绩和利润。本文结合相关网页信息&#xff0c;深入探讨跨境电商在圣诞期间如何利用信息整合工具展开选品工作&#xff0c;并优化选品流程。同…...

【Linux】vi/vim 使用技巧

文章目录 1. 简介vi和vim的历史vi和vim的区别安装vimUbuntu/DebianCentOS/RHELFedoramacOSWindows 2. 基本操作启动和退出启动退出 模式介绍普通模式插入模式命令模式 光标移动基本移动高级移动 3. 文本编辑插入文本删除文本复制和粘贴撤销和重做 4. 搜索与替换基本搜索搜索文本…...

React的功能是什么?

以下是一些React的主要功能和特点&#xff1a; 组件化架构&#xff1a; React将UI拆分为可复用的独立组件&#xff0c;每个组件负责一部分UI的逻辑和展示。组件可以嵌套使用&#xff0c;形成复杂的UI结构。 虚拟DOM&#xff1a; React使用虚拟DOM来管理UI的状态和更新&#xff…...

【6】数据分析检测(DataFrame 1)

学习目标3 昨天&#xff0c;我们学习了Series。 而Pandas的另一种数据类型&#xff1a;DataFrame&#xff0c;在许多特性上和Series有相似之处。 今天&#xff0c;我们将学习DataFrame的相关知识&#xff1a; 1. DataFrame的概念 2. 构造一个DataFrame 3. DataFrame的常用…...

React初体验 - [Next.js项目]

效果 须知 Next.js与React有哪些区别?https://juejin.cn/post/7112334604027035655 React中文手册 https://react.docschina.org/learn/start-a-new-react-project Next.js中文手册 https://www.nextjs.cn/docs/getting-started 步骤 npx提速 - 更换npm国内源 - 参考文档 …...