STM32的IO模拟串口

本文介绍了如何使用STM32的GPIO和定时器实现UART通信,包括发送和接收字节、字符串,以及初始化过程。通过定时器中断和外部中断管理数据传输和等待状态。
摘要由CSDN通过智能技术生成

串口的时序就不再多讲了,主要是分享一个比自己写的IO模拟串口的实例

申明:

这个波特率为115200

分频系数为8

自动重载值为68

约等于8.7微秒

使用其他波特率或者IO口,只需要修改.h文件中的对应参数即可

头文件

#ifndef IO_UART_H
#define IO_UART_H

#include "tim.h"

enum
{
	N_CMD,	//空闲
	W_CMD,	//写
	R_CMD,	//读
	F_CMD,	//完成
};
enum
{
	UNWAIT,
	WAITING,
};


#define U_TIM		TIM4			//UART内部定时器
#define	TX_GPIO_PIN	GPIO_PIN_15		//UART对应的TX引脚
#define	RX_GPIO_PIN	GPIO_PIN_14		//UART对应的RX引脚
#define TX_PIN		14				//UART对应的TX引脚编号
#define RX_PIN		15				//UART对应的RX引脚编号
#define	TX_GPIO		GPIOB			//UART对应的TX端口
#define	RX_GPIO		GPIOB			//UART对应的RX端口

#define MAX_WAIT 	0x5		//最大等待时间
#define T_RELOAD 	68		//发送一个字节所需的时间
#define T_FIRST		0x33	//延时到第一位的时间

#define MAX_BUFSIZE	3000	//收发最大字符数量


/************************************
function : 定时器中断回调函数
************************************/
void TIM_UART_Callback(TIM_HandleTypeDef *htim);
/************************************
function : 外部中断回调函数 
************************************/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
/************************************
function : 发送一个字节
input : uint8_t send_data	//要发送的字节
return : void
************************************/
void SEND_BYTE(uint8_t send_data);
/************************************
function : 发送一个字符串
input : uint8_t *send_data	//要发送的字符串
return : void
************************************/
void SEND_STRING(uint8_t *send_data);
/************************************
function : 等待读取一个字符串
input : uint8_t *read_data	//接收目标字符串
return : void
************************************/
void READ_STRING(uint8_t *read_data);
/************************************
function : 清空一个字符串
input : uint8_t *string	//要清楚的字符串	size_t str_len	//清除字符串的长度
return : void
************************************/
void ZERO_STRING(uint8_t *string,size_t str_len);
/************************************
function : UART初始化
input : void
return : void
************************************/
void UART_INIT(void);
#endif



.c文件

#include "io_uart.h"

volatile uint8_t uart_flag = N_CMD;
uint8_t cnt_bit = 0;
uint8_t uart_data = 0;
uint8_t wait_flag = UNWAIT;
uint8_t **buf = NULL;
uint32_t i = 0;

/************************************
function : 拉高TXD
************************************/
static void SET_TXD(void)
{
	TX_GPIO->BSRR = TX_GPIO_PIN;
}
/************************************
function : 拉低TXD
************************************/
static void RESET_TXD(void)
{
	TX_GPIO->BSRR = (uint32_t)TX_GPIO_PIN << 16u;
}
/************************************
function : 读取RXD电平
************************************/
static uint8_t READ_RXD(void)
{
	return ((RX_GPIO->IDR & RX_GPIO_PIN) >> TX_PIN);
}
/************************************
function : 定时器中断回调函数
************************************/
void TIM_UART_Callback(TIM_HandleTypeDef *htim)
{
	//写一个字节
	if(uart_flag == W_CMD)
	{
		if(cnt_bit == 0)
		{
			//拉低TXD
			RESET_TXD();
		}
		else if(cnt_bit > 0 && cnt_bit < 9)
		{
			if(uart_data & (0x01 << (cnt_bit - 1)))
			{
				//输出高电平
				SET_TXD();
			}
			else
			{
				//输出低电平
				RESET_TXD();
			}
		}
		else
		{
			//拉高TXD
			SET_TXD();
			cnt_bit = 0;
			uart_flag = N_CMD;
			uart_data = 0;
			//关闭定时器中断
			U_TIM->CR1 &= ~(TIM_CR1_CEN);
			return;
		}
		cnt_bit++;
	}
	//读一个字节
	else if(uart_flag == R_CMD)
	{
		if(cnt_bit == 0)
		{
			//设置定时器定时时间
			U_TIM->ARR = T_RELOAD;
		}
		else if(cnt_bit == 8)
		{
			cnt_bit = 0;
			/****new****/
			//设置定时器定时时间
			U_TIM->CNT = 0x00;
			U_TIM->ARR = T_RELOAD*MAX_WAIT;
			(*buf)[i] = uart_data;
			i++;
			uart_data = 0;
			wait_flag = WAITING;
			cnt_bit = 0;
			//打开外部中断
			EXTI->PR = (RX_GPIO_PIN);
			EXTI->IMR |= (0x1 << TX_PIN);
			/****new****/
			return;
		}
		uart_data |= (READ_RXD() << cnt_bit);
		cnt_bit++;
		//判断是否读取完成
		if(wait_flag == WAITING)
		{
			//读取完成
			uart_flag = F_CMD;
			wait_flag = UNWAIT;
			//关闭定时器中断
			U_TIM->CR1 &= ~(TIM_CR1_CEN);
			//关闭外部中断
			EXTI->IMR &= ~(0x1 << TX_PIN);
			return;
		}
	}
}
/************************************
function : 外部中断回调函数 
************************************/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	switch(GPIO_Pin)
	{
		case RX_GPIO_PIN:
		EXTI->PR = (RX_GPIO_PIN);
			if(uart_flag != R_CMD)
				return;
			else
			{
				wait_flag = UNWAIT;
				//关闭定时器中断
				U_TIM->CR1 &= ~(TIM_CR1_CEN);
				//设置定时器定时时间
				U_TIM->CNT = 0x00;
				U_TIM->ARR = T_FIRST;
				//打开定时器中断
				U_TIM->SR = ~(TIM_IT_UPDATE);
				U_TIM->CR1 |= (TIM_CR1_CEN);
				//关闭外部中断
				EXTI->IMR &= ~(0x1 << TX_PIN);
				EXTI->PR = (RX_GPIO_PIN);
			}
			break;
		default:
			break;
	}
}
/************************************
function : 发送一个字节
input : uint8_t send_data	//要发送的字节
return : void
************************************/
void SEND_BYTE(uint8_t send_data)
{
	while(uart_flag != N_CMD);
	uart_flag = W_CMD;
	cnt_bit = 0;
	uart_data = send_data;
	//打开定时器中断
	U_TIM->SR = ~(TIM_IT_UPDATE);
	U_TIM->CR1 |= (TIM_CR1_CEN);
	while(uart_flag != N_CMD);
}
/************************************
function : 发送一个字符串
input : uint8_t *send_data	//要发送的字符串
return : void
************************************/
void SEND_STRING(uint8_t *send_data)
{
	uint32_t j = 0;
	for(j = 0; (send_data[j] != 0 || send_data[j+1] != 0) && i < MAX_BUFSIZE-1; j++)
	{
		SEND_BYTE(send_data[j]);
	}
}
/************************************
function : 等待读取一个字符串
input : uint8_t *read_data	//接收目标字符串
return : void
************************************/
void READ_STRING(uint8_t *read_data)
{
	while(uart_flag != N_CMD);
	i = 0;
	buf = &read_data;
	cnt_bit = 0;
	uart_flag = R_CMD;
	//打开外部中断
	EXTI->PR = (RX_GPIO_PIN);
	EXTI->IMR |= (0x1 << TX_PIN);
	while(uart_flag != F_CMD);
	//read_data[255]	read_data[254] read_data[256] read_data[258] read_data[0] read_data[1] 
	buf = NULL;
	uart_data = 0;
	cnt_bit = 0;
	uart_flag = N_CMD;
}
/************************************
function : 清空一个字符串
input : uint8_t *string	//要清楚的字符串	size_t str_len	//清除字符串的长度
return : void
************************************/
void ZERO_STRING(uint8_t *string,size_t str_len)
{
	int i = 0;
	for(i = 0; i < str_len; i++)
	{
		string[i] = 0;
	}
	return;
}
/************************************
function : UART初始化
input : void
return : void
************************************/
void UART_INIT(void)
{
	//清空定时器中断标志位
	U_TIM->SR = ~(TIM_IT_UPDATE);
	//关闭定时器中断
	U_TIM->DIER |= (TIM_IT_UPDATE);
	U_TIM->CR1 &= ~(TIM_CR1_CEN);
	//关闭外部中断
	EXTI->IMR &= ~(0x1 << TX_PIN);
	//清空外部中断标志位
	EXTI->PR = (RX_GPIO_PIN);
}
//

/************************************
function : 定时器中断回调函数
************************************/
void TIM_UART_Callback(TIM_HandleTypeDef *htim);这个定时器回调函数写在对应的HAL的回调函数中,

/************************************
function : 外部中断回调函数 
************************************/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);如果使用了其他的外部中断,可以像定时器中断那样改一个名字后放入对应的HAL库的外部中断函数中

 如果程序出现了什么问题,欢迎和我交流

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值