首先使用逻辑分析仪查看ch340串口数据波形,根据波形写接收逻辑即可
开始位和停止位都是固定形式
使用外部中断捕获数据开始位,关闭中断,然后定时器计数清零重新计时,每隔1/波特率s采样一次数据,然后移位合成一个字节开启中断进入下一个等待接收状态(低位先接收)
uint8_t rec_count=0,rec_data[20]={0},rec_i=0,rx_temp;
#define baud 9600//接收波特率
int timer_rx=1000000/baud;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
HAL_GPIO_WritePin(led_GPIO_Port,led_Pin,0);
HAL_NVIC_DisableIRQ(EXTI15_10_IRQn);//关闭外部中断
rec_i=0;//接收位标记
rx_temp=0;//临时接收数据
htim1.Instance->CNT=0;//清零定时器计数值
while(htim1.Instance->CNT<timer_rx*9){//取8位数据位+1停止,无奇偶校验+1起始位
if(htim1.Instance->CNT>timer_rx*rec_i+(timer_rx+timer_rx/4)&&rec_i<8){//定时采样查看数据
rx_temp=rx_temp|((HAL_GPIO_ReadPin(rx_GPIO_Port,rx_Pin)&1)<<rec_i);//数据移位整合(默认低位先发送)
rec_i++;
}
}
rec_data[rec_count]=rx_temp;//存储临时值
rec_count++;
while(/*HAL_GPIO_ReadPin(rx_GPIO_Port,rx_Pin)==1*/htim1.Instance->CNT<timer_rx*10);//等待(前面等待时间不够)
__HAL_GPIO_EXTI_CLEAR_IT(rx_Pin);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);//开启接收中断,等待下一次
HAL_GPIO_WritePin(led_GPIO_Port,led_Pin,1);
}
发送更简单,只需要发送开始位后每隔1/波特率s发送一位数据即可(低位先发送),最后再发送停止位
void self_uart_send(int bauds,uint8_t *s){
int timer_tx=1000000/bauds;//给波特率(<9600)计算定时器计数比较值(9600->104us即1000000/9600)
HAL_NVIC_DisableIRQ(EXTI15_10_IRQn);//关闭接收
while(*s){
rec_i=0;//发送位清零
HAL_GPIO_WritePin(tx_GPIO_Port,tx_Pin,0);//起始位
htim1.Instance->CNT=0;//计时清零
while(htim1.Instance->CNT<timer_tx);//一个bit(start)
while(htim1.Instance->CNT<timer_tx*11 ){//8个数据+1个起始+2停止
if(htim1.Instance->CNT>(timer_tx*rec_i+timer_tx)&&rec_i<8||rec_i==0){
HAL_GPIO_WritePin(tx_GPIO_Port,tx_Pin,(*s>>rec_i)&1);//低位先发送
rec_i++;
}
if(htim1.Instance->CNT>timer_tx*9)HAL_GPIO_WritePin(tx_GPIO_Port,tx_Pin,1);//停止位
}
while(htim1.Instance->CNT<timer_tx*12);//直到停止位结束
s++;//
}
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);//开启接收
}
注意使用定时器需要先开启
HAL_TIM_Base_Start(&htim1);
代码:https://gitee.com/caneve/opencaneve/tree/main/STM32/103c8analog_uart