基于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

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

Hadoop集群数据均衡之磁盘间数据均衡

生产环境,由于硬盘空间不足,往往需要增加一块硬盘。刚加载的硬盘没有数据时,可以执行磁盘数据均衡命令。(Hadoop3.x新特性) plan后面带的节点的名字必须是已经存在的,并且是需要均衡的节点。 如果节点不存在,会报如下错误: 如果节点只有一个硬盘的话,不会创建均衡计划: (1)生成均衡计划 hdfs diskbalancer -plan hadoop102 (2)执行均衡计划 hd

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi