串口的时序就不再多讲了,主要是分享一个比自己写的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){//拉低TXDRESET_TXD();}else if(cnt_bit > 0 && cnt_bit < 9){if(uart_data & (0x01 << (cnt_bit - 1))){//输出高电平SET_TXD();}else{//输出低电平RESET_TXD();}}else{//拉高TXDSET_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库的外部中断函数中
如果程序出现了什么问题,欢迎和我交流