超简单GPIO模拟实现可变波特率异步串口收发(STM32)

 首先使用逻辑分析仪查看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

演示视频:超简单STM32使用GPIO模拟串口实现收发_哔哩哔哩_bilibili

猜你喜欢

转载自blog.csdn.net/hhcgn/article/details/131570616