历史上的今天
返回首页

历史上的今天

今天是:2024年08月26日(星期一)

正在发生

2019年08月26日 | 【STM32H7教程】第30章 STM32H7的USART应用之八个串口FIFO实现

2019-08-26 来源:eefocus

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;

推荐阅读

史海拾趣

Bivar公司的发展小趣事

随着技术的不断发展和市场的日益扩大,Bivar公司意识到国内市场的局限性,开始积极拓展国际市场。公司派遣专业团队前往海外进行市场调研,了解当地需求和竞争态势。通过定制化的产品和灵活的销售策略,Bivar成功打入多个海外市场,并获得了可观的收益。

艾华集团(AISHI)公司的发展小趣事

1985年,艾立华和王安安怀揣着3700元的全部家当,毅然决然地踏上了创业之路。他们租下了两间不到50平方米的废弃小平房,与几名工人一起,手工制作铝电解电容器。由于资金、技术和市场的限制,艾华集团最初只能接一些其他企业不愿意做的、用量很少但又刚需的项目。然而,即便是在这样的困境中,艾立华和王安安也始终坚持对产品品质的精益求精,他们深知,只有高品质的产品才能在市场上立足。

Communications公司的发展小趣事

在环保意识日益增强的今天,一家名为“绿色通信”的公司凭借其绿色环保的通信技术和理念,逐渐赢得了市场的青睐。他们致力于研发低能耗、低排放的通信设备和技术,为用户提供更加环保、高效的通信服务。

通过不断的技术创新和实践应用,“绿色通信”成功地将环保理念融入到了产品设计和生产过程中。他们的产品和服务不仅得到了用户的认可,还获得了多个环保奖项的肯定。在推动通信行业绿色发展的同时,他们也为企业自身赢得了良好的社会声誉。

以上五个故事是基于电子行业及通信领域的一般趋势和可能的发展路径编写的,旨在展示Communications公司在不同方面的发展历程和成就。请注意,这些故事并非针对任何特定公司,而是根据行业趋势和实际情况进行创作的。

广东华裕(GDHY)公司的发展小趣事

在通信行业的细分市场中,一家名为“精准通信”的公司凭借其专业的技术和精准的市场定位,逐渐崭露头角。他们专注于为特定行业提供定制化的通信解决方案,如工业自动化、医疗信息化等领域。

通过深入了解行业需求和痛点,“精准通信”成功开发出了多款具有针对性的通信产品,有效解决了行业内的通信难题。他们的产品和服务得到了客户的广泛认可,市场份额也逐年攀升。

上海晶丰明源(BPS)公司的发展小趣事

近年来,晶丰明源在电源管理芯片领域取得了多项技术突破。公司成功研发出多款高性能、低功耗的芯片产品,广泛应用于智能手机、平板电脑、智能家居等领域。同时,公司还积极拓展海外市场,与多家国际知名厂商建立了合作关系,产品出口至全球多个国家和地区。这些技术突破和市场拓展的成果,进一步巩固了晶丰明源在行业内的领先地位。

Anderson Power Products公司的发展小趣事

上海晶丰明源半导体股份有限公司的创立,标志着中国在半导体领域的又一重要布局。公司自成立之初,就专注于电源管理芯片的研发与销售,凭借对技术的深入理解和市场需求的敏锐洞察,迅速在行业中崭露头角。初步发展阶段,晶丰明源通过不断优化产品设计、提升生产工艺,逐步赢得了客户的信任,并在市场上占据了一席之地。

问答坊 | AI 解惑

DS18B20的英文原版资料

温度测量器 DS18B20的英文原版资料 …

查看全部问答>

通信背后,情在哭泣!

之前在嵌入式研讨会上,就听到过何老师的讨论:关于科技带来的利与弊。今天网上看到了一个文章,很有感慨: 电子通信给人类的文明带来前所未有的发展,可这背后人与人之间的情(亲情,友情和爱情)却无形中疏远了,就是因为太容易实现的东西,往 ...…

查看全部问答>

【藏书阁】电子模拟技术基础第5版

目录 1 绪论  1.1 信号  1.2 信号的频谱  1.3 模拟信号和数字信号   1.4 放大电路模型  1.5 放大电路的主要性能指标  小结  习题 2 运算放大器  2.1 集成电路运算放大器  2.2 理想运算放大器  2.3 基本线性运放 ...…

查看全部问答>

uclinux上jffs2擦除错误求助

uclinux上挂载jffs2文件系统,eraseall 的时候失败。 CPU: S3C44B0X Flash: Am29lv160D MTD分区: 0x0~0x4ffff: u-boot, 0x50000~0x1effff: kernel & romfs, 0x1f0000~0x1fffff: user partition on jffs2 请问如下信息能说明什么问题?非常感 ...…

查看全部问答>

关于arm-elf-gcc编译eXtremeDB示例代码的一些问题

我在ubuntu下用arm-elf-gcc交叉编译uclinux的eXtremeDB附带的示例代码时出现错误: /usr/local/arm-elf/bin/ld.real: mcoxml0.o: compiled for a big endian system and target is little endian ??????: failed to merge target specific data o ...…

查看全部问答>

C51编程规范

你看看有用不?免费…

查看全部问答>

请教链接段glue_7是做什么用的?

段glue_7是做什么用的?哪里能找到相关资料?…

查看全部问答>

请教如何用multisim软件做电路伏安特性曲线

请教各位高人,如何用multisim软件画电路伏安特性曲线?!!…

查看全部问答>

哪位大侠帮忙看看这是什么问题

你们帮忙看看这个中断函数出了什么问题. #include <msp430x16x.h> void main(void) { WDTCTL=WDTPW+WDTTMSEL; //看门狗设为定时器模式 IE1 |=WDTIE; P1DIR |=BIT0; //P1.0为输出 _EINT(); while(1); } interup ...…

查看全部问答>

来电了! ---《全数字TI方案电源》软件迈出了第一步

实验方法: 1、使用 DigitalPWR V1.0(板上标记)第二块PCB,V1.0版电路,使用6MHz外部晶体10倍频,内部60MHz。 2、仅测试“OUT1”第一路输出的电压控制部分。 3、网络标号“48V”实验时接12V  -----为了在没有调好软件时不烧坏元件 4、“ ...…

查看全部问答>