【电子DIY】DIY行车记录仪为游戏机之主控软件开发(2)串口驱动
代码见:https://github.com/qinyunti/py32f403-nes.git
一.前言
硬件上我们设计有两路串口,一路用于连接蓝牙模块接收无线手柄的按键信息,一路用于调试shell交互和传输文件等。这一篇来分享串口测试,以及封装串口读写驱动接口。
二.串口驱动
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,然后收到内容原样返回
四.总结
借助以前积累的FIFO的串口驱动实现,可以很快的移植适配,实现串口的收发。为后面的开发做准备。