STM32模拟串口通信实现
串口的时序就不再多讲了,主要是分享一个比自己写的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库的外部中断函数中
如果程序出现了什么问题,欢迎和我交流
作者:O WL