由于没有多余的串口,需要用到GPIO模拟串口接收,目前只用到接收,第一时间的想法是通过外部中断来捕获起始位,然后再关闭外部中断,用定时器捕获数据,这一过程遇到了不少问题,详细记录一下
1、中断优先级问题
由于最开始调试,开启了外部中断,想在外部中断里面延时打印信息,发现进入一次中断之后卡死,于是网上查阅资料,发现延时函数使用的是系统定时器,优先级最低,但外部中断默认优先级最高,因此在中断里面延时,计数器永远不会累加,中断回调函数就一直无法跳出,也无法清除中断标志位,所以就一直卡在外部中断里面。如果想用延时函数调试的话,可以将外部中断的优先级改低,系统定时器优先级提高(不建议在中断里进行延时操作)
2、外部中断停用再启用
在接收到串口发来的起始位时,需要将中断先停止,以防数据位下降产生中断。我在定时器取完值之后,再开启中断,发现即便没有产生下降沿,依然会再进一次外部中断,查阅资料发现应该是中断标志位未清除,在开启外部中断之后需要再清除一次标志位,问题解决
3、数据采样率
使用定时器来捕获数据,要么定时时间刚好等于波特率,要么就提高采样率,再在定时器中断里面判断与微调,由于懒得算波特率,采用的第二种方式。如果在起始位开始的时候立即采集,则会采集到起始位的一个0和数据的一个0,所以第一位需要丢弃掉,直至采集了8位数据之后,取出数据,重新开启外部中断,等待下次接收,目前只能一个字节一个字节接收,多字节暂未测试
测试代码
uint8_t uart_rx_flag = 0;
uint32_t exti_count = 0;
uint32_t TIM1_count = 0;
uint32_t TIM1_counter = 0;
uint16_t soft_uart_buff = 0;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin==F_BAK8_in_Pin)
{
exti_count++;
uart_rx_flag = 1;
//dbg_printf("EXIT_detect:%d\r\n",exti_count);
}
}
//定时器捕获软件串口
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1)
{
if(uart_rx_flag)
{
TIM1_counter++;
if(TIM1_counter > 71)
{
TIM1_counter = 0;
HAL_NVIC_DisableIRQ(EXTI0_IRQn);
if(HAL_GPIO_ReadPin(F_BAK8_in_GPIO_Port,F_BAK8_in_Pin) == 1)
{
soft_uart_buff = (soft_uart_buff | 0x8000) >> 1;
}
else
{
soft_uart_buff = soft_uart_buff >> 1;
}
TIM1_count++;
//dbg_printf("x%d-%d\r\n",TIM1_count,HAL_GPIO_ReadPin(F_BAK8_in_GPIO_Port,F_BAK8_in_Pin));
if(TIM1_count > 14)
{
TIM1_count = 0;
uart_rx_flag = 0;
//uint8_t send = (soft_uart_buff);
TRANSMITTER_STATE.wave_guide_sts = soft_uart_buff;
//dbg_printf("%x\r\n",TRANSMITTER_STATE.wave_guide_sts);
soft_uart_buff = 0;
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
__HAL_GPIO_EXTI_CLEAR_IT(F_BAK8_in_Pin);
}
}
}
}
}