基于STM32实现sBus协议数据获取、解析并转为CAN协议数据

2023-11-21 22:30

本文主要是介绍基于STM32实现sBus协议数据获取、解析并转为CAN协议数据,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文目录:

1、功能实现情况

2、实现路线

3、关于sBus共地问题的注意事项

4、结语

1、功能实现情况

        目前该装置可以实现将航模接收机输出的sBus协议数据进行获取并根据sBus协议进行解析,最终经CAN总线将解析之后的数据传输出去。目前为功能实现阶段,暂时将解析之后的11位数据(在stm32中,数据的存储类型为uint16_t)舍弃掉部分位之后转为8位数据(在stm32中数据的存储类型为uint8_t)经CAN总线传输出去。

2、实现路线

       图1为数据的传输方向示意图,也为装置的实现路线图。其中遥控器和接收机使用的型号为云卓T10,有10个通道,接收机5V供电,接收机输出信号选择sBus协议信号。

e001c32bb4784631b05a8e166840791d.jpeg

图1:实现路线

        其中从遥控器发送数据到接收机以及硬件取反电路组成实现路线第一段;在实现路线第一段基础上加上STM32组成实现路线第二段,最后在实现路线第二段的基础上加上CAN总线收发器模块组成实现路线第三段,至此,输出的数据为CAN协议数据。

        至于为什么在接收机和STM32之间加上硬件取反电路是由sBus协议内容要求的,关于sBus协议内容参考资料:不清楚SBUS,这份SBUS协议详解请收藏_振华OPPO的博客-CSDN博客

需特别注意sBus在STM32中串口参数的配置。

2.1、实现路线第一段 

      该段需要注意的事项为接收机的5V供电,其中5V供电的正极需和实现路线第二段中的STM32的ST-Link上5V针脚连接,5V供电的负极需和STM32的GND引脚连接(至于为什么这样连接详见本文文末“关于装置电源共地问题的注意事项”),STM32系统选择STM32F103C8T6最小系统板。此外,还需注意的事项为硬件取反电路的3.3V供电,如果3.3V供电的正极和STM32的3.3V引脚连接可能会出现硬件取反电路不工作的情况,问题可能为STM32板子上的3.3V引脚的驱动能力不强,此时可能需要外接3.3V的电源,此处对于硬件取反电路没有和STM32共地的要求。

        检验实现路线第一段是否成功实现需要一个USB转串口模块,如图2、图3所示,具体操作为:将接收机上的正负极暂时分别与ST-Link的5V针脚和STM32的GND脚断开,并将其分别于USB转串口模块上的5V与GND连接,然后将搭载了 经取反电路转换后的sBus数据 的信号线与USB转串口接线端上的Rx引脚连接,打开串口调试助手并设置好串口调试助手相关通信参数,其通信参数的具体值参考sBus协议中对波特率、奇偶校验位、停止位等的要求。

c3c7d35330564878b3c857b23c9902ba.jpeg

图2:USB转串口模块正面

cefa9fa04da74275872711dcdb2a9187.jpeg

图3:USB转串口模块反面

当实现路线第一步成功时,串口调试助手显示接收到的数据如图4所示,其中除了第一位为0x0f和最后一位为标志位外,其余位的数据由使用相应的遥控器设备助手自定义,即除了第一位和最后一位外,其余位的数值可不必与图4中显示的相同。

c2997ce94ddf4e319bd502ab147c5a16.jpeg

图4:串口调试助手页面

当串口调试助手在配置好相关通信参数的前提下显示的数据没有规律即乱码时,考虑两个可能存在的问题:(1)硬件取反电路搭错了(2)硬件取反电路的供电问题。

2.2、实现路线第二段

        实现路线第二段相比于第一段需要多一个STM32单片机,具体为STM32F103C8T6最小系统板,如图5所示,并且一起配合使用的是一个OLED屏,OLED屏的驱动函数参考B站“江协电子——江科大STM32教程”中的OLED库函数(此处为我母校学长疯狂打call)

91d24d44ece3415a89c085bf16c1af6b.jpeg

图5:STM32最小系统板

这一段的接线为:由于在实现路线第一段中将接收机上的5V电源的正负极分别与USB转串口模块的5V和GND连接了,所以首先将接收机的5V电源线的正负极与USB转串口模块的5V和GND断开,然后将接收机上5V电源正极与ST-Link上的5V引脚连接,接收机上5V电源负极与STM32最小系统板上的GND引脚连接(必须要这样连接,因为sBus协议本质上是UART协议,USART/UART接线要求中要求数据的发送端要与接收端“共地”),然后将搭载了 经取反电路转换后的sBus数据 的信号线 与STM32最小系统板上用于USART通信的Rx引脚即负责串口数据接收的引脚连接(图5中为与PA10连接)。STM32的程序为:

main函数(包含了实现路线第三步中的CAN通信部分)

#include "stm32f10x.h"
#include "usart_RS.h"
#include "OLED.h"
#include "CAN_test.h"
#include "Delay.h"int main(void)
{	usart_RS_Init();CAN_Config();CanTxMsg CAN_TxMessage;//SendString(USART1,"This is a USART receive and send test!");OLED_Init();	uint16_t* CH_main;uint8_t* buf_main;while(1){		if(Get_flag_CH_deal_finish() == 1){CH_main = Get_CH();buf_main = Get_buf();//OLED_Clear();CAN_TxMessage.ExtId = 0x1314;CAN_TxMessage.DLC = 8;CAN_TxMessage.IDE = CAN_ID_EXT;CAN_TxMessage.RTR = CAN_RTR_DATA;CAN_TxMessage.Data[0] = CH_main[0];CAN_TxMessage.Data[1] = CH_main[1];CAN_TxMessage.Data[2] = CH_main[2];CAN_TxMessage.Data[3] = CH_main[3];CAN_TxMessage.Data[4] = CH_main[4];CAN_TxMessage.Data[5] = CH_main[5];CAN_TxMessage.Data[6] = CH_main[6];CAN_TxMessage.Data[7] = CH_main[7];//			OLED_ShowNum(1,1,CH_main[0],4);
//			OLED_ShowNum(1,6,CH_main[1],4);
//			OLED_ShowNum(1,11,CH_main[2],4);
//			OLED_ShowNum(2,1,CH_main[3],4);
//			OLED_ShowNum(2,6,CH_main[4],4);
//			OLED_ShowNum(2,11,CH_main[5],4);
//			OLED_ShowNum(3,1,CH_main[6],4);
//			OLED_ShowNum(3,6,CH_main[7],4);
//			OLED_ShowNum(3,11,CH_main[8],4);
//			OLED_ShowNum(4,1,CH_main[9],4);
//			OLED_ShowNum(4,6,CH_main[10],4);//		    OLED_ShowHexNum(1,1,buf_main[0],2);
//			OLED_ShowHexNum(1,4,buf_main[1],2);
//            OLED_ShowHexNum(1,7,buf_main[2],2);
//			OLED_ShowHexNum(1,10,buf_main[3],2);
//			OLED_ShowHexNum(1,13,buf_main[4],2);
//			OLED_ShowHexNum(2,1,buf_main[5],2);
//			OLED_ShowHexNum(2,4,buf_main[6],2);
//			OLED_ShowHexNum(2,7,buf_main[7],2);
//			OLED_ShowHexNum(2,10,buf_main[8],2);
//			OLED_ShowHexNum(2,13,buf_main[9],2);
//			OLED_ShowHexNum(3,1,buf_main[10],2);
//			OLED_ShowHexNum(3,4,buf_main[11],2);
//            OLED_ShowHexNum(3,7,buf_main[12],2);
//			OLED_ShowHexNum(3,10,buf_main[13],2);
//			OLED_ShowHexNum(3,13,buf_main[14],2);
//			OLED_ShowHexNum(4,1,buf_main[15],2);
//			OLED_ShowHexNum(4,4,buf_main[16],2);
//			OLED_ShowHexNum(4,7,buf_main[17],2);
//			OLED_ShowHexNum(4,10,buf_main[18],2);
//			OLED_ShowHexNum(4,13,buf_main[19],2);CAN_Transmit(CAN1,&CAN_TxMessage);Delay_ms(10);USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);}}	
}

usart_RS.h文件代码为:

#ifndef __USART_RS_H
#define __USART_RS_Hvoid usart_RS_Init(void);
void SendString(USART_TypeDef* USARTx,char* str);uint8_t Get_flag_CH_deal_finish(void);uint16_t* Get_CH(void);uint8_t* Get_buf(void);#endif

usart_RS.c文件代码为:

#include "stm32f10x.h"                  // Device headervoid usart_RS_Init(void)
{//1、打开外设(GPIOA、USART1)时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//2、重置外设参数USART_DeInit(USART1);//3、配置GPIO口//配置PA9为复用推挽输出模式GPIO_InitTypeDef GPIO_InitStructure={0};GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//配置PA10为浮空输入模式GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//4、配置USARTUSART_InitTypeDef USART_InitStructure={0};USART_InitStructure.USART_BaudRate = 100000;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_InitStructure.USART_Parity = USART_Parity_Even;USART_InitStructure.USART_StopBits = USART_StopBits_2;USART_InitStructure.USART_WordLength = USART_WordLength_9b;USART_Init(USART1,&USART_InitStructure);//5、配置NVICNVIC_InitTypeDef NVIC_InitStructure={0};NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);//6、配置中断USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//7、使能串口USART_Cmd(USART1,ENABLE);
}void SendByte(USART_TypeDef* USARTx,uint8_t data)
{USART_SendData(USARTx,data);while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
}
void SendString(USART_TypeDef* USARTx,char* str)
{unsigned int k=0;while(*(str+k)!='\0'){SendByte(USARTx,*(str+k));k++;}while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
}static uint8_t flag_receive_sBus = 0;
void copyANDdeal_data_sBus(uint8_t ucTemp);
void USART1_IRQHandler(void)
{uint8_t ucTemp;if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET){ucTemp = USART_ReceiveData(USART1);if (flag_receive_sBus == 1){copyANDdeal_data_sBus(ucTemp);}else if(ucTemp == 0x0f){flag_receive_sBus = 1;}}
}static uint8_t buf[24];
static uint8_t count = 0;
static uint16_t CH[10];
static uint8_t flag_CH_deal_finish=0;
void copyANDdeal_data_sBus(uint8_t ucTemp)
{ buf[count] = ucTemp;count++;if(count == 24){CH[ 0] = ((int16_t)buf[ 0] >> 0 | ((int16_t)buf[ 1] << 8 )) & 0x07FF;CH[ 1] = ((int16_t)buf[ 1] >> 3 | ((int16_t)buf[ 2] << 5 )) & 0x07FF;CH[ 2] = ((int16_t)buf[ 2] >> 6 | ((int16_t)buf[ 3] << 2 )  | (int16_t)buf[ 4] << 10 ) & 0x07FF;CH[ 3] = ((int16_t)buf[ 4] >> 1 | ((int16_t)buf[ 5] << 7 )) & 0x07FF;CH[ 4] = ((int16_t)buf[ 5] >> 4 | ((int16_t)buf[ 6] << 4 )) & 0x07FF;CH[ 5] = ((int16_t)buf[ 6] >> 7 | ((int16_t)buf[ 7] << 1 )  | (int16_t)buf[8] <<  9 ) & 0x07FF;CH[ 6] = ((int16_t)buf[ 8] >> 2 | ((int16_t)buf[ 9] << 6 )) & 0x07FF;CH[ 7] = ((int16_t)buf[ 9] >> 5 | ((int16_t)buf[10] << 3 )) & 0x07FF; CH[ 8] = ((int16_t)buf[11] << 0 | ((int16_t)buf[12] << 8 )) & 0x07FF;CH[ 9] = ((int16_t)buf[12] >> 3 | ((int16_t)buf[13] << 5 )) & 0x07FF;flag_CH_deal_finish = 1;count = 0;flag_receive_sBus = 0;USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);}		
}uint8_t Get_flag_CH_deal_finish(void)
{return flag_CH_deal_finish;
}uint16_t* Get_CH(void)
{flag_CH_deal_finish = 0;return CH;
}uint8_t* Get_buf(void)
{flag_CH_deal_finish = 0;return buf;
}

关于代码需要注意的事项为:(1)USART通信参数的配置如图6所示,(2)在中断服务子函数中的(void copyANDdeal_data_sBus(uint8_t ucTemp))函数中有一个关闭串口接收中断的函数和在主函数末尾有一个打开串口接收中断的函数。由于接收机是一直向外发送sBus数据,如果没有这两个函数,STM32的主函数会一直被串口接收中断 中断执行。

6f09e6e177c64876aa84d61d959a3aa8.png

图6:USART通信参数的配置 

        检验实现路线第二段是否成功的操作为:可在主函数中写一个“OLED_Clear()”观察OLED屏的刷新频率是否固定,刷新频率不固定即为一会儿刷新快一点,一会儿刷新慢一点。至于为什么可以这样检测的原因为:由于sBus数据段长度固定为25个字节,按照程序逻辑,每接收到24个字节(在上述程序中包头0x0f没有存储,所以是24个字节)并完成解析后会执行一次刷新OLED屏的操作,当接收到的数据不正确时,出现包头即数据0x0f的时间不固定(因为数据不正确的话数据为乱码),那么刷新OLED屏的时间也不固定,时而快时而慢。

        关于实现路线第二段中OLED屏的现象有三种:(1)OLED屏不显示;(2)OLED屏显示数据,在加上OLED屏刷新函数后刷新频率不固定,显示的数据没有规律即乱码;(3)OLED屏显示数据,在加上OLED屏刷新函数后刷新频率固定,显示的数据每一组都在变化但有规律。当出现第一种情况时为串口中断服务子程序中(void copyANDdeal_data_sBus(uint8_t ucTemp))函数的串口接收数据中断未关闭导致的,由于主函数的运行一直被中断服务子函数打断,导致即使接收到数据也没办法显示在OLED屏上,需要注意的是在中断服务子函数中关闭中断后需要在合适的地方打开(上述程序中为在主函数的末尾打开);当出现第二种情况时为STM32接收到的数据有误所致,在实现路线第一段成功的情况下(即由取反电路输出的数据正确的情况下),检查接收机的5V电源GND是否与最小系统板上的GND连接,接收机5V电源的正极是否与ST-Link的5V引脚连接,当不满足USART通信数据发送端与接收端“共地”的要求时,数据接收端接收到的数据可能会存在问题;当出现上述第三种情况时为正常情况,至于显示的数据呈现有规律的变化猜测是OLED的驱动函数问题,可不用管。

2.3、实现路线第三段

        实现路线第三段为将由实现路线第二段中处理后的通道数据CH[ ii ]( ii = 0、1、2...9)赋值给CAN的数据段并通过CAN总线发送出去,具体程序为(下述程序包含CAN接收数据的功能):

CAN_test.h文件代码为:

#ifndef __CAN_test_H
#define __CAN_test_Hvoid CAN_Config(void);uint8_t CAN_Get_Flag_Receive(void);CanRxMsg CAN_Get_RxMessage(void);#endif

CAN_test.c文件的代码为:

#include "stm32f10x.h"                  // Device headervoid CAN_Config(void)
{//1、配置(PA11)、(PA12)和CAN1对应的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);//2、配置GPIO口GPIO_InitTypeDef GPIO_InitStructure={0};//配置PA11(CAN_Rx)为上拉输入模式GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//配置PA12(CAN_Tx)为复用推挽输出模式GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//3、配置CAN模式CAN_InitTypeDef CAN_InitStructure={0};      CAN_InitStructure.CAN_ABOM = ENABLE;             //自动离线功能CAN_InitStructure.CAN_AWUM = ENABLE;             //自动唤醒功能CAN_InitStructure.CAN_BS1 = CAN_BS1_5tq;         //配置BS1段长度CAN_InitStructure.CAN_BS2 = CAN_BS2_3tq;         //配置BS2段长度CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;  //配置CAN工作模式CAN_InitStructure.CAN_NART = DISABLE;            //配置自动重传功能CAN_InitStructure.CAN_Prescaler = 4;             //配置CAN外设的时钟分频CAN_InitStructure.CAN_RFLM = DISABLE;            //锁存FIFOCAN_InitStructure.CAN_SJW = CAN_SJW_1tq;         //SJW极限值CAN_InitStructure.CAN_TTCM = DISABLE;            //是否使能时间触发功能CAN_InitStructure.CAN_TXFP = DISABLE;            //配置报文优先级的判别方法CAN_Init(CAN1,&CAN_InitStructure);    //4、配置CAN筛选器参数CAN_FilterInitTypeDef CAN_FilterInitStructure={0};CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;                //是否使能本筛选器 CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FilterFIFO0;   //设置经筛选器筛选后的数据存到哪个FIFO中//筛选器中要筛选ID的高16位CAN_FilterInitStructure.CAN_FilterIdHigh = ((((u32)0x2023<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF0000)>>16; //筛选器中要筛选ID的低16位CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)0x2023<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;               CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF;               //筛选器中筛选屏蔽位的高16位(设置1的位表示接收报ID的该位必须与筛选器中设置的ID的对应位一致)CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFF;                //筛选器中筛选屏蔽位的低16位(同上)CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;      //筛选器的工作模式(列表还是屏蔽模式)CAN_FilterInitStructure.CAN_FilterNumber = 0;                        //筛选器组的编号CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;     //设置筛选器的长度CAN_FilterInit(&CAN_FilterInitStructure);//5、配置NVICNVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);NVIC_InitTypeDef NVIC_InitStructure={0};NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_Init(&NVIC_InitStructure);//6、使能CAN1的接收中断CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
}static uint8_t flag_receive=0;
CanRxMsg RxMessage;void USB_LP_CAN1_RX0_IRQHandler(void)
{CAN_Receive(CAN1,CAN_FIFO0,&RxMessage);   //其中CAN_FIFO0与CAN筛选器是设置的关联FIFO相对应flag_receive = 1;if((RxMessage.ExtId == 0x2023) && (RxMessage.IDE == CAN_ID_EXT) && (RxMessage.DLC == 8)){flag_receive = 2;}else{flag_receive = 3;}
}uint8_t CAN_Get_Flag_Receive(void)
{return flag_receive;
}
CanRxMsg CAN_Get_RxMessage(void)
{return RxMessage;
}

3、关于共地问题的注意事项

3.1、当使用外部的5V直流电源给接收机供电时

        外部5V电源的GND与STM32最小系统板的GND电平不一致,实际情况如图7、图8所示:

a18b95e749894d58a7db3ccb775aeb1a.jpeg

图7:万用表笔头与外部电源的负极和STM32最小系统板GND连接情况

c7ec8842bafe460688ff5e5fd378d478.jpeg

图8:外部电源负极与STM32最小系统板GND间的电压结果

此时不能满足USART/UART协议中关于数据发送端与接收端“共地”的要求,当由该外部电源给接收机供电时,其sBus信号输出端经取反电路后数据波形如图9、图10所示:

51d781ac8421407291b3976d358a659b.jpeg

图9:当不满足“共地”要求时经取反电路取反后的信号

899739f55b90461c998a4d2ac5de485c.jpeg

图10:对图9进行局部放大后的信号波形

而正常的波形如图11、图12所示:

6eaba09f4e2c4a3bb2682efa47ca0720.jpeg

图11: 满足“共地”要求时信号波形

3cc520fa5ed44781ae86af77532f9777.jpeg

图12:图11进行局部放大后的波形

3.2、外部电源负极与STM32最小系统板间的电位差

        关于外部电源负极与STM32最小系统板GND间的电位差如图13所示:

138085435f2341449c80e50fc22314c8.jpeg

图13:外部电源负极与STM32最小系统板GND端的电位差 

4、结语

        nnd,写了五个小时终于写完了!!!

        我去干饭了,下次有好玩的再写!

 

这篇关于基于STM32实现sBus协议数据获取、解析并转为CAN协议数据的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/405529

相关文章

Python pyinstaller实现图形化打包工具

《Pythonpyinstaller实现图形化打包工具》:本文主要介绍一个使用PythonPYQT5制作的关于pyinstaller打包工具,代替传统的cmd黑窗口模式打包页面,实现更快捷方便的... 目录1.简介2.运行效果3.相关源码1.简介一个使用python PYQT5制作的关于pyinstall

使用Python实现大文件切片上传及断点续传的方法

《使用Python实现大文件切片上传及断点续传的方法》本文介绍了使用Python实现大文件切片上传及断点续传的方法,包括功能模块划分(获取上传文件接口状态、临时文件夹状态信息、切片上传、切片合并)、整... 目录概要整体架构流程技术细节获取上传文件状态接口获取临时文件夹状态信息接口切片上传功能文件合并功能小

python实现自动登录12306自动抢票功能

《python实现自动登录12306自动抢票功能》随着互联网技术的发展,越来越多的人选择通过网络平台购票,特别是在中国,12306作为官方火车票预订平台,承担了巨大的访问量,对于热门线路或者节假日出行... 目录一、遇到的问题?二、改进三、进阶–展望总结一、遇到的问题?1.url-正确的表头:就是首先ur

C#实现文件读写到SQLite数据库

《C#实现文件读写到SQLite数据库》这篇文章主要为大家详细介绍了使用C#将文件读写到SQLite数据库的几种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下... 目录1. 使用 BLOB 存储文件2. 存储文件路径3. 分块存储文件《文件读写到SQLite数据库China编程的方法》博客中,介绍了文

Oracle Expdp按条件导出指定表数据的方法实例

《OracleExpdp按条件导出指定表数据的方法实例》:本文主要介绍Oracle的expdp数据泵方式导出特定机构和时间范围的数据,并通过parfile文件进行条件限制和配置,文中通过代码介绍... 目录1.场景描述 2.方案分析3.实验验证 3.1 parfile文件3.2 expdp命令导出4.总结

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

JAVA利用顺序表实现“杨辉三角”的思路及代码示例

《JAVA利用顺序表实现“杨辉三角”的思路及代码示例》杨辉三角形是中国古代数学的杰出研究成果之一,是我国北宋数学家贾宪于1050年首先发现并使用的,:本文主要介绍JAVA利用顺序表实现杨辉三角的思... 目录一:“杨辉三角”题目链接二:题解代码:三:题解思路:总结一:“杨辉三角”题目链接题目链接:点击这里

基于Python实现PDF动画翻页效果的阅读器

《基于Python实现PDF动画翻页效果的阅读器》在这篇博客中,我们将深入分析一个基于wxPython实现的PDF阅读器程序,该程序支持加载PDF文件并显示页面内容,同时支持页面切换动画效果,文中有详... 目录全部代码代码结构初始化 UI 界面加载 PDF 文件显示 PDF 页面页面切换动画运行效果总结主

更改docker默认数据目录的方法步骤

《更改docker默认数据目录的方法步骤》本文主要介绍了更改docker默认数据目录的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1.查看docker是否存在并停止该服务2.挂载镜像并安装rsync便于备份3.取消挂载备份和迁

SpringBoot实现基于URL和IP的访问频率限制

《SpringBoot实现基于URL和IP的访问频率限制》在现代Web应用中,接口被恶意刷新或暴力请求是一种常见的攻击手段,为了保护系统资源,需要对接口的访问频率进行限制,下面我们就来看看如何使用... 目录1. 引言2. 项目依赖3. 配置 Redis4. 创建拦截器5. 注册拦截器6. 创建控制器8.