STM32CUBEMX_DMA串口空闲中断接收+接收发送缓冲区
STM32CUBEMX_DMA串口空闲中断接收+接收发送缓冲区
前言:
我了解的串口接收指令的方式有:在这里插入图片描述
1、接收数据中断+特定帧尾
2、接收数据中断+空闲中断
3、DMA接收+空闲中断
我最推荐第三种,尤其是数据量比较大且频繁的时候
串口配置



my_it.c
#include "my_it.h"
#include "mymain.h"
#include "main.h"
#include "gpio.h"
#include "tim.h"
#include "usart.h"
#include "uart_lcd.h"void MY_UART_IDLECallback(UART_HandleTypeDef *huart)//自定义的串口超时中断回调函数
{HAL_UART_DMAStop(&huart3); //暂停DMAunsigned char data_length = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart3_rx); //计算此帧数据长度if(data_length == RBUFF_UNIT){unsigned char recv_data[10] = {0};memcpy(recv_data,receive_buff,RBUFF_UNIT);RxDataBufCheck(recv_data,RBUFF_UNIT);}//HAL_UART_Transmit_DMA(&huart3,receive_buff,data_length); //回环测试,接收到什么返回什么HAL_UART_Receive_DMA(&huart3, (unsigned char*)receive_buff, BUFFER_SIZE); //继续开启接收data_length = 0;
}void MY_UART_IRQHandler(UART_HandleTypeDef *huart)//此函数调用放在void USART3_IRQHandler(void)内执行
{if(USART3 == huart->Instance){if(RESET != __HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE)) //判断是否是空闲中断{__HAL_UART_CLEAR_IDLEFLAG(&huart3); //清除空闲中断MY_UART_IDLECallback(huart); //空闲中断处理函数}}
}
my_it.h
#ifndef __MY_IT_H
#define __MY_IT_H
#include "log.h"
#include "usart.h"extern DMA_HandleTypeDef hdma_usart3_rx;void MY_UART_IRQHandler(UART_HandleTypeDef *huart);
void MY_UART_IDLECallback(UART_HandleTypeDef *huart);#endif
uart_lcd.c
#include "uart_lcd.h"
#include "sensor.h"
#include "dev_control.h"
#include <stdint.h>unsigned char UART_RxDataBuf[R_NUM][RBUFF_UNIT]; //接收缓冲区
unsigned char *UART_RxDataInPtr;
unsigned char *UART_RxDataOutPtr;
unsigned char *UART_RxDataEndPtr;unsigned char UART_TxDataBuf[T_NUM][TBUFF_UNIT]; //发送缓冲区
unsigned char *UART_TxDataInPtr;
unsigned char *UART_TxDataOutPtr;
unsigned char *UART_TxDataEndPtr;unsigned char receive_buff[BUFFER_SIZE]; //串口接收临时缓存//发送数据实例
#include "uart_lcd.h"
#include "sensor.h"
#include "dev_control.h"
#include <stdint.h>unsigned char UART_RxDataBuf[R_NUM][RBUFF_UNIT]; //接收缓冲区
unsigned char *UART_RxDataInPtr;
unsigned char *UART_RxDataOutPtr;
unsigned char *UART_RxDataEndPtr;unsigned char UART_TxDataBuf[T_NUM][TBUFF_UNIT]; //发送缓冲区
unsigned char *UART_TxDataInPtr;
unsigned char *UART_TxDataOutPtr;
unsigned char *UART_TxDataEndPtr;unsigned char receive_buff[BUFFER_SIZE]; //串口接收临时缓存//发送数据实例
unsigned char lcd_send_data[] = {0xFF,0x55,0x00,0x04,0x00,0x00,0x00,0x00,0xC1,0xBB};//大小端转化
unsigned short swapEndian16(unsigned short value)
{return ((value & 0xFF00) >> 8) | ((value & 0x00FF) << 8);
}unsigned int swapEndian32(unsigned int value)
{return ((value & 0xFF000000) >> 24) |((value & 0x00FF0000) >> 8) |((value & 0x0000FF00) << 8) |((value & 0x000000FF) << 24);
}/* Table of CRC values for high order byte */
const uint8_t crctablehi[] = {0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,0x40
};
/* Table of CRC values for low order byte */
const uint8_t crctablelo[] = {0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,0x40
};unsigned short crc16Modbus(unsigned char *ptr, unsigned short len)
{unsigned char crchi = 0xff;unsigned char crclo = 0xff;unsigned short index;while(len--){index = crclo ^ *ptr++;crclo = crchi ^ crctablehi[index];crchi = crctablelo[index];}return (crchi | crclo << 8);//(crchi << 8 | crclo)高低字节互换//return (crchi << 8 | crclo);
}void uartLcdInit(void)
{UART_RxDataInPtr = UART_RxDataBuf[0];UART_RxDataOutPtr = UART_RxDataInPtr;UART_RxDataEndPtr = UART_RxDataBuf[R_NUM-1];UART_TxDataInPtr = UART_TxDataBuf[0];UART_TxDataOutPtr = UART_TxDataInPtr;UART_TxDataEndPtr = UART_TxDataBuf[T_NUM-1];__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);//使能空闲中断HAL_UART_Receive_DMA(&huart3, (unsigned char*)receive_buff, BUFFER_SIZE);//开始DMA接收串口数据
}void uartLcdTask(void)//50ms调用一次,来定时处理缓存数据
{if(UART_RxDataOutPtr != UART_RxDataInPtr)//if成立说明缓冲区有数据了{//解析处理数据unsigned char recv_data[RBUFF_UNIT] = {0};memcpy(recv_data,UART_RxDataOutPtr,RBUFF_UNIT);RxDataBufAnalyze(recv_data);UART_RxDataOutPtr += RBUFF_UNIT; //指针下移if(UART_RxDataOutPtr == UART_RxDataEndPtr) //指针移动到缓冲区的尾部{UART_RxDataOutPtr = UART_RxDataBuf[0]; //指针归为到缓冲区开头}}if(UART_TxDataOutPtr != UART_TxDataInPtr)//if成立说明了发送缓冲区有数据了{UARTLCD_debug("TxData:%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\r\n",UART_TxDataOutPtr[0],UART_TxDataOutPtr[1],UART_TxDataOutPtr[2],UART_TxDataOutPtr[3],UART_TxDataOutPtr[4],UART_TxDataOutPtr[5],UART_TxDataOutPtr[6],UART_TxDataOutPtr[7],UART_TxDataOutPtr[8],UART_TxDataOutPtr[9]);HAL_UART_Transmit_DMA(&huart3,UART_TxDataOutPtr,TBUFF_UNIT); //发送数据UART_TxDataOutPtr += TBUFF_UNIT; //指针下移if(UART_TxDataOutPtr == UART_TxDataEndPtr) //指针移动到了缓冲区的尾巴{UART_TxDataOutPtr = UART_TxDataBuf[0]; //指针归为到缓冲区开头}}
}void uartLcdMainUpdate(unsigned int num) //在需要与串口屏发送数据的地方调用
{TxDataBufSend(UARTLCD_COMMAND_INIT_CHECK,num);
}void TxDataBufAdd(unsigned char *data)
{memcpy(UART_TxDataInPtr,data,TBUFF_UNIT); //拷贝数据到发送缓冲区UART_TxDataInPtr += TBUFF_UNIT; //指针下移if(UART_TxDataInPtr == UART_TxDataOutPtr){UARTLCD_error("UART_TxDataBuf exceed !!!\r\n"); //缓存满了报错提示}if(UART_TxDataInPtr == UART_TxDataEndPtr) //指针移动到缓冲区的尾部{UART_TxDataInPtr = UART_TxDataBuf[0]; //指针归为到缓冲区开头}
}void RxDataBufAdd(unsigned char *data)
{memcpy(UART_RxDataInPtr,data,RBUFF_UNIT); //拷贝数据到接收缓冲区UART_RxDataInPtr += RBUFF_UNIT; //指针下移if(UART_RxDataInPtr == UART_RxDataOutPtr) //缓存满了报错提示{UARTLCD_error("UART_RxDataBuf exceed !!!\r\n");}if(UART_RxDataInPtr == UART_RxDataEndPtr) //指针移动到缓冲区的尾部{UART_RxDataInPtr = UART_RxDataBuf[0]; //指针归为到缓冲区开头}
// for(int i = 0;i<10;i++)
// {
// for(int j = 0;j<10;j++)
// {
// Debug_printf("%x,",UART_RxDataBuf[i][j]);
// }
// Debug_printf("\r\n");
// }
// Debug_printf("\r\n");
}void TxDataBufPack(unsigned char command,unsigned int num) //发送串口数据封包
{uartLcdDataFrame_t * send_data = (uartLcdDataFrame_t *)lcd_send_data;send_data->bodyData.commandData = command;send_data->bodyData.controlData = swapEndian32(num);unsigned char bodyData[RBUFF_UNIT-2] = {0};memcpy(bodyData,&send_data->bodyData,RBUFF_UNIT-2);unsigned short send_crc = crc16Modbus(bodyData,RBUFF_UNIT-2);send_data->crcData = send_crc;TxDataBufAdd((unsigned char *)send_data);
}void TxDataBufSend(unsigned char command,unsigned int num) //直接发送数据,不经过缓存
{uartLcdDataFrame_t * send_data = (uartLcdDataFrame_t *)lcd_send_data;send_data->bodyData.commandData = command;send_data->bodyData.controlData = swapEndian32(num);unsigned char bodyData[RBUFF_UNIT-2] = {0};memcpy(bodyData,&send_data->bodyData,RBUFF_UNIT-2);unsigned short send_crc = crc16Modbus(bodyData,RBUFF_UNIT-2);send_data->crcData = send_crc;unsigned char send_data_[TBUFF_UNIT] = {0};memcpy(send_data_,send_data,TBUFF_UNIT);UARTLCD_debug("TxDataBufSend:%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\r\n",send_data_[0],send_data_[1],send_data_[2],send_data_[3],send_data_[4],send_data_[5],send_data_[6],send_data_[7],send_data_[8],send_data_[9]);HAL_UART_Transmit_DMA(&huart3,(unsigned char *)lcd_send_data,TBUFF_UNIT);HAL_Delay(2);
}void RxDataBufCheck(unsigned char *data,unsigned char length) //校验接收到的串口数据是不是一帧数据
{if(length != RBUFF_UNIT) return;uartLcdDataFrame_t * recv_data = (uartLcdDataFrame_t *)data;if(recv_data->bodyData.headData == 0x55FF)//校验头{unsigned char bodyData[RBUFF_UNIT-2] = {0};memcpy(bodyData,&recv_data->bodyData,RBUFF_UNIT-2);unsigned short recv_crc = crc16Modbus(bodyData,RBUFF_UNIT-2);if(recv_crc == recv_data->crcData)//校验CRC{
// Debug_printf("RxDataBufCheck recv data:%x,%x,%x,%x,%x\r\n",
// recv_data->bodyData.headData,recv_data->bodyData.commandData,recv_data->bodyData.lengthData,
// recv_data->bodyData.controlData,recv_data->crcData);RxDataBufAdd(data);//加入环形缓冲区}}
}void RxDataBufAnalyze(unsigned char *data) //处理串口指令
{UARTLCD_debug("RxDataBufAnalyze:%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\r\n",data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7],data[8],data[9]);uartLcdDataFrame_t * recv_data = (uartLcdDataFrame_t *)data;switch(recv_data->bodyData.commandData){case UARTLCD_COMMAND_INIT_CHECK:break;case UARTLCD_COMMAND_FLOW_LEVEL:break;case UARTLCD_COMMAND_SMOKE_CLEAN:break;case UARTLCD_COMMAND_AIR_CONSUME:break;case UARTLCD_COMMAND_PRESSURE_NOW:devBuzzerSetNum(1);break;case UARTLCD_COMMAND_PRESSURE_TARGET:devBuzzerSetNum(1);break;case UARTLCD_COMMAND_PRESSURE_REDUCE:devBuzzerSetNum(1);break;case UARTLCD_COMMAND_PRESSURE_ADD:devBuzzerSetNum(1);break;case UARTLCD_COMMAND_FLOW_NOW:devBuzzerSetNum(1);break;case UARTLCD_COMMAND_FLOW_TARGET:devBuzzerSetNum(1);break;case UARTLCD_COMMAND_FLOW_REDUCE:devBuzzerSetNum(1);break;case UARTLCD_COMMAND_FLOW_ADD:devBuzzerSetNum(1);break;case UARTLCD_COMMAND_PRESSURE_MODE:devBuzzerSetNum(1);break;case UARTLCD_COMMAND_HEAT_STATE:devBuzzerSetNum(1);break;case UARTLCD_COMMAND_AIR_START:devBuzzerSetNum(1);break;case UARTLCD_COMMAND_AIR_INPUT_STATE:devBuzzerSetNum(1);break;case UARTLCD_COMMAND_BUZZER_LEVEL:devBuzzerSetNum(1);break;case UARTLCD_COMMAND_LANGUAGE:devBuzzerSetNum(1);break;case UARTLCD_COMMAND_MESSAGE_WARNING:devBuzzerSetNum(1);break;case UARTLCD_COMMAND_LIGHT_WARNING:devBuzzerSetNum(1);break;case UARTLCD_COMMAND_USB_CHANGE:devBuzzerSetNum(1);break;case UARTLCD_COMMAND_VERSION_MESSGAE:devBuzzerSetNum(1);break; default:break;}
}
uart_lcd.h
#ifndef __UART_LCD_H
#define __UART_LCD_H
#include "main.h"
#include "log.h"
#include "usart.h"
#include "eeprom.h"
#include <string.h>#define UARTLCD_TASK_PERIOD 2 //#define UARTLCD_LOG_EN 0
#if UARTLCD_LOG_EN#define UARTLCD_printf(format, ...) printf(RTT_CTRL_TEXT_WHITE format , ##__VA_ARGS__)//"\r\n"#define UARTLCD_info(format, ...) printf(RTT_CTRL_TEXT_GREEN"[uartlcd]info:" format , ##__VA_ARGS__)#define UARTLCD_debug(format, ...) printf(RTT_CTRL_TEXT_WHITE"[uartlcd]debug:" format , ##__VA_ARGS__)#define UARTLCD_warning(format, ...) printf(RTT_CTRL_TEXT_YELLOW"[uartlcd]warning:" format , ##__VA_ARGS__)#define UARTLCD_error(format, ...) printf(RTT_CTRL_TEXT_RED"[uartlcd]error:" format ,##__VA_ARGS__)
#else#define UARTLCD_printf(format, ...)#define UARTLCD_info(format, ...)#define UARTLCD_debug(format, ...)#define UARTLCD_warning(format, ...)#define UARTLCD_error(format, ...)
#endif#define R_NUM 20 //缓冲区的个数(可以缓存几帧数据)
#define RBUFF_UNIT 10 //缓冲区一帧数据的长度#define T_NUM 20 //缓冲区的个数(可以缓存几帧数据)
#define TBUFF_UNIT 10 //缓冲区一帧数据的长度extern unsigned char UART_RxDataBuf[R_NUM][RBUFF_UNIT]; //接收缓存区
extern unsigned char *UART_RxDataInPtr; //接收缓存区存放数据的位置
extern unsigned char *UART_RxDataOutPtr; //接收缓存区读取数据的位置
extern unsigned char *UART_RxDataEndPtr; //接收缓存区结束的位置extern unsigned char UART_TxDataBuf[T_NUM][TBUFF_UNIT]; //发送缓存区
extern unsigned char *UART_TxDataInPtr; //发送缓存区存放数据的位置
extern unsigned char *UART_TxDataOutPtr; //发送缓存区读取数据的位置
extern unsigned char *UART_TxDataEndPtr; //发送缓存区结束的位置#define BUFFER_SIZE 100 //串口接收数据的临时缓存区大小
extern unsigned char receive_buff[BUFFER_SIZE]; //串口接收数据的临时缓存区typedef struct
{unsigned short headData; //数据头unsigned char commandData; //数据指令unsigned char lengthData; //数据内容长度unsigned int controlData; //数据内容
} uartLcdDataBody_t;typedef struct
{uartLcdDataBody_t bodyData; //消息体unsigned short crcData; //数据校验
} uartLcdDataFrame_t;enum{UARTLCD_COMMAND_INIT_CHECK, UARTLCD_COMMAND_FLOW_LEVEL, UARTLCD_COMMAND_SMOKE_CLEAN, UARTLCD_COMMAND_AIR_CONSUME, UARTLCD_COMMAND_PRESSURE_NOW, UARTLCD_COMMAND_PRESSURE_TARGET,UARTLCD_COMMAND_PRESSURE_REDUCE,UARTLCD_COMMAND_PRESSURE_ADD, UARTLCD_COMMAND_FLOW_NOW, UARTLCD_COMMAND_FLOW_TARGET, UARTLCD_COMMAND_FLOW_REDUCE, UARTLCD_COMMAND_FLOW_ADD, UARTLCD_COMMAND_PRESSURE_MODE, UARTLCD_COMMAND_HEAT_STATE, UARTLCD_COMMAND_AIR_START, UARTLCD_COMMAND_AIR_INPUT_STATE,UARTLCD_COMMAND_BUZZER_LEVEL, UARTLCD_COMMAND_LANGUAGE, UARTLCD_COMMAND_MESSAGE_WARNING,UARTLCD_COMMAND_LIGHT_WARNING, UARTLCD_COMMAND_USB_CHANGE, UARTLCD_COMMAND_VERSION_MESSGAE
};void uartLcdInit(void);
void uartLcdEndInit(void);
void uartLcdTask(void);unsigned short swapEndian16(unsigned short value);
unsigned int swapEndian32(unsigned int value);
unsigned short crc16Modbus(unsigned char *ptr, unsigned short len);void uartLcdMainUpdate(unsigned int num); void TxDataBufAdd(unsigned char *data); //向发送缓冲区加入一条待发送的数据
void RxDataBufAdd(unsigned char *data); //向接收缓冲区加入一条待处理的数据
void RxDataBufCheck(unsigned char *data,unsigned char length); //检验接收到串口数据是不是一帧合格的数据
void RxDataBufAnalyze(unsigned char *data); //处理串口指令
void TxDataBufPack(unsigned char command,unsigned int num); //发送串口数据封包
void TxDataBufSend(unsigned char command,unsigned int num); //直接发送串口数据,不经过缓存#endif相关文章:
STM32CUBEMX_DMA串口空闲中断接收+接收发送缓冲区
STM32CUBEMX_DMA串口空闲中断接收接收发送缓冲区 前言: 我了解的串口接收指令的方式有:在这里插入图片描述 1、接收数据中断特定帧尾 2、接收数据中断空闲中断 3、DMA接收空闲中断 我最推荐第三种,尤其是数据量比较大且频繁的时候 串口配置 …...
酸蚀刻对钛医药材料纳米形态表面特性及活化能的影响
引言 由于商业纯钛(CP Ti)具有抗腐蚀性,并且具有合适的机械性能以及生物相容性,因此,目前一直被用作牙科植入材料。为了在临床手术中获得高水平的成功,CP Ti的表面质量和形貌是影响植入手术结果的比较关键的因素之一,…...
iOS代码混淆工具推荐:IPA Guard详细介绍
iOS代码混淆工具推荐:IPA Guard详细介绍 目录 摘要: 引言 正文 1. IPA Guard概述 2. IPA Guard的功能特性 3. IPA Guard的混淆模式 4. 支持的语言 5. 使用场景 总结 参考资料 总结 参考资料 摘要: 了解并选择合适的iOS代码混淆工…...
Vue检测数据的原理
Vue能够对用户的数据进行响应式,也就是你在data中写了什么,你在模板中用到data的部分就会渲染成什么,那么Vue是怎么知道用户修改了data中的数据变化并对模板重新进行解析的呢? 在Vue将数据存储为自身的_data之前,Vue会…...
队列的运行算法
1.链队: 插入 删除 打印 取队顶 #include <stdio.h> #include <stdlib.h>typedef struct Qnode{int data;struct Qnode *next; }Qnode,*QuenePtr;typedef struct {QuenePtr front;QuenePtr rear; }LinkQueue; //初始化 void InitQueue(LinkQueue *q){(…...
KVM/qemu安装UOS 直接让输入用户密码
错误信息 安装后出现: 1、点击刚刚建立的虚拟机最上角感叹号(设备管理器) ----新建硬件---输入----类型:【通用 USB Mouse】。 ----新建硬件---输入----类型:【通用 USB keyboard】。 2、在设备管理器中----新建硬…...
画一条0.5px的线、设置小于12px的字体、解决 1px 问题
1、如何画一条0.5px的线 ① 采用 transform: scale() 的方式 该方法用来定义元素的 2D 缩放转换; .line {width: 100px;height: 40px;transform: scale(1,0.5);background-color: red;} ② 采用 meta viewport 的方式 这样就能缩放到原来的 0.5 倍,如…...
Unity中Shader的深度写入ZWrite
文章目录 前言一、更新深度缓冲区中值二、深度值的写入操作只有两个选择 开启 和 关闭ZWrite OnZWrite Off 三、深度写入在半透明物体物体中开启的情况1、特效一般都需要关闭深度写入2、如果在人物模型上使用 特效半透明 的 Shader,为了不出现模型自身穿透问题&…...
Jetson nano 系列之7—jetson 通过rtp将视频发给远程host
Jetson nano 系列之7—jetson 通过rtp将视频发给远程host 1.笔记本端配置1.1 安装VLC软件1.2 配置端口号1.3 创建SDP 文件2.执行命名,查看效果2.1 jetson端2.2 笔记本端参考文献本博客介绍了将jetson nano csi摄像头的视频通过rtp发给其他主机(这里是一台windows笔记本)。 …...
有哪些值得推荐的优秀 HTMLCSS 网站前端设计的网络资源(博客、论坛)?
前言 推荐几个有意思的CSS学习的网站和github上的学习类型的项目~ 网站推荐 1、CODEPEN 代码与所展示的页面相互对应,你可以在上面找到其他人已经写好的demo,参考 代码效果 网址:https://codepen.io 2、Coding Fantasy 通过游戏的形式来提…...
RTSP/Onvif安防视频平台EasyNVR级联至EasyNVS系统不显示通道,是什么原因?
视频安防监控平台EasyNVR可支持设备通过RTSP/Onvif协议接入,并能对接入的视频流进行处理与多端分发,包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等多种格式。 我们在此前的文章中也介绍过关于EasyNVR级联EasyNVS上云网关综合管理平台的内容ÿ…...
点云处理【三】(点云降采样)
点云降采样 第一章 点云数据采集 第二章 点云滤波 第二章 点云降采样 1. 为什么要降采样? 我们获得的数据量大,特别是几十万个以上的点云,里面有很多冗余数据,会导致处理起来比较耗时。 降采样是一种有效的减少数据、缩减计算量…...
GB/T 41510-2022 起重机械安全评估规范 通用要求 摘要
在线预览|GB/T 41510-2022http://c.gb688.cn/bzgk/gb/showGb?typeonline&hcno696806EC48F4105CEF7479EB32C80C9E 知识点: 安全等级定义,设计寿命,剩余寿命,使用寿命。 标准附录有应力的具体解算演示。...
【vr】【unity】白马VR课堂系列-VR开发核心基础05-主体设置-手柄对象的引入和设置
【视频教学】 【白马VR课堂系列-VR开发核心基础05-主体设置-手柄对象的引入和设置】 https://www.bilibili.com/video/BV19D4y1N73i/?share_source=copy_web&vd_source=7f5c96f5a58b7542fc6b467a9824b04e 【内容】 上一节引入了XR Origin并进行了初步设置,运行测试时V…...
UE5发布Android屏幕适配实践(Blueprint)
之前发了一个文章UE5屏幕适配,后续做项目中又遇到问题,对DPI Scale又有了理解,所以又写了这篇文章。https://mp.csdn.net/mp_blog/creation/editor/133337134https://mp.csdn.net/mp_blog/creation/editor/133337134 DPI Scale Rule使用Short…...
Spanner: Google’s Globally Distributed Database
1. INTRODUCTION Spanner可以扩展到跨数百个数据中心的数百万台机器与数万亿个数据库行。 Spanner是一个可伸缩、全球化分布的数据库,其由Google设计、构建、并部署。在抽象的最高层,Spanner是一个将数据分片(shard)到分布在全世…...
Java基础——了解进制和位运算
文章目录 关于进制位运算左位移右位移无符号右移取反按位与按位或按位异或 关于进制 所有数字在计算机底层都是以二进制的形式存在。 进制的四种表达形式: 二进制:[0,1],满2进1,以0b或0B开头。八进制:[0-7]…...
mybatisplus 自定义mapper加多表联查结合分页插件查询时出现缺失数据的问题
问题描述 最近做项目时使用了mybatisplus,分页插件也使用的是mybatisplus自带的分页插件,业务需求是查询客户列表,每个客户列表中有一个子列表,在通过分页插件查询后,会出现数量总数为子列表总数、客户列表与子列表不…...
陪诊系统|陪诊软件革新陪诊体验解决病患难题
随着医疗服务的不断升级和改善,陪诊系统作为现代医院的一项重要创新,为病患和陪护人员提供了更加便捷、高效的服务体验。本文将全面介绍陪诊系统的功能、特点和优势,让您更好地了解和体验这一创新科技。 一、系统功能 陪诊系统旨在为病患和陪…...
[Tkinter 教程08] Canvas 图形绘制
python - [译][Tkinter 教程08] Canvas 图形绘制 - 个人文章 - SegmentFault 思否 一、简介 Canvas 为 Tkinter 提供了绘图功能. 其提供的图形组件包括 线形, 圆形, 图片, 甚至其他控件. Canvas 控件为绘制图形图表, 编辑图形, 自定义控件提供了可能. 在第一个例子里, …...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
