阻塞轮询方式

// 发送数据
int std::fputc(int ch, FILE* f) {
 HAL_UART_Transmit(&huart3, (uint8_t*)&ch, 1, HAL_MAX_DELAY);
 return ch;
}

//接收数据
int std::fgetc(FILE* f) {
 uint8_t ch;
 HAL_UART_Receive(&huart3, &ch, 1, HAL_MAX_DELAY);
 return ch;
}

中断式

固定长度

// 定长
char rx_data[5]; // 每次接收一个字节
uint8_t rx_len = sizeof(rx_data);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef* huart) {
    if (huart->Instance == USART3) {
        HAL_UART_Transmit_IT(&huart3, (uint8_t*)"www", 3); // 回传接收到的字节
        HAL_UART_Receive_IT(&huart3, (uint8_t*)&rx_data, rx_len);  // 重新启用接收中断
    }
}

void receive(void) {
    HAL_UART_Receive_IT(&huart3, (uint8_t*)&rx_data, rx_len); // 开始逐字节接收
}

不定长

// 不定长,终止位
uint8_t rx_data[100] = {0}; // 用于接收和回传的数据
uint8_t buf;
uint16_t size = sizeof(rx_data);
uint8_t index = 0; // 当前缓冲区索引

// 接收完成回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
  if (huart->Instance == USART3) {
	rx_data[index++]=buf;
    if (index >= 0 && (buf == '#' || buf == '\n')) {
      // 检测到结束符,回传所有接收到的数据
      HAL_UART_Transmit_IT(&huart3, rx_data,index); // 回传所有数据

	}
	HAL_UART_Receive_IT(&huart3, &buf, 1);
  }
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
  if (huart->Instance == USART3) {
     for(uint8_t i = 0;i<index;i++){
		rx_data[i]= '0';
	 }
     index = 0; // 重置索引
  }
}

// 初始化接收
void receive() {
  index = 0;
  HAL_UART_Receive_IT(&huart3, &buf, 1);
}

解包

typedef enum {
	RED = 0,
	GREEN = 1,
	BLUE = 2,
	red = 3,
	green = 4,
	blue = 5,
	UNKNOWN = -1 // 用于表示未知颜色
} color_t;

typedef struct node {
	float x;
	float y;
	uint8_t color;
}point;
point node[CLASS] = { 0 };// 用于存储接收到的坐标和颜色

uint8_t rx_data[CLASS][50] = { 0 }; // 用于接收数据缓冲区

uint16_t size = sizeof(rx_data);
uint8_t buf;
uint8_t count = 0, index = 0;
uint8_t start = 0, next = 0, end = 0;

// 颜色字符串转序号
color_t string_to_color(const char* str) {
	if (strcmp(str, "RED") == 0)
		return RED;
	else if (strcmp(str, "GREEN") == 0)
		return GREEN;
	else if (strcmp(str, "BLUE") == 0)
		return BLUE;
	else if (strcmp(str, "red") == 0)
		return red;
	else if (strcmp(str, "green") == 0)
		return green;
	else if (strcmp(str, "blue") == 0)
		return blue;
	return UNKNOWN;
}

// 解析数据
void parse_data(char* data, point* p) {
	// char* color_str;
	if (sscanf(data, "%f,%f,%d", &p->x, &p->y, p->color) == 3) {
		//p->color = string_to_color(color_str); // 将颜色转换为枚举值
	}
}

// 结构体入队列*************
void queue(point* p) {

}

// 重置状态
void restart() {
	buf = 0;
	count = 0;
	index = 0;
	start = 0;
	next = 0;
	end = 0;
	for (uint8_t i = 0; i < CLASS; i++) {
		memset(rx_data[i], 0, sizeof(rx_data[i]));
	}
	for (uint8_t i = 0; i < CLASS; i++) {
		node[i].x = 0;
		node[i].y = 0;
		node[i].color = UNKNOWN;
	}
}

uint8_t s[100];
uint8_t i = 0;
// @125.05,256.55,0|255.47,896.05,1|1024.05,204.92,2|#
// 60*(6*2*6+5+2+2*6) = 60*
// 接收中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef* huart) {
	if (huart->Instance == USART3) {
		// 状态
		switch (buf)
		{
		case '@':
			start = 1;
			next = 0;
			end = 0;
			break;
		case '|':
			next = 1;
			start = 0;
			end = 0;
			break;
		case '#':
			end = 1;
			start = 0;
			next = 0;
			break;
		default:
			break;
		}
		if (start && next == 0 && end == 0 && buf != '@') {
			rx_data[count][index++] = buf; // 将接收到的数据存入缓冲区
			s[i++] = buf;
		}
		else if (next && end == 0 && start == 0) {
			parse_data(rx_data[count], &node[count]); //解包
			// queue(&node[count]); // 入队列
			count++;
			index = 0;
			next = 0;
			start = 1; //继续接收
		}
		else if (end && start == 0 && next == 0) {
			// HAL_UART_Transmit_IT(&huart3, (uint8_t *)"Data Received\n", 14);
			HAL_UART_Transmit_IT(&huart3, s, i);
			restart(); // 重置状态
		}
		HAL_UART_Receive_IT(&huart3, &buf, 1);
	}
}

// 发送完成回调
void HAL_UART_TxCpltCallback(UART_HandleTypeDef* huart) {
	if (huart->Instance == USART3) {
		i = 0;
		memset(s, 0, sizeof(s));
	}
}

// 主函数中调用此函数以启动接收
void receive(void) {
	index = 0;
	HAL_UART_Receive_IT(&huart3, &buf, 1);
}

版本2

typedef struct node {
	float x;
	float y;
	uint8_t color;
}point;
point node[CLASS] = { 0 };// 用于存储接收到的坐标和颜色

uint8_t rx_data[CLASS][50] = { 0 }; // 用于接收数据缓冲区

uint16_t size = sizeof(rx_data);
uint8_t buf;
uint8_t count = 0, index = 0;
uint8_t start = 0, next = 0, end = 0;


// 解析数据
void parse_data(char* data, point* p) {
	if (sscanf(data, "%f,%f,%d", &p->x, &p->y, p->color) == 3) {
		// 解析成功
	}
}

// 结构体入队列*************
void queue(point* p) {

}

// 重置状态
void restart() {
	buf = 0;
	count = 0;
	index = 0;
	start = 0;
	next = 0;
	end = 0;
	for (uint8_t i = 0; i < CLASS; i++) {
		memset(rx_data[i], 0, sizeof(rx_data[i]));
	}
	for (uint8_t i = 0; i < CLASS; i++) {
		node[i].x = 0;
		node[i].y = 0;
		node[i].color = 255;
	}
}

uint8_t s[100];
uint8_t i = 0;
// @125.05,256.55,0|255.47,896.05,1|1024.05,204.92,2|#
// 60*(6*2*6+5+2+2*6) = 60*
// 接收中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef* huart) {
	if (huart->Instance == USART3) {
		// 状态
		switch (buf)
		{
		case '@':
			start = 1;
			next = 0;
			end = 0;
			break;
		case '|':
			next = 1;
			start = 0;
			end = 0;
			break;
		case '#':
			end = 1;
			start = 0;
			next = 0;
			break;
		default:
			break;
		}
		if (start && next == 0 && end == 0 && buf != '@') {
			rx_data[count][index++] = buf; // 将接收到的数据存入缓冲区
			s[i++] = buf;
		}
		else if (next && end == 0 && start == 0) {
			parse_data(rx_data[count], &node[count]); //解包
			// queue(&node[count]); // 入队列
			count++;
			index = 0;
			next = 0;
			start = 1; //继续接收
		}
		else if (end && start == 0 && next == 0) {
			// HAL_UART_Transmit_IT(&huart3, (uint8_t *)"Data Received\n", 14);
			HAL_UART_Transmit_IT(&huart3, s, i);
			restart(); // 重置状态
		}
		HAL_UART_Receive_IT(&huart3, &buf, 1);
	}
}

// 发送完成回调
void HAL_UART_TxCpltCallback(UART_HandleTypeDef* huart) {
	if (huart->Instance == USART3) {
		i = 0;
		memset(s, 0, sizeof(s));
	}
}

// 主函数中调用此函数以启动接收
void receive(void) {
	index = 0;
	HAL_UART_Receive_IT(&huart3, &buf, 1);
}

DMA

定长

char rx_data[5]; // 每次接收一个字节
uint8_t rx_len = sizeof(rx_data);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef* huart) {
    if (huart->Instance == USART3) {
        HAL_UART_Transmit_DMA(&huart3, (uint8_t*)&rx_data, 3); // 回传接收到的字节
        HAL_UART_Receive_DMA(&huart3, (uint8_t*)&rx_data, rx_len);  // 重新启用接收中断
    }
}

void receive(void) {
    HAL_UART_Receive_DMA(&huart3, (uint8_t*)&rx_data, rx_len); // 开始逐字节接收
}

不定长

uint8_t rx_data[125] = { 0 }; // 每次接收一个字节
uint8_t rx_len = sizeof(rx_data);

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef* huart, uint16_t Size) {
    if (huart->Instance == USART3) {
      HAL_UART_Transmit_DMA(&huart3, rx_data, Size); // 回传接收到的字节

      HAL_UARTEx_ReceiveToIdle_DMA(&huart3, rx_data, rx_len);
    }
}

void start_usart3() {
  HAL_UARTEx_ReceiveToIdle_DMA(&huart3, rx_data, rx_len);
}

DMA当接收的数据量打到一半的rx_len的时候也会触发这个空闲中断,所以需要关闭掉这个玩意。上面的代码是有问题的哦!

下面是关闭传输过半就发生的代码:

uint8_t rx_data[125] = { 0 }; // 每次接收一个字节
uint8_t rx_len = sizeof(rx_data);

// DMA当接收的数据量打到一半的rx_len的时候也会触发这个空闲中断,所以需要判断一下
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef* huart, uint16_t Size) {
    if (huart->Instance == USART3) {
      HAL_UART_Transmit_DMA(&huart3, rx_data, Size); // 回传接收到的字节

      HAL_UARTEx_ReceiveToIdle_DMA(&huart3, rx_data, rx_len);
      __HAL_DMA_DISABLE_IT(&hdma_usart3_rx, DMA_IT_HT);
    }
}

void start_usart3() {
  HAL_UARTEx_ReceiveToIdle_DMA(&huart3, rx_data, rx_len);
  __HAL_DMA_DISABLE_IT(&hdma_usart3_rx, DMA_IT_HT);
}

解包

/*
DMA操作
*/
typedef struct node {
  float x;
  float y;
  uint8_t color;
}point;

point node[CLASS] = { 0 };// 用于存储接收到的坐标和颜色

uint8_t rx_data[125] = { 0 }; // 用于接收数据缓冲区
uint8_t rx_buffer[CLASS][50] = { 0 }; // 用于存储接收到的字符串
uint16_t size = sizeof(rx_data);

uint8_t count = 0, index = 0;
// @125.05,256.55,0|255.47,896.05,1|1024.05,204.92,2|#
uint8_t s[100];
uint8_t i;
// 字符串数据存入结构体
void parse_data(char* data, point* p) {
  if (sscanf(data, "%f,%f,%d", &p->x, &p->y, p->color) == 3) {
    // 解析成功
  }
}

void clear() {
  memset(rx_buffer, 0, sizeof(rx_buffer));
  memset(rx_data, 0, sizeof(rx_data));
  memset(node, 0, sizeof(node));
  memset(s, 0, sizeof(s));
  count = 0;
  index = 0;
  i = 0;
}

// 解析字符串
uint8_t parse_string(char* data, uint8_t len) {
  char* p = data;
  uint8_t flag = 0x00; // 判断是否为完整的数据包
  while (*p != '\0') {
    if (*p == '@') {
      p++;
      flag = flag | 0x01;
    }
    else if (*p == '|') {
      parse_data((char*)rx_buffer[count], &node[count]);
      index = 0;
      count++;
      p++;
    }
    else if (*p == '#') {
      s[i++] = '\n';
      flag = flag | 0x10;
    }
    else {
      s[i++] = *p;
      rx_buffer[count][index++] = *p;
      p++;
    }
  }
  if(flag!=0x11){
    clear();
  }
  return 1;
}

// 结构体入队列*************
void queue(point* p) {

}

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef* huart, uint16_t Size) {
  if (huart->Instance == USART3) {

    parse_string((char*)rx_data, Size);
    // queue();
    HAL_UART_Transmit_DMA(&huart3, s, i); // 回传接收到的字节

    HAL_UARTEx_ReceiveToIdle_DMA(&huart3, rx_data, sizeof(rx_data));
    __HAL_DMA_DISABLE_IT(&hdma_usart3_rx, DMA_IT_HT);
  }
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART3)
    {
        clear(); // 清空缓冲区
    }
}

void start_usart3() {
  HAL_UARTEx_ReceiveToIdle_DMA(&huart3, rx_data, sizeof(rx_data));
  __HAL_DMA_DISABLE_IT(&hdma_usart3_rx, DMA_IT_HT);
}

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐