(一)需实现的功能
在串口1接收到上位机以ASCII码格式发送的字符串“OK!”后,返回两路ADC的采集结果。
(二)状态机状态设定
状态机有三个状态:
- 等待 'O' (
state 0
) - 等待 'K' (
state 1
) - 等待 '!' (
state 2
)
状态转换过程:
-
初始状态:
USART1_State = 0
- 如果接收到字符 'O',则状态转换到
state 1
,即USART1_State = 1
。 - 其他字符不会改变状态,保持在
state 0
。
- 如果接收到字符 'O',则状态转换到
-
状态
state 1
:- 如果接收到字符 'K',则状态转换到
state 2
,即USART1_State = 2
。 - 如果接收到字符 'O',则状态保持在
state 1
,即继续等待 'K'。 - 其他字符会使状态重置到
state 0
。
- 如果接收到字符 'K',则状态转换到
-
状态
state 2
:- 如果接收到字符 '!',则标志
UART1_Rx_flg
置为 1,状态机重置到state 0
。 - 如果接收到字符 'O',则状态转换到
state 1
,即等待 'K'。 - 其他字符会使状态重置到
state 0
- 如果接收到字符 '!',则标志
(三)代码实现
1.串口中断回调函数(usart.c中)
注意使用Switch语句需配套break使用否则会造成卡死,且STM32标准串口在接收数据时总是一个字节一个字节的进行接收。若想读取所有接受到的数据则应将所接收的数据存入缓存中
static uint8_t USART1_State=0; // 初始状态等待,设置状态机标志为0
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
// 将接收到的字节存入缓冲区
UART1_Rx_Buf[UART1_Rx_cnt] = UART1_temp[0];
UART1_Rx_cnt++;
// 状态机处理接收到的字节
switch (USART1_State)
{
case 0:
if (UART1_temp[0] == 'O')
{
USART1_State = 1;//接收到了字符O则将标志置1
}
break;
case 1:
if (UART1_temp[0] == 'K')
{
USART1_State = 2;//接收到了字符K则将标志置2
}
else if (UART1_temp[0] == 'O')
{
USART1_State = 1;// 如果接收到 'O',则继续等待 'K'
}
else
{
USART1_State = 0;// 如果不是 'O' 或 'K',重置状态机
}
break;
case 2:
if (UART1_temp[0] == '!')
{
UART1_Rx_flg = 1; // 收到 "OK!",置标志位
USART1_State = 0; // 重置状态机
}
else if (UART1_temp[0] == 'O')
{
USART1_State = 1;// 如果接收到 'O',则等待 'K'
} else
{
USART1_State = 0;// 如果不是 'O' 或 '!',重置状态机
}
break;
default:
USART1_State = 0;
break;
}
// 继续接收下一个字节
HAL_UART_Receive_IT(&huart1, (uint8_t *)UART1_temp, 1);
}
}
代码说明
UART1_Rx_Buf[UART1_Rx_cnt] = UART1_temp[0];
- 将接收到的字节存入接收缓冲区。
UART1_Rx_cnt++;
- 增加接收计数器。
switch (USART1_State)
- 根据当前状态机状态,选择对应的状态处理。
HAL_UART_Receive_IT(&huart1, (uint8_t *)UART1_temp, 1);
- 继续接收下一个字节,以中断方式
上述用到的变量及数组需要在usart.h中声明
#define REC_LENGTH 1
#define MAX_REC_LENGTH 1024
extern uint8_t UART1_Rx_Buf[MAX_REC_LENGTH];//串口1数据接收缓存,最大可缓存1024字节
extern uint8_t UART1_Rx_flg;//接收完成标志,接收到0a回车键认为接收完成
extern uint32_t UART1_Rx_cnt;//接收计数标志
extern uint8_t UART1_temp[REC_LENGTH];//串口数据实时缓存
2.主函数检测接收标志(main.c中)
send_string及send_hex_as_decimal为自定义函数,使用时需从已有工程中复制
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
Get_ADC1_Average_Value();//计算ADC1的值并存入缓存数组
if(UART1_Rx_flg==1)//接收到上位机发送的OK
{
send_string("Y_out=",&huart1);
send_hex_as_decimal(Y_out,&huart1);
send_string(" ; ",&huart1);
send_string("Z_out=",&huart1);
send_hex_as_decimal(Z_out,&huart1);
send_string("\r\n",&huart1);
for(uint16_t i=0;i<UART1_Rx_cnt;i++)
{
UART1_Rx_Buf[i]=0; //清零接收缓存
}
UART1_Rx_cnt = 0;
UART1_Rx_flg = 0;
}
}
/* USER CODE END 3 */
}