最近工作中需要用到单片机与外接模块通信,因为串口都被占用,所以需要使用普通io口模拟uart实现通信,使用到PF0(tx)、PF1(rx)、TIM12(微秒延时)、TIM13IT(信号线电平检测)、TIM14IT(数据结束判断),特此做了demo进行测试,实测运行正常,用cubemx生成代码移植到rt-thread studio使用。如有遗漏或者存在bug的地方,请多指正!!
gpio配置在board.c
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin : PF0 */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_SET);
/*Configure GPIO pin : PF1 */ //rx配置为外部中断下降沿触发
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI1_IRQn,2,0);
HAL_NVIC_EnableIRQ(EXTI1_IRQn);
}
stm32f4xx_hal_conf.h
#define HAL_MODULE_ENABLED
#define HAL_TIM_MODULE_ENABLED
#define HAL_UART_MODULE_ENABLED
#define HAL_EXTI_MODULE_ENABLED
#define HAL_GPIO_MODULE_ENABLED
#define HAL_DMA_MODULE_ENABLED
#define HAL_RCC_MODULE_ENABLED
#define HAL_FLASH_MODULE_ENABLED
#define HAL_PWR_MODULE_ENABLED
#define HAL_CORTEX_MODULE_ENABLED
tim.c 定时配置为104us对应9600波特率,高波特率会乱码,9600刚刚好。TIM13、TIM14的中断服务函数和TIM8的部分中断共用一个:TIM8_UP_TIM13_IRQn、TIM8_TRG_COM_TIM14_IRQn。cv的时候注意mspinit中定时器时钟是否对应开启,中断优先级视情况而定
TIM_HandleTypeDef htim12; //用作us级延时,104us对应波特率9600
TIM_HandleTypeDef htim13;
TIM_HandleTypeDef htim14;
void MX_TIM12_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
htim12.Instance = TIM12;
htim12.Init.Prescaler = 84 - 1;
htim12.Init.CounterMode = TIM_COUNTERMODE_UP;
htim12.Init.Period = 0xFFFF -1 ;
htim12.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim12.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim12) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim12, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_Base_Start(&htim12);
}
void MX_TIM13_Init(void)
{
htim13.Instance = TIM13;
htim13.Init.Prescaler = 84 - 1;
htim13.Init.CounterMode = TIM_COUNTERMODE_UP;
htim13.Init.Period = 104 - 1;
htim13.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim13.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim13) != HAL_OK)
{
Error_Handler();
}
__HAL_TIM_CLEAR_FLAG(&htim13,TIM_FLAG_UPDATE); //清除溢出中断标志
__HAL_TIM_ENABLE_IT(&htim13,TIM_FLAG_UPDATE);
HAL_TIM_Base_Stop_IT(&htim13);
}
void MX_TIM14_Init(void)
{
htim14.Instance = TIM14;
htim14.Init.Prescaler = 84 - 1;
htim14.Init.CounterMode = TIM_COUNTERMODE_UP;
htim14.Init.Period = 104 - 1;
htim14.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim14.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim14) != HAL_OK)
{
Error_Handler();
}
__HAL_TIM_CLEAR_FLAG(&htim14,TIM_FLAG_UPDATE); //清除溢出中断标志
__HAL_TIM_ENABLE_IT(&htim14,TIM_FLAG_UPDATE);
HAL_TIM_Base_Stop_IT(&htim14);
}
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{
if(tim_baseHandle->Instance==TIM12)
{
__HAL_RCC_TIM12_CLK_ENABLE();
}
else if(tim_baseHandle->Instance==TIM13)
{
__HAL_RCC_TIM13_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);
}
else if(tim_baseHandle->Instance==TIM14)
{
__HAL_RCC_TIM14_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn);
}
}
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{
if(tim_baseHandle->Instance==TIM12)
{
__HAL_RCC_TIM12_CLK_DISABLE();
}
else if(tim_baseHandle->Instance==TIM13)
{
__HAL_RCC_TIM13_CLK_DISABLE();
HAL_NVIC_DisableIRQ(TIM8_UP_TIM13_IRQn);
}
else if(tim_baseHandle->Instance==TIM14)
{
__HAL_RCC_TIM14_CLK_DISABLE();
HAL_NVIC_DisableIRQ(TIM8_TRG_COM_TIM14_IRQn);
}
}
// 微秒延时
void delay_us(uint16_t us)
{
uint16_t tp1;
uint16_t tp2;
uint16_t dif;
tp1 = TIM12->CNT;
while(1){
tp2 = TIM12->CNT;
if(tp2 < tp1){
dif = tp2 + 0xffff - tp1;
}else{
dif = tp2 - tp1;
}
if(dif >= us)
break;
}
}
void delay_ms(uint16_t ms)
{
for(uint32_t i = 0 ;i < ms ;i++){
delay_us(1000);
}
}
it.h
#define UART_REC_LEN 32
enum {
UART_START_BIT, //停止位
UART_D0_BIT, //bit0
UART_D1_BIT, //bit1
UART_D2_BIT, //bit2
UART_D3_BIT, //bit3
UART_D4_BIT, //bit4
UART_D5_BIT, //bit5
UART_D6_BIT, //bit6
UART_D7_BIT, //bit7
UART_STOP_BIT, //结束位
};
extern uint8_t recvStat;
extern uint8_t recvData;
extern uint8_t UART_RX_BUF[UART_REC_LEN];
extern uint8_t UART_RX_STA;
extern uint8_t send_flag;
extern uint8_t data_cnt;
it.c
uint8_t recvStat = UART_STOP_BIT;
uint8_t recvData = 0x00;
uint8_t UART_RX_BUF[UART_REC_LEN];
uint8_t UART_RX_STA = 0;
uint8_t cnt = 0;
uint8_t data_cnt = 0;
void EXTI1_IRQHandler(void)
{
rt_interrupt_enter();
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
rt_interrupt_leave();
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_1){
if(!UART_RD_RX){
if(recvStat == UART_STOP_BIT){
recvStat = UART_START_BIT;
HAL_TIM_Base_Stop_IT(&htim14);
__HAL_TIM_SET_COUNTER(&htim14,0);
HAL_TIM_Base_Start_IT(&htim13);
}
}
}
__HAL_GPIO_EXTI_CLEAR_FLAG(EXTI_LINE_1);
}
void TIM8_UP_TIM13_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim13);
}
void TIM8_TRG_COM_TIM14_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim14);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM13){
recvStat++;
if(recvStat == UART_STOP_BIT){
HAL_TIM_Base_Stop_IT(&htim13);
__HAL_TIM_SET_COUNTER(&htim13,0);
UART_RX_BUF[UART_RX_STA] = recvData; //将当前处理完的字节存入数组
recvData = 0;
UART_RX_STA++;
data_cnt++; //判断接收到的字节数
HAL_TIM_Base_Start_IT(&htim14);
}else{
if(UART_RD_RX)
recvData |= 1 << (recvStat - 1);
else
recvData &= ~(1 << (recvStat - 1));
}
}else if(htim->Instance == TIM14){
if((recvStat == UART_STOP_BIT) && UART_RD_RX){
cnt++;
if(cnt > 11){
cnt = 0;
uart_transmit_str(UART_RX_BUF);
buf_clear();
HAL_TIM_Base_Stop_IT(&htim14);
__HAL_TIM_SET_COUNTER(&htim14,0);
}
}
}
}
iouart.h
#include "main.h"
#define delay_time 104 //波特率9600,1s传输9600bit
#define UART_SET_TX(x) HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, x)
#define UART_SET_RX(x) HAL_GPIO_WritePin(GPIOF, GPIO_PIN_1, x)
#define UART_RD_RX HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_1)
void uart_start(void);
void uart_stop(void);
void uart_transmit_byte(uint8_t cmd);
void uart_transmit_str(uint8_t *str);
void uart_transmit_buf(uint8_t *str);
void buf_clear(void);
iouart.c
#include "iouart.h"
void uart_start(void)
{
UART_SET_TX(0); //拉低tx线,作为起始信号
}
void uart_stop(void)
{
UART_SET_TX(1); //拉高tx线,作为结束信号
}
/*
* io模拟串口发送单个字节
* cmd:对应ascii码
* 低位在前
* */
void uart_transmit_byte(uint8_t cmd)
{
uart_start();
delay_us(delay_time);
for(uint8_t i = 0; i < 8 ; i++){
if(cmd & (0x01 << i)){
UART_SET_TX(1);
}else{
UART_SET_TX(0);
}
delay_us(delay_time); //波特率9600
}
uart_stop();
delay_us(delay_time);
}
/*
* io模拟串口发送字符串
* str:指针,指向字符串首地址
* */
void uart_transmit_str(uint8_t *str)
{
while(*str != '\0'){
uart_transmit_byte(*str);
str++;
}
}
/*
* io模拟串口发送数组
* str:指针,指向数组首地址
* */
void uart_transmit_buf(uint8_t *str)
{
while(data_cnt --){
uart_transmit_byte(*str);
str++;
}
}
/*清空接收数组*/
void buf_clear(void)
{
memset(UART_RX_BUF,0,sizeof(UART_RX_BUF));
UART_RX_STA = 0;
send_flag = 0;
data_cnt = 0;
}
main.h
#include <rtthread.h>
#include <stdio.h>
#include <string.h>
#include "drv_common.h"
#include "stm32f4xx_hal.h"
#include "tim.h"
#include "it.h"
#include "iouart.h"
main.c
#include "main.h"
int main(void)
{
MX_GPIO_Init();
MX_TIM12_Init();
MX_TIM13_Init();
MX_TIM14_Init();
uart_transmit_str("for test...");
while (1){
if(send_flag){
// uart_transmit_buf(UART_RX_BUF);
rt_kprintf("%s\r\n",UART_RX_BUF);
buf_clear();
}
return RT_EOK;
}
中断部分在实际应用时因为rt-thread studio有设备驱动的回调函数,就懒省事直接写了中断服务函数
void EXTI1_IRQHandler(void)
{
rt_interrupt_enter();
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
rt_interrupt_leave();
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_1){
if(!IOUART_RD_RX){
if(recvStat == UART_STOP_BIT){
recvStat = UART_START_BIT;
UART_RX_END = 1;
HAL_TIM_Base_Stop_IT(&htim14);
__HAL_TIM_SET_COUNTER(&htim14,0);
HAL_TIM_Base_Start_IT(&htim13);
}
}
}
__HAL_GPIO_EXTI_CLEAR_FLAG(EXTI_LINE_1);
}
void TIM8_UP_TIM13_IRQHandler(void)
{
if (__HAL_TIM_GET_FLAG(&htim13, TIM_FLAG_UPDATE) != RESET){
if (__HAL_TIM_GET_IT_SOURCE(&htim13, TIM_IT_UPDATE) != RESET){
__HAL_TIM_CLEAR_IT(&htim13, TIM_IT_UPDATE);
recvStat++;
if(recvStat == UART_STOP_BIT){
UART_RX_END = 0;
HAL_TIM_Base_Stop_IT(&htim13);
__HAL_TIM_SET_COUNTER(&htim13,0);
// delay_us(7);
UART_RX_BUF[UART_RX_STA] = recvData;
recvData = 0;
UART_RX_STA++;
if(UART_RX_STA > (UART_REC_LEN - 1))
UART_RX_STA = 0;
HAL_TIM_Base_Start_IT(&htim14);
}else{
if(IOUART_RD_RX)
recvData |= 1 << (recvStat - 1);
else
recvData &= ~(1 << (recvStat - 1));
}
}
}
HAL_TIM_IRQHandler(&htim13);
}
void TIM8_TRG_COM_TIM14_IRQHandler(void)
{
if (__HAL_TIM_GET_FLAG(&htim14, TIM_FLAG_UPDATE) != RESET){
if (__HAL_TIM_GET_IT_SOURCE(&htim14, TIM_IT_UPDATE) != RESET){
__HAL_TIM_CLEAR_IT(&htim14, TIM_IT_UPDATE);
if((recvStat == UART_STOP_BIT) && IOUART_RD_RX && !UART_RX_END){
cnt++;
if(cnt > 10){
cnt = 0;
send_flag = 1;
HAL_TIM_Base_Stop_IT(&htim14);
__HAL_TIM_SET_COUNTER(&htim14,0);
}
}
}
}
HAL_TIM_IRQHandler(&htim14);
}
模拟串口发送字节里调用了失能中断和使能中断,避免在发送数据时被其他中断打断造成乱码,或者把该线程优先级调高,可能都会有bug
void iouart_transmit_byte(uint8_t cmd)
{
__disable_irq();
iouart_start();
delay_us(delay_time);
for(uint8_t i = 0; i < 8 ; i++){
if(cmd & (0x01 << i)){
IOUART_SET_TX(1);
}else{
IOUART_SET_TX(0);
}
delay_us(delay_time);
}
iouart_stop();
delay_us(delay_time);
__enable_irq();
}