- 最近不做嵌入式,这是一个以前做过产品的技术备忘。因为之前请教大神得到一些很好的思路。
如果我们需要接收一个序列协议,怎么做呢?
先放到缓冲区然后再检查标志位是一种思路。道理简单,关键要看怎么设计。这里介绍的方法是巧妙利用定时器,与串口中断进行耦合,得到一种鲁棒的接收方法。
具体:
- 打开定时器与串口中断
- 首先用示波器查看完整帧所需要的时间,并且设置为timMax。
- 定时器以适当的中断频率开启(例如1ms),每次中断都把表示时间的变量+1。
- 如果定时器中断时间超过timMax,则令接收数组的指针为0。
- 每次进来串口中断之后,定时器时间变量为0,接收数组的指针+1。
给出代码:
定时器端:
/**
* @brief This function handles TIM4 global interrupt.
*/
void TIM4_IRQHandler(void)
{
/* USER CODE BEGIN TIM4_IRQn 0 */
/* USER CODE END TIM4_IRQn 0 */
HAL_TIM_IRQHandler(&htim4);
/* USER CODE BEGIN TIM4_IRQn 1 */
div_freq_flag_temp_laser_1 += 1;
// Èç¹ûһֱûÓб»ÇåÁã ÄÇôºÜ¿ì»áÇ¿ÖÆÇåÁã Ò»¶¨Òª×¢Òâ ֮ǰµÄ»ù´¡ÖÜÆÚ²»ÊÇ1ms£¡£¡ÏÖÔڸĹýÀ´¾Í¿ÉÒÔÁË£¡
if(div_freq_flag_temp_laser_1 > div_freq_laser_flag){
laser_1_ptr = 0;
}
// ToggleIO
// HAL_GPIO_TogglePin(GPIOH, GPIO_PIN_9);
/* USER CODE END TIM4_IRQn 1 */
}
串口端:
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
div_freq_flag_temp_laser_1 = 0; // ½ÓÊս׶α£Ö¤temp²»»á³¬¹ý10ms
lazer_data1[laser_1_ptr] = recvyoadata1[0];
laser_1_ptr += 1;
// ²½½øµç»ú ºáÏò X
// if(lazer_data1[0]==0x55 && lazer_data1[1]==0x51 && lazer_data1[10]==0xFF)
if(lazer_data1[0] == 0x55)
{
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
lazer_op1= (uint16_t)(lazer_data1[6] << 8 | lazer_data1[7]); // 2 3 //
// YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
lazer_op2=(uint16_t)(lazer_data1[8] << 8 | lazer_data1[9]);
// HAL_GPIO_TogglePin(GPIOH, GPIO_PIN_9);
}
HAL_UART_Receive_IT(&huart1, recvyoadata1,1);
/* USER CODE END USART1_IRQn 1 */
}