单缓冲区 + 接收中断
单缓冲区 + 空闲中断
双缓冲区 + 空闲中断
环形缓冲区 + 空闲中断
自定义串口协议
串口数据解析:
/**
* 计算数据校验和
* 从帧类型开始(包括帧类型),累加到最后一个数据,后取低8位
*/
uint8_t mid_tp_check_sum(uint8_t *p_data, uint8_t length)
{
uint8_t check_sum = 0;
for (uint8_t i = 0; i < length; i++)
{
check_sum += p_data[i];
}
return check_sum;
}
void mid_tp_state_machine(void)
{
uint8_t rec_buffer = 0, check_sum = 0;
static mid_tp_frame_format_t rec_frame;
static uint32_t timeout = 0;
static uint8_t count = 0;
if (CircularBufferGetDataSize(uart_receive_buffer) > 0)
{
// 刷新计时器
timeout = HAL_GetTick();
CircularBufferPop(uart_receive_buffer, 1, &rec_buffer);
switch (step)
{
case 0: // 解析帧头
if (rec_buffer == MID_TP_FRAME_HEAD_F)
{
step = 1;
}
break;
case 1: // 解析帧头
if (rec_buffer == MID_TP_FRAME_HEAD_S)
{
step = 2;
}
else
{
step = 0;
}
break;
case 2: // 解析帧类型
rec_frame.frame_type = rec_buffer;
if ((rec_buffer == MID_TP_FRAME_TYPE_SET) || (rec_buffer == MID_TP_FRAME_TYPE_GET))
{
count = 0;
step = 3;
}
else
{
printf("rec frame_type error\r\n");
memset(&rec_frame, 0, sizeof(mid_tp_frame_format_t));
step = 0;
}
break;
case 3: // 解析数据长度
rec_frame.frame_length = rec_buffer;
step = 4;
break;
case 4: // 解析数据
rec_frame.frame_payload[count++] = rec_buffer;
// printf("frame_payload[%d] = 0x%x\r\n", count, rec_buffer);
if (count == rec_frame.frame_length)
{
step = 5;
}
// printf("count = %d, rec_frame.frame_length = %d\r\n", count, rec_frame.frame_length);
break;
case 5: // 解析校验和
rec_frame.frame_check_sum = rec_buffer;
check_sum = mid_tp_check_sum((uint8_t *)&rec_frame.frame_type, rec_frame.frame_length + 2);
if (rec_frame.frame_check_sum == check_sum) // 校验成功
{
switch (rec_frame.frame_type)
{
case MID_TP_FRAME_TYPE_SET: // 设置
switch (rec_frame.frame_payload[0])
{
case MID_TP_DATA_FUNC_VOLTAGE:
printf("set voltage = %d\r\n", rec_frame.frame_payload[1] << 8 | rec_frame.frame_payload[2]);
g_commu_data.target_voltage = rec_frame.frame_payload[1] << 8 | rec_frame.frame_payload[2];
mid_tp_ack(MID_TP_FRAME_TYPE_ACK, MID_TP_DATA_FUNC_VOLTAGE);
break;
case MID_TP_DATA_FUNC_CURRENT:
printf("set current = %d\r\n", rec_frame.frame_payload[1] << 8 | rec_frame.frame_payload[2]);
g_commu_data.target_current = rec_frame.frame_payload[1] << 8 | rec_frame.frame_payload[2];
mid_tp_ack(MID_TP_FRAME_TYPE_ACK, MID_TP_DATA_FUNC_CURRENT);
break;
default:
break;
}
break;
case MID_TP_FRAME_TYPE_GET: // 获取
switch (rec_frame.frame_payload[0])
{
case MID_TP_DATA_FUNC_STATUS:
mid_tp_ack(MID_TP_FRAME_TYPE_GET, MID_TP_DATA_FUNC_STATUS);
break;
default:
break;
}
break;
default:
break;
}
}
else
{
printf("rec frame_check_sum error, rec_frame.frame_check_sum = 0x%x, check_sum = 0x%x\r\n", rec_frame.frame_check_sum, check_sum);
}
memset(&rec_frame, 0, sizeof(mid_tp_frame_format_t));
step = 0;
break;
}
}
if (step != 0) // 超时检测,比如收到了开头或是中间部分,但是后续的部分没收到
{
if (HAL_GetTick() - timeout > 500)
{
printf("timeout current step = %d\r\n", step);
memset(&rec_frame, 0, sizeof(mid_tp_frame_format_t));
step = 0;
}
}
}发送数据:
static void mid_tp_ack(uint8_t frame_type, uint8_t data_func)
{
uint8_t send_buffer[20] = {0};
send_buffer[0] = 0xA5;
send_buffer[1] = 0x5A;
send_buffer[2] = MID_TP_FRAME_TYPE_ACK;
send_buffer[3] = 3;
send_buffer[4] = data_func;
switch (data_func)
{
case MID_TP_DATA_FUNC_VOLTAGE: // 发送电压
send_buffer[5] = g_commu_data.target_voltage >> 8;
send_buffer[6] = g_commu_data.target_voltage & 0xFF;
send_buffer[7] = mid_tp_check_sum(send_buffer + 2, 5);
break;
case MID_TP_DATA_FUNC_CURRENT: // 发送电流
send_buffer[5] = g_commu_data.target_current >> 8;
send_buffer[6] = g_commu_data.target_current & 0xFF;
send_buffer[7] = mid_tp_check_sum(send_buffer + 2, 5);
break;
case MID_TP_DATA_FUNC_STATUS: // 发送状态
send_buffer[3] = 7;
send_buffer[5] = MID_TP_STA_MODE_CV; // 模式
send_buffer[6] = g_commu_data.current_voltage >> 8;
send_buffer[7] = g_commu_data.current_voltage & 0xFF;
send_buffer[8] = g_commu_data.current_current >> 8;
send_buffer[9] = g_commu_data.current_current & 0xFF;
send_buffer[10] = MID_TP_STA_ERROR_NONE; // 错误信息
send_buffer[11] = mid_tp_check_sum(send_buffer + 2, 9);
break;
default:
break;
}
HAL_UART_Transmit(&huart3, send_buffer, send_buffer[3] + 5, 0xFFFF);
}