stm32f4 IO模拟uart通信

最近工作中需要用到单片机与外接模块通信,因为串口都被占用,所以需要使用普通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();
}

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值