本帖最后由 qinyunti 于 2025-1-25 21:09 编辑

【电子DIY】DIY行车记录仪为游戏机之主控软件开发(2)串口驱动
代码见:https://github.com/qinyunti/py32f403-nes.git

一.前言

硬件上我们设计有两路串口,一路用于连接蓝牙模块接收无线手柄的按键信息,一路用于调试shell交互和传输文件等。这一篇来分享串口测试,以及封装串口读写驱动接口。

204551c21rfrt1zt8qw71f

204551cc5jh528lx5zg0td

二.串口驱动

py32f403_hal_conf.h中

取消注释

#define HAL_UART_MODULE_ENABLED 使能串口模块驱动库。

添加uart.c和uart.h文件

Uart.h 定义接口

#ifndef UART_H

#define UART_H

#ifdef __cplusplus

extern "C" {

#endif


#include <stdint.h>

void uart_init(int id, uint32_t baud);

uint32_t uart_send(int id, uint8_t* buffer, uint32_t len);

uint32_t uart_read(int id, uint8_t* buffer, uint32_t len);

#ifdef __cplusplus

}

#endif

#endif

Uart.c中实现

#include "uart.h"

#include "fifo.h"

#include "py32f4xx_hal.h"

#include "py32f403_ll_usart.h"

#define CriticalAlloc()

#define EnterCritical()        __disable_irq()

#define ExitCritical()  __enable_irq()

uint8_t s_uart_rx_buffer[2][128];

static fifo_st s_uart_fifo_dev[2]=

{

        {

         .in = 0,

         .len = 0,

         .out = 0,

         .buffer = s_uart_rx_buffer[0],

         .buffer_len = sizeof(s_uart_rx_buffer[0]),

        },

        {

         .in = 0,

         .len = 0,

         .out = 0,

         .buffer = s_uart_rx_buffer[1],

         .buffer_len = sizeof(s_uart_rx_buffer[1]),

        }

};

void uart_rx_cb(int id, uint8_t* buff, uint32_t len)

{

        fifo_in(&(s_uart_fifo_dev[id]), buff, len);

}

void USART1_IRQHandler(void)

{

        uint8_t ch;

        ch = LL_USART_ReceiveData8(USART1);

        uart_rx_cb(0, &ch, 1);

}

void USART3_IRQHandler(void)

{

        uint8_t ch;

        ch = LL_USART_ReceiveData8(USART3);

        uart_rx_cb(1, &ch, 1);

}

void uart_init(int id, uint32_t baud)

{

        if(id == 0){

        /* PA9  USART1_TX AF2

         * PA10 USART1_RX AF2

         */

                UART_HandleTypeDef huart;

                GPIO_InitTypeDef  GPIO_InitStruct;

                __HAL_RCC_GPIOA_CLK_ENABLE();         

                __HAL_RCC_USART1_CLK_ENABLE();


                GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;

                GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;              

                GPIO_InitStruct.Pull = GPIO_PULLUP;                    

                GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;   

                GPIO_InitStruct.Alternate = GPIO_AF2_USART1;   

                HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);  


                huart.Instance = USART1;

                huart.Init.BaudRate = baud;

                huart.Init.WordLength = UART_WORDLENGTH_8B;

                huart.Init.StopBits = UART_STOPBITS_1;

                huart.Init.Parity = UART_PARITY_NONE;

                huart.Init.HwFlowCtl = UART_HWCONTROL_NONE;

                huart.Init.Mode = UART_MODE_TX_RX;

                huart.Init.OverSampling = UART_OVERSAMPLING_8;

                HAL_UART_Init(&huart);


                __HAL_UART_ENABLE_IT(&huart, UART_IT_RXNE);

                HAL_NVIC_SetPriority(USART1_IRQn,1,1);

                HAL_NVIC_EnableIRQ(USART1_IRQn);

        }else if(id == 1){

        /* PB10 USART3_TX AF2

         * PB11 USART3_RX AF2

         */

                UART_HandleTypeDef huart;

                GPIO_InitTypeDef  GPIO_InitStruct;

                __HAL_RCC_GPIOB_CLK_ENABLE();         

                __HAL_RCC_USART3_CLK_ENABLE();


                GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_11;

                GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;              

                GPIO_InitStruct.Pull = GPIO_PULLUP;                    

                GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;   

                GPIO_InitStruct.Alternate = GPIO_AF2_USART3;   

                HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);  


                huart.Instance = USART3;

                huart.Init.BaudRate = baud;

                huart.Init.WordLength = UART_WORDLENGTH_8B;

                huart.Init.StopBits = UART_STOPBITS_1;

                huart.Init.Parity = UART_PARITY_NONE;

                huart.Init.HwFlowCtl = UART_HWCONTROL_NONE;

                huart.Init.Mode = UART_MODE_TX_RX;

                huart.Init.OverSampling = UART_OVERSAMPLING_8;

                HAL_UART_Init(&huart);


                __HAL_UART_ENABLE_IT(&huart, UART_IT_RXNE);

                HAL_NVIC_SetPriority(USART3_IRQn,1,1);

                HAL_NVIC_EnableIRQ(USART3_IRQn);

        }

}

uint32_t uart_send(int id, uint8_t* buffer, uint32_t len)

{

          if(id == 0){

                        for(uint32_t i=0;i<len;i++)

                        {

                                while(LL_USART_IsActiveFlag_TXE(USART1) == 0);

                                LL_USART_TransmitData8(USART1,buffer);

                        }

                }else if(id == 1){

                        for(uint32_t i=0;i<len;i++)

                        {

                                while(LL_USART_IsActiveFlag_TXE(USART3) == 0);

                                LL_USART_TransmitData8(USART3,buffer);

                        }

                }

    return len;

}

uint32_t uart_read(int id, uint8_t* buffer, uint32_t len)

{

    uint32_t rlen;

    CriticalAlloc();

    EnterCritical();

    rlen = fifo_out(&(s_uart_fifo_dev[id]), buffer, len);

    ExitCritical();

    return rlen;

}

主要逻辑是串口中断中将接收的数据写入FIFO,uart_read读数据时即从FIFO读数据即可。

void USART1_IRQHandler(void)

{

        uint8_t ch;

        ch = LL_USART_ReceiveData8(USART1);

        uart_rx_cb(0, &ch, 1);

}

发送则简单使用查询发送,实际发送也可以使用FIFO+中断过方式。

依赖fifo.c/h实现见公众号文章

https://mp.weixin.qq.com/s/MvL9eDesyuxD60fnbl1nag?token=1631959641&lang=zh_CN

三.测试

main.c中

#include "uart.h"

uint8_t rx_buffer[64];

int main(void)

{

        HAL_Init();

        clk_init();

        HAL_Init();

        clk_out();


        uart_init(0, 115200);

        uart_init(1, 115200);        

        uart_send(1,(uint8_t*)"Hello World\r\n",strlen("Hello World\r\n"));

        while(1){

                uint32_t len = uart_read(1, rx_buffer, sizeof(rx_buffer));

                if(len > 0){

                        uart_send(1,rx_buffer,len);

                }

        }

}

将uart_xxx接口的id改为0测试另一路串口。

可以看到串口打印HelloWorld,然后收到内容原样返回

204551zq7nioqvf3igvo44

四.总结

借助以前积累的FIFO的串口驱动实现,可以很快的移植适配,实现串口的收发。为后面的开发做准备。