【STM32H7教程】第30章 STM32H7的USART应用之八个串口FIFO实现

发布者:as233632621最新更新时间:2019-08-26 来源: eefocus关键字:STM32H7  USART应用  串口  FIFO 手机看文章 扫描二维码
随时随地手机看文章

30.1 初学者重要提示


学习本章节前,务必优先学习第29章。


串口FIFO的实现跟前面章节按键FIFO的机制是一样的。


本章节比较重要,因为后面的ESP8266,GPS,RS485,GPRS等试验都是建立在这个驱动的基础上实现。


大家自己做的板子,测试串口收发是乱码的话,重点看stm32h7xx_hal_conf.h文件中的HSE_VALUE的大小跟板子上实际晶振大小是否一致,然后再看PLL配置。


CH340/CH341的USB转串口Windows驱动程序的安装包,支持32/64位 Windows 10/8.1/8/7。http://forum.armfly.com/forum.php?mod=viewthread&tid=32826 。


30.2 硬件设计


STM32H743XIH6最多可以支持8个独立的串口。其中串口4和串口5和SDIO的GPIO是共用的,也就是说,如果要用到SD卡,那么串口4和串口5将不能使用。串口7和SPI3共用,串口8和RGB硬件接口共用。串口功能可以分配到不同的GPIO。我们常用的引脚分配如下:


串口USART1  TX = PA9,   RX = PA10


串口USART2  TX = PA2,   RX = PA3


串口USART3  TX = PB10,  RX = PB11


串口UART4   TX = PC10,  RX = PC11 (和SDIO共用)


串口UART5   TX = PC12,  RX = PD2  (和SDIO共用)


串口USART6  TX = PG14,  RX = PC7  


串口UART7   TX = PB4,   RX = PB3  (和SPI1/3共用)


串口UART8   TX = PJ8,   RX =PJ9   (和RGB硬件接口共用)


STM32-V7开发板使用了4个串口设备。


  串口1用于RS232接口,很多例子的pritnf结果就是输出到串口1

  串口2用于GPS

  串口3用于RS485接口

  串口6 用于TTL串口插座,板子上有GPRS插座和串口WIFI插座。

下面是RS232的原理图:


关于232的PHY芯片SP3232E要注意以下几个问题:


  SP3232E的作用是TTL电平转RS232电平。

  电阻R130的作用是避免CPU复位期间,TX为高阻时串口线上出现异常数据。

  检测SP3232E的好坏可以采用回环的方式,即短接T1OUT和R1IN,对应到DB9插座上就是短接引脚2和引脚3。


实际效果如下:

通过这种方式,可以在应用程序中通过串口发送几个字符,查看是否可以正确接收来判断232 PHY芯片是否有问题。


  由于这里是TTL转RS232,如果电脑端自带DB9串口,可以找根交叉线直接接上。如果电脑端没有,就需要用RS232转USB的串口线。这里要注意是RS232转USB,不是TTL转USB。像我们用的CH340就是RS232转USB芯片。

  检测串口线的好坏跟板子上的232 PHY一样,将电脑端的串口助手打开,串口线接到电脑端并短接串口线的2脚和3脚,然后使用串口助手进行自收发测试即可。

30.3 串口FIFO驱动设计

30.3.1 串口FIFO框架

为了方便大家理解,先来看下串口FIFO的实现框图:


 

  第1阶段,初始化:


通过函数bsp_InitUart初始化串口结构体,串口硬件参数。

  第2阶段,串口中断服务程序:


  接收中断是一直开启的。

  做了发送空中断和发送完成中断的消息处理。

  第3阶段,串口数据的收发:


  串口发送函数会开启发送空中断。

  串口接收中断接收到函数后,可以使用函数comGetChar获取数据。

30.3.2 串口FIFO之相关的变量定义

串口驱动的核心文件为:bsp_uart_fifo.c, bsp_uart_fifo.h。


这里面包括有串口硬件的配置函数、中断处理函数,以及串口的读写接口函数。还有ptinft函数的实现。


每个串口都有2个FIFO缓冲区,一个是用于发送数据的TX_FIFO,一个用于保存接收数据的RX_FIFO。


我们来看下这个FIFO的定义,在bsp_uart_fifo.h文件。


/* 定义串口波特率和FIFO缓冲区大小,分为发送缓冲区和接收缓冲区, 支持全双工 */

#if UART1_FIFO_EN == 1

#define UART1_BAUD 115200

#define UART1_TX_BUF_SIZE 1*1024

#define UART1_RX_BUF_SIZE 1*1024

#endif

 

/* 串口设备结构体 */

typedef struct

{

USART_TypeDef *uart; /* STM32内部串口设备指针 */

uint8_t *pTxBuf; /* 发送缓冲区 */

uint8_t *pRxBuf; /* 接收缓冲区 */

uint16_t usTxBufSize; /* 发送缓冲区大小 */

uint16_t usRxBufSize; /* 接收缓冲区大小 */

__IO uint16_t usTxWrite; /* 发送缓冲区写指针 */

__IO uint16_t usTxRead; /* 发送缓冲区读指针 */

__IO uint16_t usTxCount; /* 等待发送的数据个数 */

 

__IO uint16_t usRxWrite; /* 接收缓冲区写指针 */

__IO uint16_t usRxRead; /* 接收缓冲区读指针 */

__IO uint16_t usRxCount; /* 还未读取的新数据个数 */

 

void (*SendBefor)(void); /* 开始发送之前的回调函数指针(主要用于RS485切换到发送模式) */

void (*SendOver)(void); /* 发送完毕的回调函数指针(主要用于RS485将发送模式切换为接收模式) */

void (*ReciveNew)(uint8_t _byte); /* 串口收到数据的回调函数指针 */

uint8_t Sending; /* 正在发送中 */

}UART_T;

bsp_uart_fifo.c文件定义变量。我们以串口1为例,其他的串口都是一样的代码。


/* 定义每个串口结构体变量 */

#if UART1_FIFO_EN == 1

static UART_T g_tUart1;

static uint8_t g_TxBuf1[UART1_TX_BUF_SIZE]; /* 发送缓冲区 */

static uint8_t g_RxBuf1[UART1_RX_BUF_SIZE]; /* 接收缓冲区 */

#endif

关于FIFO的机制,我们在按键FIFO驱动已经做过详细的介绍,这个地方就不赘述了。每个串口有两个FIFO缓冲区,每个FIFO对应一个写指针和一个读指针。这个结构中还有三个回调函数。回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。


30.3.3 串口FIFO初始化

串口的初始化代码如下;


/*

*********************************************************************************************************

* 函 数 名: bsp_InitUart

* 功能说明: 初始化串口硬件,并对全局变量赋初值.

* 形    参: 无

* 返 回 值: 无

*********************************************************************************************************

*/

void bsp_InitUart(void)

{

UartVarInit(); /* 必须先初始化全局变量,再配置硬件 */

 

InitHardUart();    /* 配置串口的硬件参数(波特率等) */

 

RS485_InitTXE(); /* 配置RS485芯片的发送使能硬件,配置为推挽输出 */

}

 


下面将初始化代码实现的功能依次为大家做个说明。


  函数UartVarInit

这个函数实现的功能比较好理解,主要是串口设备结构体变量的初始化,代码如下:


/*

*********************************************************************************************************

* 函 数 名: UartVarInit

* 功能说明: 初始化串口相关的变量

* 形    参: 无

* 返 回 值: 无

*********************************************************************************************************

*/

static void UartVarInit(void)

{

#if UART1_FIFO_EN == 1

g_tUart1.uart = USART1; /* STM32 串口设备 */

g_tUart1.pTxBuf = g_TxBuf1; /* 发送缓冲区指针 */

g_tUart1.pRxBuf = g_RxBuf1; /* 接收缓冲区指针 */

g_tUart1.usTxBufSize = UART1_TX_BUF_SIZE;      /* 发送缓冲区大小 */

g_tUart1.usRxBufSize = UART1_RX_BUF_SIZE;      /* 接收缓冲区大小 */

g_tUart1.usTxWrite = 0; /* 发送FIFO写索引 */

g_tUart1.usTxRead = 0; /* 发送FIFO读索引 */

g_tUart1.usRxWrite = 0; /* 接收FIFO写索引 */

g_tUart1.usRxRead = 0; /* 接收FIFO读索引 */

g_tUart1.usRxCount = 0; /* 接收到的新数据个数 */

g_tUart1.usTxCount = 0; /* 待发送的数据个数 */

g_tUart1.SendBefor = 0; /* 发送数据前的回调函数 */

g_tUart1.SendOver = 0; /* 发送完毕后的回调函数 */

g_tUart1.ReciveNew = 0; /* 接收到新数据后的回调函数 */

g_tUart1.Sending = 0; /* 正在发送中标志 */

#endif

    /* 串口2-8的初始化省略未写 */

}

  函数InitHardUart

此函数主要用于串口的GPIO,中断和相关参数的配置。


1. /* 串口1的GPIO  PA9, PA10   RS323 DB9接口 */

2. #define USART1_CLK_ENABLE()              __HAL_RCC_USART1_CLK_ENABLE()

3.

4. #define USART1_TX_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOA_CLK_ENABLE()

5. #define USART1_TX_GPIO_PORT              GPIOA

6. #define USART1_TX_PIN                    GPIO_PIN_9

7. #define USART1_TX_AF                     GPIO_AF7_USART1

8.

9. #define USART1_RX_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOA_CLK_ENABLE()

10. #define USART1_RX_GPIO_PORT              GPIOA

11. #define USART1_RX_PIN                    GPIO_PIN_10

12. #define USART1_RX_AF                     GPIO_AF7_USART1

13.

14. /* 串口2-8的引脚和时钟宏定义未写 */

15.

16. /*

17. ******************************************************************************************************

18. * 函 数 名: InitHardUart

19. * 功能说明: 配置串口的硬件参数(波特率,数据位,停止位,起始位,校验位,中断使能)适合于STM32-H7开

20. *              发板

21. * 形    参: 无

22. * 返 回 值: 无

23. ******************************************************************************************************

24. */

25. static void InitHardUart(void)

26. {

27. GPIO_InitTypeDef  GPIO_InitStruct;

28. RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit;

29.

30. /* 

31.        下面这个配置可以注释掉,预留下来是为了方便以后选择其它时钟使用 

32.        默认情况下,USART1和USART6选择的PCLK2,时钟100MHz。

33.        USART2,USART3,UART4,UART5,UART6,UART7和UART8选择的时钟是PLCK1,时钟100MHz。

34.     */

35. RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART16;

36. RCC_PeriphClkInit.Usart16ClockSelection = RCC_USART16CLKSOURCE_D2PCLK2;

37. HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit);

38.

39. #if UART1_FIFO_EN == 1 /* 串口1 */

40. /* 使能 GPIO TX/RX 时钟 */

41. USART1_TX_GPIO_CLK_ENABLE();

42. USART1_RX_GPIO_CLK_ENABLE();

43.

44. /* 使能 USARTx 时钟 */

45. USART1_CLK_ENABLE();

46.

47. /* 配置TX引脚 */

48. GPIO_InitStruct.Pin       = USART1_TX_PIN;

49. GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;

50. GPIO_InitStruct.Pull      = GPIO_PULLUP;

51. GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;

52. GPIO_InitStruct.Alternate = USART1_TX_AF;

53. HAL_GPIO_Init(USART1_TX_GPIO_PORT, &GPIO_InitStruct);

54.

55. /* 配置RX引脚 */

56. GPIO_InitStruct.Pin = USART1_RX_PIN;

57. GPIO_InitStruct.Alternate = USART1_RX_AF;

58. HAL_GPIO_Init(USART1_RX_GPIO_PORT, &GPIO_InitStruct);

59.

60. /* 配置NVIC the NVIC for UART */   

61. HAL_NVIC_SetPriority(USART1_IRQn, 0, 1);

62. HAL_NVIC_EnableIRQ(USART1_IRQn);

63.   

64. /* 配置波特率、奇偶校验 */

65. bsp_SetUartParam(USART1,  UART1_BAUD, UART_PARITY_NONE, UART_MODE_TX_RX);

66.

67. SET_BIT(USART1->ICR, USART_ICR_TCCF);   /* 清除TC发送完成标志 */

68. SET_BIT(USART1->RQR, USART_RQR_RXFRQ);  /* 清除RXNE接收标志 */

69. // USART_CR1_PEIE | USART_CR1_RXNEIE

70. SET_BIT(USART1->CR1, USART_CR1_RXNEIE); /* 使能PE. RX接受中断 */

71. #endif

72. /* 串口2-8的初始化省略未写 */

73. }

  第2-12行,以宏定义的方式设置串口1-8的GPIO时钟、引脚和串口时钟,方便修改。

  第35-37行,这里的配置可以注释掉,预留下来仅仅是为了方便以后选择其它时钟使用。默认情况下,USART1和USART6选择的PCLK2,时钟100MHz。USART2,USART3,UART4,UART5,UART6,UART7和UART8选择的时钟是PLCK1,时钟100MHz。

  第61-62行,配置串口中断优先级并使能串口中断,用户可以根据实际工程修改优先级大小。

  第65行,配置串口的基本参数,具体配置在函数里面有注释。

/*

*********************************************************************************************************

* 函 数 名: bsp_SetUartParam

* 功能说明: 配置串口的硬件参数(波特率,数据位,停止位,起始位,校验位,中断使能)适合于STM32- H7开发板

* 形    参: Instance   USART_TypeDef类型结构体

*             BaudRate   波特率

*             Parity     校验类型,奇校验或者偶校验

*             Mode       发送和接收模式使能

* 返 回 值: 无

*********************************************************************************************************

*/

void bsp_SetUartParam(USART_TypeDef *Instance,  uint32_t BaudRate, uint32_t Parity, uint32_t Mode)

{

UART_HandleTypeDef UartHandle;

/*##-1- 配置串口硬件参数 ######################################*/

/* 异步串口模式 (UART Mode) */

/* 配置如下:

  - 字长    = 8 位

  - 停止位  = 1 个停止位

  - 校验    = 参数Parity

  - 波特率  = 参数BaudRate

  - 硬件流控制关闭 (RTS and CTS signals) */

 

UartHandle.Instance        = Instance;

 

UartHandle.Init.BaudRate   = BaudRate;

UartHandle.Init.WordLength = UART_WORDLENGTH_8B;

UartHandle.Init.StopBits   = UART_STOPBITS_1;

UartHandle.Init.Parity     = Parity;

UartHandle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;

UartHandle.Init.Mode       = Mode;

UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;

UartHandle.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;

[1] [2] [3] [4] [5]
关键字:STM32H7  USART应用  串口  FIFO 引用地址:【STM32H7教程】第30章 STM32H7的USART应用之八个串口FIFO实现

上一篇:【STM32H7教程】第31章 STM32H7的USART应用之RS485
下一篇:【STM32H7教程】第29章 STM32H7的USART串口基础知识和HAL库API

推荐阅读最新更新时间:2024-11-15 04:41

STM32高级开发(12)-在GCC中使用printf打印串口数据
在大家使用keil或是iar开发stm32等arm芯片的时候,想来最不陌生的就是使用print通过串口输出一些数据,用来调试或是其他作用。但是要明确的是由于keil iar gcc 他们使用的标准C语言库虽然都遵循一个标准,但他们底层的函数实现方式都是不同的,那么在GCC中我们能否像在keil中一样重映射print的输出流到串口上呢?答案是肯定的。 keil中的重映射方式及原理 /* * libc_printf.c * * Created on: Dec 26, 2015 * Author: Yang * * 使用标准C库时,重映射printf等输出函数的文件 * 添加在工程内即可生效(切勿选择semi
[单片机]
ZigBee基础实验(七)--AD采集温度串口显示
1、ADC 简介   ADC 支持多达14 位的模拟数字转换,具有多达12 位有效数字位。它包括一个模拟多路转换器,具有多达8 个各自可配置的通道;以及一个参考电压发生器。转换结果通过DMA 写入存储器。还具有若干运行模式。   ADC 的主要特性如下: ● 可选的抽取率,这也设置了分辨率(7 到12 位) ● 8 个独立的输入通道,可接受单端或差分信号 ● 参考电压可选为内部单端、外部单端、外部差分或AVDD5 ● 产生中断请求 ● 转换结束时的DMA 触发 ● 温度传感器输入 ● 电池测量功能 2、ADC 操作   本节描述了ADC 的一般安装和操作,并描述了CPU 存取的ADC 控制和状态寄存器的使用。 2.1
[单片机]
ZigBee基础实验(七)--AD采集温度<font color='red'>串口</font>显示
三 ARM9(S3C2440)的串口UART——程序实例讲解
串口通信程序编写步骤 UART通信程序可以采用查询、中断和DMA模式。我们通过使用较多的中断方式来介UART通信程序的编写。简单做法是,UART通信程序的编写参照例子程序。 选通道,通过函数Uart_Select();选UART0~UART2; 选波特率和波特率发生器时钟,选波特率通过函数Uart_Pclk_En(int ch, int baud)或Uart_Pclk_En(int ch, int baud)来进行。时钟选UCLK ,rUCON0|=0x400;时钟选PCLK ,rUCON0&=0x3ff。 通信协议(rULCON0)设定,如果正常通信,一位停止位,8位数据位,无奇偶效验: rULCON0=(0 6
[单片机]
STM32串口的设置和库函数的介绍
串口设置的一般步骤可以总结为如下几个: 1) 串口时钟使能, GPIO时钟使能 2) 串口复位 3)GPIO 端口模式设置 4) 串口参数初始化 5) 开启中断并且初始化 NVIC(如果需要开启中断才这个步骤) (如果需要开启中断才这个步骤) 6) 使能串口 使能串口 7) 编写中断处理函数 下面,我们就简单介绍这几个与串口基本配置直接相关的固件库函数。这些函数和 定义主要分布在 stm32f10x_usart.h ,stm32f10x_usart.c 文件中。 1.串口时钟使能。串口是挂载在APB2上的,所以使能函数为: RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1) 2.串
[单片机]
STM32单片机(3) 串口中断通信
注:使用普中科技开发板测试时,需要拔掉Boot1短接帽 两根下载线也要拿掉,重启 /******************************************************************************* * * 软件功能: 串口实验(软件延时方式) * *******************************************************************************/ #include stm32f10x.h #include string.h #include delay.h u8 uart1_buf ; int count=0
[单片机]
lesson7 串口通信
1、异步通信是指通信的发送与接收设备使用各自的时钟控制数据的发送和接收过程。为使双方的收发协调,要求发送和接收设备的时钟尽可能一致。异步通信是以字符(构成的帧)为单位进行传输,字符与字符之间的间隙(时间间隔)是任意的,但每个字符中的各位是以固定的时间传送的,即字符之间不一定有“位间隔”的整数倍的关系,但同一字符内的各位之间的距离均为“位间隔”的整数倍。异步通信的特点:不要求收发双方时钟的严格一致,实现容易,设备开销较小,但每个字符要附加2~3位用于起止位,各帧之间还有间隔,因此传输效率不高。 2、同步通信时要建立发送方时钟对接收方时钟的直接控制,使双方达到完全同步。此时,传输数据的位之间的距离均为“位间隔”的整数倍,同时传送的
[单片机]
lesson7 <font color='red'>串口</font>通信
mini2440 uart串口实验(fifo模式+中断)
这次是S3C2440上面的uart0的FIFO模式的实验,程序设置串口0的输入fifo中包含的数据个数在从小于16字节的状态变换为大于等于16字节的状态的瞬间触发一个脉冲中断,在这个中断中,把输入fifo 中的数据全部写入到输出fifo中,在输出fifo 从非空状态变换成空的状态的瞬间会触发一个脉冲中断,在中断中我让灯闪一下,实验的正确现象是从超级终端往2440的串口0发数据,每发16个字节的数据,串口就会把这16个字节全部打印出来,同时由于输出fifo变空,会触发灯闪一下,经过测试,实验现象和上面说的是一致的。要注意在往utxh0寄存器写数据的时候要先检查输出fifo是不是已经满了,如果已经满了就要等待,否则会造成输出fifo对
[单片机]
Keil软件的串口通讯调试
可以利用KEIL软件模拟单片机的串口, 虚拟串口驱动程序(Virtual Serial Ports Driver,VSPD)能够创建数对“虚拟”的串行端口,每对串口虚拟互联,在一般程序看来,这些“虚拟”的串行端口跟实体的串行端口完全一致,因此,在单台计算机上运行VSPD即可达到串口扩展的目的。本调试方法的基本流程如下: ① 运行VSPD实现计算机串口的扩展和互联; ② 在Keil中运行通信程序,对单片机的UART进行仿真,并将之与计算机的某一个虚拟串口绑定,即用计算机的串口来模拟单片机的UART; ③ 打开串口调试助手,选择与②中互联的虚拟串口,进行数据收发从而实现通信调试。 在KEIL里将虚拟串口COM3绑定为单片机的
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved