STM32与openmv的串口通信
OpenMV与STM32的通信是嵌入式系统和物联网领域中的一项重要技术。OpenMV是一种开源的微型机器视觉模块,基于ARM Cortex-M7微控制器,支持多种图像处理功能,如颜色识别、形状检测等。而STM32是STMicroelectronics公司推出的基于ARM Cortex内核的32位微控制器系列,具有高性能、低功耗和丰富的外设接口。
在OpenMV与STM32之间建立通信,常用的方式包括UART(通用异步收发传输器)、SPI(串行外设接口)和I2C(两线式串行总线)等。这些通信协议各有特点,如UART适合长距离通信,SPI和I2C则更适合短距离通信。在选择通信协议时,需要考虑数据传输速率、硬件资源、通信距离以及复杂度等因素。
实现OpenMV与STM32的通信,需要在硬件上进行引脚连接,确保双方的工作电压一致,并正确连接TX(发送)和RX(接收)引脚。在软件方面,需要分别在OpenMV和STM32上配置相应的通信接口参数,如波特率、数据位、停止位等,以确保双方能够正确地进行数据传输。
通过OpenMV与STM32的通信,可以实现图像数据的实时传输和处理,为嵌入式系统和物联网应用提供了强大的机器视觉功能。这种通信方式在智能小车、机器人、无人机等领域具有广泛的应用前景。
OpenMV与STM32之间的通信通常通过串行通信接口(如UART、SPI或I2C)来实现。这些接口允许两个设备之间以数字信号的形式交换数据。以下是OpenMV与STM32通信的几种常见方法:
1. UART(通用异步收发传输器)

UART是最常用的串行通信接口之一,它不需要时钟同步信号,而是使用起始位、数据位、校验位和停止位来标记数据的开始和结束。
硬件连接:将OpenMV的TX(发送)引脚连接到STM32的RX(接收)引脚,同时将OpenMV的RX(接收)引脚连接到STM32的TX(发送)引脚。确保两个设备的GND(地线)也连接在一起。
软件配置:在OpenMV上,使用pyb.UART()函数来初始化串口。在STM32上,使用STM32CubeMX或手动配置USART外设,并编写代码来初始化串口。
数据通信:在OpenMV上,使用uart.send()或uart.write()函数发送数据。在STM32上,使用中断或轮询方式接收数据,并使用HAL_UART_Receive()等函数读取数据。
2. SPI(串行外设接口)

SPI是一种同步串行通信协议,它使用主从设备架构,其中一个设备作为主机(通常是STM32),其他设备作为从机(如OpenMV,但需要注意OpenMV的SPI支持情况)。
硬件连接:连接MOSI(主出从入)、MISO(主入从出)、SCK(时钟)和CS(片选)引脚。确保GND也连接在一起。
软件配置:在OpenMV上,如果支持SPI,则使用pyb.SPI()函数来初始化SPI接口。在STM32上,使用STM32CubeMX或手动配置SPI外设。
数据通信:在OpenMV上,使用spi.send()和spi.recv()等函数进行数据传输。在STM32上,使用HAL_SPI_Transmit()和HAL_SPI_Receive()等函数进行数据传输。
注意:OpenMV的SPI支持可能因版本和硬件配置而异,因此在使用前需要查阅OpenMV的官方文档以确认其SPI功能。
3. I2C(总线)

I2C也是一种同步串行通信协议,它使用两根线(SDA数据线和SCL时钟线)进行数据传输。与SPI相比,I2C支持多个从设备连接到一个主设备。
硬件连接:连接SDA和SCL引脚,以及GND。
软件配置:在OpenMV上,如果支持I2C,则使用pyb.I2C()函数来初始化I2C接口。在STM32上,使用STM32CubeMX或手动配置I2C外设。
数据通信:在OpenMV上,使用i2c.send()和i2c.recv()等函数进行数据传输。在STM32上,使用HAL_I2C_Master_Transmit()和HAL_I2C_Master_Receive()等函数进行数据传输。
注意:同样地,OpenMV的I2C支持也可能因版本和硬件配置而异。
总结
在选择通信接口时,需要考虑数据传输速率、设备数量、硬件资源和软件复杂度等因素。UART通常是最简单且最常用的选择,而SPI和I2C则适用于需要更高数据传输速率或需要连接多个从设备的场景。在编写代码时,务必确保两个设备的通信参数(如波特率、数据位、停止位、校验位等)一致,以避免通信错误。
通信原理:
1、通信基础
通信方式:OpenMV与STM32之间的通信主要通过串口(UART)实现,这是一种异步通信方式,不需要时钟同步信号,而是直接在数据信号中穿插一些用于同步的信号位,或者以数据帧的格式传输数据。
硬件连接:在硬件连接上,OpenMV的TX(发送)引脚连接到STM32的RX(接收)引脚,同时OpenMV的RX(接收)引脚连接到STM32的TX(发送)引脚。通常,OpenMV的UART引脚为P4(TX)和P5(RX),而STM32的UART引脚则根据具体型号有所不同,如STM32F103系列的USART1通常使用PA9(TX)和PA10(RX)。此外,还需要确保OpenMV和STM32的电源和地线正确连接,以保证稳定的电源供应和信号传输。
2、通信过程
初始化:在通信开始前,需要在OpenMV和STM32上分别进行初始化设置。在OpenMV端,需要编写Python代码来配置串口,包括设置波特率、数据位、停止位和校验位等参数。在STM32端,则需要使用STM32CubeMX或手动配置时钟和GPIO引脚,并编写代码来初始化串口,确保与OpenMV的串口配置一致。
数据发送:在OpenMV端,可以通过串口发送数据。数据可以包括图像识别结果(如目标坐标、大小等)。发送数据前,需要编写函数来打包需要发送的数据,并通过串口发送。数据打包时,可以使用特定的字节作为帧头和帧尾,以确保数据传输的准确性和可靠性。
数据接收:在STM32端,需要编写接收中断服务函数来读取接收到的数据,并根据数据帧格式进行解析。接收数据时,STM32需要不断地检查串口接收缓冲区,当接收到完整的数据帧时,进行解析并提取出有效数据。如果数据帧不完整或格式错误,则需要丢弃当前数据帧并等待下一个数据帧的到来。
一、串口通信传输两个数据(x坐标和y坐标)
(一)、 OPENMV串口通信部分
import sensor, image, time,math,pyb
from pyb import UART,LED
import json
import ustructsensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 2000)
sensor.set_auto_gain(False) # must be turned off for color tracking
sensor.set_auto_whitebal(False) # must be turned off for color tracking
red_threshold_01=(10, 100, 127, 32, -43, 67)
clock = time.clock()uart = UART(3,115200) #定义串口3变量
uart.init(115200, bits=8, parity=None, stop=1) # init with given parametersdef find_max(blobs): #定义寻找色块面积最大的函数max_size=0for blob in blobs:if blob.pixels() > max_size:max_blob=blobmax_size = blob.pixels()return max_blobdef sending_data(cx,cy,cw,ch):global uart;#frame=[0x2C,18,cx%0xff,int(cx/0xff),cy%0xff,int(cy/0xff),0x5B];#data = bytearray(frame)data = ustruct.pack("<bbhhhhb", #格式为俩个字符俩个短整型(2字节)0x2C, #帧头10x12, #帧头2int(cx), # up sample by 4 #数据1int(cy), # up sample by 4 #数据2int(cw), # up sample by 4 #数据1int(ch), # up sample by 4 #数据20x5B)uart.write(data); #必须要传入一个字节数组while(True):clock.tick()img = sensor.snapshot()blobs = img.find_blobs([red_threshold_01])max_b = find_max(blobs)cx=0;cy=0;if blobs:#如果找到了目标颜色cx=max_b[5]cy=max_b[6]cw=max_b[2]ch=max_b[3]img.draw_rectangle(max_b[0:4]) # rectimg.draw_cross(max_b[5], max_b[6]) # cx, cyFH = bytearray([0x2C,0x12,cx,cy,cw,ch,0x5B])#sending_data(cx,cy,cw,ch)uart.write(FH)print(cx,cy,cw,ch)在这里插入代码片
STM32端的代码相对复杂,涉及到硬件抽象层(HAL)或标准外设库(SPL)的使用,以及串口中断服务函数的编写。基本思路是初始化串口,编写接收中断服务函数来读取数据,并根据数据帧格式进行解析和处理。
接下来请看STM32串口通信部分的代码:
#include "uart.h"
#include "oled.h"
#include "stdio.h"static u8 Cx=0,Cy=0,Cw=0,Ch=0;void USART1_Init(void)
{//USART1_TX:PA 9 //USART1_RX:PA10GPIO_InitTypeDef GPIO_InitStructure; //串口端口配置结构体变量USART_InitTypeDef USART_InitStructure; //串口参数配置结构体变量NVIC_InitTypeDef NVIC_InitStructure; //串口中断配置结构体变量RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //打开PA端口时钟//USART1_TX PA9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA9GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设定IO口的输出速度为50MHzGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9//USART1_RX PA10GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PA10GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA10 //USART1 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ; //抢占优先级0NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //子优先级2NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器//USART 初始化设置USART_InitStructure.USART_BaudRate = 115200; //串口波特率为115200USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式USART_InitStructure.USART_StopBits = USART_StopBits_1; //一个停止位USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式USART_Init(USART1, &USART_InitStructure); //初始化串口1USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //使能中断USART_Cmd(USART1, ENABLE); //使能串口1//如下语句解决第1个字节无法正确发送出去的问题USART_ClearFlag(USART1, USART_FLAG_TC); //清串口1发送标志}//USART1 全局中断服务函数
void USART1_IRQHandler(void)
{u8 com_data; u8 i;static u8 RxCounter1=0;static u16 RxBuffer1[10]={0};static u8 RxState = 0; static u8 RxFlag1 = 0;if( USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) //接收中断 {USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志com_data = USART_ReceiveData(USART1);if(RxState==0&&com_data==0x2C) //0x2c帧头{RxState=1;RxBuffer1[RxCounter1++]=com_data;OLED_Refresh();}else if(RxState==1&&com_data==0x12) //0x12帧头{RxState=2;RxBuffer1[RxCounter1++]=com_data;}else if(RxState==2){RxBuffer1[RxCounter1++]=com_data;if(RxCounter1>=10||com_data == 0x5B) //RxBuffer1接受满了,接收数据结束{RxState=3;RxFlag1=1;Cx=RxBuffer1[RxCounter1-5];Cy=RxBuffer1[RxCounter1-4];Cw=RxBuffer1[RxCounter1-3];Ch=RxBuffer1[RxCounter1-2];}}else if(RxState==3) //检测是否接受到结束标志{if(RxBuffer1[RxCounter1-1] == 0x5B){USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);//关闭DTSABLE中断if(RxFlag1){OLED_Refresh();OLED_ShowNum(0, 0,Cx,3,16,1);OLED_ShowNum(0,17,Cy,3,16,1);OLED_ShowNum(0,33,Cw,3,16,1);OLED_ShowNum(0,49,Ch,3,16,1);}RxFlag1 = 0;RxCounter1 = 0;RxState = 0;USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);}else //接收错误{RxState = 0;RxCounter1=0;for(i=0;i<10;i++){RxBuffer1[i]=0x00; //将存放数据数组清零}}} else //接收异常{RxState = 0;RxCounter1=0;for(i=0;i<10;i++){RxBuffer1[i]=0x00; //将存放数据数组清零}}}}
(一)OPENMV串口部分
from machine import Pin
import sensor, image, time, pyb
#import seekfree
from pyb import UART# 初始化TFT180屏幕
#lcd = seekfree.LCD180(3)# 初始化摄像头
sensor.reset()
sensor.set_pixformat(sensor.RGB565) # 设置图像色彩格式为RGB565格式
sensor.set_framesize(sensor.QQVGA) # 设置图像大小为160*120
sensor.set_auto_whitebal(True) # 设置自动白平衡
sensor.set_brightness(3000) # 设置亮度为3000
sensor.skip_frames(time = 20) # 跳过帧
uart = UART(3, 115200,timeout_char=3000) #配置串口
clock = time.clock()def sending_data(cx,cy,cw,ch):global uart;data = ustruct.pack("<bbhhb", #格式为俩个字符俩个短整型(2字节)0x2C, #帧头10x12, #帧头2int (cx1), # up sample by 4 #数据26int (cy1),int (cx2), # up sample by 4 #数据26int (cy2),int (cx3), # up sample by 4 #数据26int (cy3),int (cx4), # up sample by 4 #数据26int (cy4),0x5B)uart.write(data); #必须要传入一个字节数组while(True):clock.tick()img = sensor.snapshot()# -----矩形框部分-----# 在图像中寻找矩形for r in img.find_rects(threshold = 10000):# 判断矩形边长是否符合要求if r.w() > 20 and r.h() > 20:# 在屏幕上框出矩形img.draw_rectangle(r.rect(), color = (255, 0, 0), scale = 4)# 获取矩形角点位置corner = r.corners()# 在屏幕上圈出矩形角点img.draw_circle(corner[0][0], corner[0][1], 5, color = (0, 0, 255), thickness = 2, fill = False)img.draw_circle(corner[1][0], corner[1][1], 5, color = (0, 0, 255), thickness = 2, fill = False)img.draw_circle(corner[2][0], corner[2][1], 5, color = (0, 0, 255), thickness = 2, fill = False)img.draw_circle(corner[3][0], corner[3][1], 5, color = (0, 0, 255), thickness = 2, fill = False)# 打印四个角点坐标, 角点1的数组是corner[0], 坐标就是(corner[0][0],corner[0][1])# 角点检测输出的角点排序每次不一定一致,矩形左上的角点有可能是corner0,1,2,3其中一个corner1_str = f"corner1 = ({corner[0][0]},{corner[0][1]})"corner2_str = f"corner2 = ({corner[1][0]},{corner[1][1]})"corner3_str = f"corner3 = ({corner[2][0]},{corner[2][1]})"corner4_str = f"corner4 = ({corner[3][0]},{corner[3][1]})"print(corner1_str + "\n" + corner2_str + "\n" + corner3_str + "\n" + corner4_str)# 显示到屏幕上,此部分会降低帧率#lcd.show_image(img, 160, 120, 0, 0, zoom=0) #屏幕显示#串口通信传输的数据cx1=(int)(corner[0][0]*10)cy1=(int)(corner[0][1]*10)cx2=(int)(corner[1][0]*10)cy2=(int)(corner[1][1]*10)cx3=(int)(corner[2][0]*10)cy3=(int)(corner[2][1]*10)cx4=(int)(corner[3][0]*10)cy4=(int)(corner[3][1]*10)FH=bytearray([0x2C,0x12,cx1,cy1,cx2,cy2,cx3,cy3,cx4,cy4,0x5B])uart.write(FH)cx1=0cy1=0cx2=0cy2=0cx3=0cy3=0cx4=0cy4=0# 打印帧率print(clock.fps())
STM32串口通信部分
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>
#include "OLED.h"
#include "LED.h"
#include "Serial.h"uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
static int16_t Cx1=0,Cy1=0,Cx2=0,Cy2=0,Cx3=0,Cy3=0,Cx4=0,Cy4=0; int Cx5[16];//用于存放分段求的坐标值
int Cy5[16];
//static u8 RxFlag1 = 0;//串口中断接收标志位extern float Ang1,Ang2,AngFlag;
extern float Angle1,Angle2;int avel_X1 ;
int avel_X2 ;
int avel_X3 ;
int avel_X4 ;int avel_Y1 ;
int avel_Y2 ;
int avel_Y3 ;
int avel_Y4 ;void Serial_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//TXGPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//RXGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);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(USART3, &USART_InitStructure);USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);USART_Cmd(USART3, ENABLE);
}void Serial_SendByte(uint8_t Byte)
{USART_SendData(USART3, Byte);while (USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
}void Serial_SendArray(uint8_t *Array, uint16_t Length)
{uint16_t i;for (i = 0; i < Length; i ++){Serial_SendByte(Array[i]);}
}void Serial_SendString(char *String)
{uint8_t i;for (i = 0; String[i] != '\0'; i ++){Serial_SendByte(String[i]);}
}uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{uint32_t Result = 1;while (Y --){Result *= X;}return Result;
}void Serial_SendNumber(uint32_t Number, uint8_t Length)
{uint8_t i;for (i = 0; i < Length; i ++){Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');}
}int fputc(int ch, FILE *f)
{Serial_SendByte(ch);return ch;
}void Serial_Printf(char *format, ...)
{char String[100];va_list arg;va_start(arg, format);vsprintf(String, format, arg);va_end(arg);Serial_SendString(String);
}
//USART3 全局中断服务函数
void USART3_IRQHandler(void)
{int com_data; u8 i;u8 Jieshou = 1;static u8 RxCounter1=0;static int RxBuffer1[16]={0};static u8 RxState = 0; static u8 RxFlag1 = 0;//串口中断接收标志位,已被移除至函数体外作为全局变量if( USART_GetITStatus(USART3,USART_IT_RXNE)!=RESET && Jieshou == 1) //接收中断 {
// OLED_ShowSignedNum(1,1,520,4);USART_ClearITPendingBit(USART3,USART_IT_RXNE); //清除中断标志com_data = USART_ReceiveData(USART3);if(Jieshou == 1){if(RxState==0&&com_data==0x2C) //0x2c帧头{RxBuffer1[RxCounter1++]=com_data;RxState=1;}else if(RxState==1&&com_data==0x12) //0x12帧头{RxBuffer1[RxCounter1++]=com_data;RxState=2;} else if(RxState==2){RxBuffer1[RxCounter1++]=com_data;if(RxCounter1>=14||com_data == 0x5B) //RxBuffer1接受满了,接收数据结束{RxState=3;RxFlag1=1;Jieshou = 2;Cx1=RxBuffer1[RxCounter1-9];Cy1=RxBuffer1[RxCounter1-8];Cx2=RxBuffer1[RxCounter1-7];Cy2=RxBuffer1[RxCounter1-6];Cx3=RxBuffer1[RxCounter1-5];Cy3=RxBuffer1[RxCounter1-4];Cx4=RxBuffer1[RxCounter1-3];Cy4=RxBuffer1[RxCounter1-2];OLED_ShowSignedNum(1,1,Cx1,4);OLED_ShowSignedNum(2,1,Cy1,4);OLED_ShowSignedNum(3,1,Cx2,4);OLED_ShowSignedNum(4,1,Cy2,4);OLED_ShowSignedNum(1,7,Cx3,4);OLED_ShowSignedNum(2,7,Cy3,4);OLED_ShowSignedNum(3,7,Cx4,4);OLED_ShowSignedNum(4,7,Cy4,4);}}}else if(RxState==3) //检测是否接受到结束标志{if(RxBuffer1[RxCounter1-1] == 0x5B){USART_ITConfig(USART3,USART_IT_RXNE,DISABLE);//关闭DTSABLE中断if(RxFlag1){ AngFlag=0;HuanRaoZuoBiao();
//
// OLED_ShowSignedNum(1,1,Cx1,4);// OLED_ShowSignedNum(2,1,Cx2,4);
// OLED_ShowSignedNum(3,1,avel_X1,4);
// OLED_ShowSignedNum(4,1,Cx5[0],4);AngFlag=1;RxFlag1 = 0;RxCounter1 = 0;RxState = 0; }USART_ITConfig(USART3,USART_IT_RXNE,ENABLE); }else //接收错误{RxState = 0;RxCounter1=0;for(i=0;i<10;i++){RxBuffer1[i]=0x00; //将存放数据数组清零}}} else //接收异常{RxState = 0;RxCounter1=0;for(i=0;i<10;i++){RxBuffer1[i]=0x00; //将存放数据数组清零}}}}
注意事项
波特率匹配:确保OpenMV和STM32的波特率设置一致,否则会导致数据传输错误。
数据帧格式:定义清晰的数据帧格式,避免数据冲突和解析错误。数据帧通常包括帧头、数据部分和帧尾。
电源稳定性:确保电源供应稳定,避免因电压波动导致的通信中断。
逐步测试:逐步测试每个功能模块,确保OpenMV和STM32之间的通信正常,数据解析正确。
相关文章:
STM32与openmv的串口通信
OpenMV与STM32的通信是嵌入式系统和物联网领域中的一项重要技术。OpenMV是一种开源的微型机器视觉模块,基于ARM Cortex-M7微控制器,支持多种图像处理功能,如颜色识别、形状检测等。而STM32是STMicroelectronics公司推出的基于ARM Cortex内核的…...
C#基于SkiaSharp实现印章管理(11)
PdfSharpCore支持类似GDI方式在PDF页面绘制文字、矩形、圆形、多边形、路径、图片等内容,本文学习基于PdfSharpCore将结构化印章数据导出为PDF文件的基本用法,评估其使用可行性。 PdfSharpCore创建PDF文件很方便,调用PdfDocument类创建实…...
Spring使用@Async出现循环依赖原因以及解决方案
场景复现 1、首先项目需要打开spring的异步开关,在application主类上加EnableAsync 2、创建一个包含了Async方法的异步类MessageService: Service public class MessageService {Resource private TaskService taskService; Async public void…...
如何训练 RAG 模型
训练 RAG(Retrieval-Augmented Generation)模型涉及多个步骤,包括准备数据、构建知识库、配置检索器和生成模型,以及进行训练。以下是一个详细的步骤指南,帮助你训练 RAG 模型。 1. 安装必要的库 确保你已经安装了必…...
鸿蒙网络编程系列34-Wifi热点扫描及连接示例
1. Wifi热点简介 Wifi热点是移动设备接入网络的重要形式,特别是在不具备固定网络接入点的情况下,可以通过Wifi热点灵活方便的接入网络,因此在日常生活中具有广泛的应用。鸿蒙系统也提供了方便的Wifi管理API,支持热点扫描…...
LVS三种模式工作原理
常用负载均衡设备 实现负载均衡的技术的方式有哪些:硬件层面有F5负载均衡器,网络层层面有LVS(Linux Virtual Server),应用层层面就是nginx、Haproxy等。 lvs工作在网络层,nginx工作在应用层。 LVS有三种工作模式 lvs是由章文崇…...
【二轮征稿启动】第三届环境工程与可持续能源国际会议持续收录优质稿件
第三届环境工程与与可持续能源国际会议(EESE 2024)由中南林业科技大学主办,湖南农业大学协办,将于2024年12月20日-22日在湖南长沙召开。 大会邀请到国家杰出青年科学基金获得者、华中科技大学能源与动力工程学院冯光教授…...
网络安全——防火墙技术
目录 前言基本概念常见防火墙技术防火墙的主要功能防火墙的不足之处相关题目1.组织外部未授权用户访问内部网络2.DMZ区3.包过滤防火墙和代理服务防火墙 前言 这是在软件设计师备考时编写的资料文章,相关内容偏向软件设计师 基本概念 防火墙技术是网络安全领域中的…...
Missing classes detected while running R8报错解决方案
Android 打包release版本时报错如下: > Task :printlib:minifyReleaseWithR8 FAILED AGPBI: {"kind":"error","text":"Missing classes detected while running R8. Please add the missing classes or apply additional ke…...
智能指针
目录 1. 为什么需要智能指针? 2. 内存泄漏 2.1 什么是内存泄漏,内存泄漏的危害 2.2 内存泄漏分类(了解) 堆内存泄漏(Heap leak) 系统资源泄漏 2.3 如何检测内存泄漏(了解) 2.4如何避免内存泄漏 3.…...
通过DevTools逃离Chrome沙盒(CVE-2024-6778和CVE-2024-5836)
介绍 这篇博文详细介绍了如何发现CVE-2024-6778和CVE-2024-5836的,这是Chromium web浏览器中的漏洞,允许从浏览器扩展(带有一点点用户交互)中进行沙盒逃逸。 简而言之,这些漏洞允许恶意的Chrome扩展在你的电脑上运行…...
手持无人机飞手执照,会组装调试入伍当兵有多香!
手持无人机飞手执照,并具备组装调试技能,在入伍当兵时确实会具有显著的优势和吸引力。以下是对这一情况的详细分析: 一、无人机飞手执照的优势 1. 法规遵从与安全保障: 根据《民用无人驾驶航空器系统驾驶员管理暂行规定》等相关…...
项目经理好累好烦啊,不想干了....
打住! 先问问自己,在所有的项目管理过程中,有没有体验到任和何乐趣。如果没有,请不要再继续内耗。 如果有,慎重考虑,然后适当解压,每个岗位都会不同的烦心事,每个企业都不完美&…...
论技术人员“技术人格”的重要意义
此论题从表面上看,是社会科学的,或者心理学的。然其对于信息技术这种科学的工作,又显得非常的重要。作为信息技术的从业者,或者说科学的从业者,具备良好的“技术人格”,对确保工作的质量,与正确…...
Kafka异常重试方案小记
背景 在最近进行的项目架构升级中,我们对原有的核心项目结构进行了细致的拆分。 现在,核心项目与非核心项目之间的通信和数据交换主要通过Kafka这一中间件来实现。 这种设计主要体现在核心项目向非核心项目发送通知,这些通知大致可以分为三个…...
非页面缓冲池占用过高处理方法
1.现象 电脑变莫名其妙得特别卡,明明16G的内存,理论上日常使用,打游戏之类的使用起来完全不会有什么大问题,但是实际使用却是卡的要死。 下面开始查找原因。 2.查找原因 使用win自带的任务管理器,可以看到日常内存…...
【Linux】进程信号(下)
目录 一、信号的阻塞 1.1 信号在内核中的保存方式 1.2 sigset_t信号集 (1)信号集操作 (2)sigprocmask函数 (3)sigpending函数 二、信号的处理 2.1 用户态和内核态 2.2 重谈进程地址空间 三、信号…...
FlinkCDC 实现 MySQL 数据变更实时同步
文章目录 1、基本介绍2、代码实战2.1、数据源准备2.2、代码实战2.3、数据格式 1、基本介绍 Flink CDC 是 Apache Flink 提供的一个功能强大的组件,用于实时捕获和处理数据库中的数据变更。可以实时地从各种数据库(如MySQL、PostgreSQL、Oracle、MongoDB…...
JavaWeb——Maven(4/8):Maven坐标,idea集成-导入maven项目(两种方式)
目录 Maven坐标 导入Maven项目 第一种方式 第二种方式 Maven坐标 Maven 坐标 是 Maven 当中资源的唯一标识。通过这个坐标,我们就能够唯一定位资源的位置。 Maven 坐标主要用在两个地方。第一个地方:我们可以使用坐标来定义项目。第二个地方&#…...
实现uniapp天地图边界范围覆盖
在uniapp中,难免会遇到使用地图展示的功能,但是百度谷歌这些收费的显然对于大部分开源节流的开发者是不愿意接受的,所以天地图则是最佳选择。 此篇文章,详细的实现地图展示功能,并且可以自定义容器宽高,还可…...
家庭实验室应用:OpenClaw+Qwen3.5-9B管理智能家居
家庭实验室应用:OpenClawQwen3.5-9B管理智能家居 1. 为什么需要AI中控? 去年装修新房时,我给自己定了个小目标:打造一个完全通过自然语言控制的智能家居系统。市面上的语音助手总让我觉得差点意思——要么响应速度慢,…...
颠覆式音频编辑:Audacity AI插件的OpenVINO技术应用指南
颠覆式音频编辑:Audacity AI插件的OpenVINO技术应用指南 【免费下载链接】audacity Audio Editor 项目地址: https://gitcode.com/GitHub_Trending/au/audacity 一、价值定位:重新定义音频处理效率边界 在数字内容创作领域,音频后期…...
DRV2667压电触觉驱动器原理与Arduino嵌入式实践
1. DRV2667 压电触觉驱动器深度技术解析与嵌入式集成实践 1.1 芯片级功能定位与工程价值 DRV2667 是德州仪器(TI)推出的高集成度压电触觉驱动芯片,专为需要高电压、低功耗、精准波形控制的触觉反馈系统设计。其核心价值不在于简单地“驱动压…...
ProDino MKR Zero工业RS-485与LoRaWAN开发指南
1. ProDino MKR Zero 硬件平台与配套库深度解析ProDino MKR Zero 是 KMP(KMP Electronics)面向工业物联网边缘节点推出的紧凑型 ARM Cortex-M0 开发平台,基于 Microchip SAMD21G18A 微控制器(48MHz 主频、256KB Flash、32KB SRAM&…...
【仿真】【具身智能】云端低成本畅玩Isaac Lab:抢占式实例部署实战
1. 为什么选择云端抢占式实例部署Isaac Lab 第一次接触Isaac Lab时,我和大多数开发者一样被本地部署的高门槛吓退了。一张RTX 3090显卡就要上万元,更别提配套的CPU和内存配置要求。后来尝试过VNC远程连接方案,结果画面卡顿得像在看PPT&#x…...
FPGA DSP48E2实战避坑:为什么你的32x32定点乘法性能上不去?从原理到优化全解析
FPGA DSP48E2实战避坑:为什么你的32x32定点乘法性能上不去?从原理到优化全解析 在FPGA信号处理系统设计中,32x32定点乘法器是构建数字滤波器、FFT核心和矩阵运算的基础模块。许多工程师在使用Xilinx UltraScale系列FPGA的DSP48E2 Slice时&…...
PyTorch 2.8镜像惊艳效果:Wan2.2-T2V在RTX 4090D上生成1080p视频实录
PyTorch 2.8镜像惊艳效果:Wan2.2-T2V在RTX 4090D上生成1080p视频实录 1. 开篇:专业级视频生成环境 当我们需要处理视频生成这类计算密集型任务时,一个稳定高效的运行环境至关重要。今天要介绍的PyTorch 2.8深度优化镜像,正是为R…...
PLC编程必备:西门子200SMART符号表与注释的高效使用技巧
PLC编程效率革命:西门子200SMART符号表与注释的进阶实践 在工业自动化领域,PLC编程的可读性和可维护性往往决定了项目的长期成败。许多工程师花费大量时间编写功能代码,却忽视了符号表和注释这一"软实力"的建设。当项目需要升级或故…...
STM32停机模式深度优化:唤醒后外设恢复的5个关键操作(附RTC配置代码)
STM32停机模式深度优化:唤醒后外设恢复的5个关键操作(附RTC配置代码) 当你的嵌入式设备需要以微安级电流运行时,停机模式(Stop Mode)往往是平衡功耗与唤醒速度的最佳选择。但唤醒后的世界并非总是美好的——…...
小程序毕业设计-基于微信小程序的时间管理系统的设计与实现-时间管理小程序-番茄时钟小程序
小程序毕业设计-基于微信小程序的时间管理系统的设计与实现 https://www.bilibili.com/video/BV1ts3FzxEci/?spm_id_from333.1387.search.video_card.click&vd_source832d614817260f8f26d9431e5d8f726b 基于微信小程序的时间管理系统的设计与实现 技术说明: 用户前端:微信…...
