【STM32F103ZET6开发板】第2-6讲:USART串口通信

【STM32F103ZET6开发板】第2-6讲:USART串口通信

首页模拟经营cts6游戏更新时间:2024-06-07

串口USART

实验目的实验内容硬件设计开发板串口硬件电路

IK-ZET6开发板上设计了USB转TTL电路,它的主要作用有2个:

  1. USB转串口通讯,通过USB数据线连接到计算机的USB口即可使用串口通信功能。
  2. 开发板供电通过USB可以为开发板供电(计算机USB可以提供500mA的电流)。

USB转TTL电路如下图所示,串口接收和发送的管脚上均连接了LED指示灯,收发数据时指示灯会闪烁,这样,更方便我们从硬件的角度观察串口有没有在进行数据收发。电路中的1000mA自恢复保险丝用于保护开发板板和计算机USB口。

图1:开发板USB转TTL电路

表1:串口电路引脚分配

USART

功能描述

引脚

说明

USART_TX

串口发送

PA9

独立gpio

USART_RX

串口接收

PA10

独立GPIO

STM32串行口简介

STM32F103ZET6微处理器有3组USART,2组UART。并且3组USART均带硬件流控。下表列举出各组串行口所占用MCU的引脚情况。

表2:STM32F103ZET6串行口相关引脚

序号

串行口

引脚名

对应IO口

功能描述

备注

1

USART1

USART1_RX

PA10

串口接收

APB2总线

2

USART1_TX

PA9

串口发送

3

USART1_CK

PA8

串口同步时钟线

4

USART1_RTS

PA12

串口硬件流控RTS

5

USART1_CTS

PA11

串口硬件流控CTS

6

USART2

USART2_RX

PA3

串口接收

APB1总线

7

USART2_TX

PA2

串口发送

8

USART2_CK

PA4

串口同步时钟线

9

USART2_RTS

PA1

串口硬件流控RTS

10

USART2_CTS

PA0

串口硬件流控CTS

11

USART3

USART3_RX

PB11

串口接收

APB1总线

12

USART3_TX

PB10

串口发送

13

USART3_CK

PB12

串口同步时钟线

14

USART3_RTS

PB14

串口硬件流控RTS

15

USART3_CTS

PB13

串口硬件流控CTS

16

UART4

UART4_RX

PC11

串口接收

APB1总线

17

UART4_TX

PC10

串口发送

18

UART5

UART5_RX

PD2

串口接收

APB1总线

19

UART5_TX

PC12

串口发送

STM32F103ZET6微处理器USART框图如下图所示,大致可分4个部分,MCU功能引脚是画原理图使用的芯片引脚,其它3个部分均在芯片内部集成,用户如需详细知晓其每一块的原理可参考数据手册研读。

图2:USART框图

软件设计USART寄存器汇集

STM32F103提供了7个用于操作USART的寄存器,如下表所示:

表3:USART相关寄存器

序号

寄存器名

读/写

功能描述

1

USART_SR

只读

状态寄存器。

2

USART_DR

读/写

数据寄存器。

3

USART_BRR

读/写

波特率寄存器。

4

USART_CR1

读/写

控制寄存器1。

5

USART_CR2

读/写

控制寄存器2。

6

USART_CR3

读/写

控制寄存器3。

7

USART_GTPR

读/写

保护时间和预分频寄存器。

每一种寄存器详细的描述在这里不做具体的介绍,大家可以参考目录:“第1部分:开发板硬件资料”--->“2 - 芯片资料”中“STM32英文参考手册_V15”或“STM32中文参考手册_V10”对应的USART章节的寄存器部分认真研读。

USART库函数汇集

官方提供的最终库函数版本是V3.5版本,该版本库函数提供了25个与USART操作有关的库函数,如下表所示:

表4:USART相关库函数汇集

序号

函数名

功能描述

1

USART_DeInit

将外设USARTx寄存器重设为缺省值。

2

USART_Init

根据USART_InitStruct中指定的参数初始化外设USARTx寄存器。

3

USART_StructInit

把USART_InitStruct中的每一个参数按缺省值填入。

4

USART_Cmd

使能或者失能USART外设。

5

USART_ITConfig

使能或者失能指定的USART中断。

6

USART_DMACmd

使能或者失能指定USART的 DMA请求。

7

USART_SetAddress

设置USART节点的地址。

8

USART_WakeUpConfig

选择USART的唤醒方式。

9

USART_ReceiverWakeUpCmd

检查USART是否处于静默模式。

10

USART_LINBreakDetectLengthConfig

设置USART LIN中断检测长度。

11

USART_LINCmd

使能或者失能USARTx的LIN模式。

12

USART_SendData

通过外设USARTx发送单个数据。

13

USART_ReceiveData

返回USARTx最近接收到的数据。

14

USART_SendBreak

发送中断字。

15

USART_SetGuardTime

设置指定的USART保护时间。

16

USART_SetPrescaler

设置USART时钟预分频。

17

USART_SmartCardCmd

使能或者失能指定USART的智能卡模式。

18

USART_SmartCardNackCmd

使能或者失能NACK传输。

19

USART_HalfDuplexCmd

使能或者失能USART半双工模式。

20

USART_IrDAConfig

设置USART IrDA模式。

21

USART_IrDACmd

使能或者失能USART IrDA模式。

22

USART_GetFlagStatus

检查指定的USART标志位设置与否。

23

USART_ClearFlag

清除USARTx的待处理标志位。

24

USART_GetITStatus

检查指定的USART中断发生与否。

25

USART_ClearITPendingBit

清除USARTx的中断待处理位。

每一种寄存器详细的描述在这里不一一进行介绍,大家可以参考目录:“第1部分:开发板硬件资料”--->“2 - 芯片资料”中“STM32固件库使用手册的中文翻译版”对应的USART章节的库函数部分认真研读。

USART配置过程

针对STM32F103的GPIO口为USART进行串口通信时,软件的配置过程如下:

图3:USART软件配置步骤

USART1串口收发实验工程需要用到的库文件

在使用库函数建“实验6-1:USART1串口收发数据”工程时,需要用到的c文件如下表所示。

表5:实验需要用到的C文件

序号

文件名

后缀

功能描述

1

stm32f10x_rcc

.c

复位与时钟控制器。

2

stm32f10x_gpio

.c

通用输入输出。

3

stm32f10x_usart

.c

通用同步/异步收发器。

4

misc

.c

中断向量控制器。

可按下图所示在新建工程时添加需要的c文件。

图4:在新建工程中添加所需库函数c文件

表6:实验需要用到的H文件

序号

文件名

后缀

功能描述

1

stm32f10x_rcc

.h

复位与时钟控制器。

2

stm32f10x_gpio

.h

通用输入输出。

3

stm32f10x_usart

.h

通用同步/异步收发器。

4

misc

.h

中断向量控制器。

在使用该实验工程时,需要用到的h文件如表5所示。需要在MDK中点击魔术棒,打开工程配置窗口,按照下图所示添加头文件包含路径。

图5:如何添加头文件包含路径

编写代码

首先初始化USART1,完成的操作有:使能GPIO和USART1的时钟,复位USART1,配置USART1用到的PA9和PA10模式,初始化USART1参数,开启USART1并初始化NVIC,使能USART1外设。具体代码如下。

代码清单:初始化USART1并配置USART1中断优先级

  1. /**************************************************************************************
  2. * 描 述 : 初始化USART1并配置USART1中断优先级
  3. * 入 参 : 无
  4. * 返回值 : 无
  5. **************************************************************************************/
  6. void USART1_Init(void)
  7. {
  8. GPIO_InitTypeDef GPIO_InitStructure;
  9. USART_InitTypeDef USART_InitStructure;
  10. USART_ClockInitTypeDef USART_ClockInitStructure;
  11. NVIC_InitTypeDef NVIC_InitStructure;

  12. //打开所用GPIO及串口1的时钟
  13. RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1 , ENABLE);

  14. //配置的IO是PA9,串口1的TXD
  15. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  16. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  17. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //推挽输出
  18. GPIO_Init(GPIOA, &GPIO_InitStructure);
  19. //配置的IO是PA10,串口1的RXD
  20. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  21. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  22. GPIO_Init(GPIOA, &GPIO_InitStructure);

  23. //配置串口1的硬件参数
  24. USART_DeInit(USART1); //将外设USART1寄存器重设为缺省值
  25. USART_InitStructure.USART_BaudRate = 19200; //设置串口1波特率为19200
  26. USART_InitStructure.USART_WordLength = USART_WordLength_8b; //设置一个帧中传输数据位
  27. USART_InitStructure.USART_StopBits = USART_StopBits_1; //定义发送的停止位数目为1
  28. USART_InitStructure.USART_Parity = USART_Parity_No; //奇偶失能
  29. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制失能
  30. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //发送接收使能
  31. USART_Init(USART1, &USART_InitStructure);

  32. USART_ClockInitStructure.USART_Clock = USART_Clock_Disable; //时钟低电平活动
  33. USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low; //设置SCLK引脚上时钟输出的极性为低电平
  34. USART_ClockInitStructure.USART_CPHA = USART_CPHA_1Edge; //时钟第一个边沿进行数据捕获
  35. USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable; //最后一位数据的时钟脉冲不从SCLK输出
  36. USART_ClockInit(USART1, &USART_ClockInitStructure);

  37. USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //使能USART1接收中断
  38. USART_Cmd(USART1, ENABLE); //使能USART1外设

  39. //配置串口1中断优先级
  40. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //NVIC_Group:先占优先级2位,从优先级2位
  41. NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //配置为串口1中断
  42. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1; //先占优先级为1
  43. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级为3
  44. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断通道
  45. NVIC_Init(&NVIC_InitStructure);
  46. }

然后,编写USART1的中断服务函数。代码如下。

代码清单:USART1中断服务函数

  1. /**************************************************************************************
  2. * 描 述 : USART1全局中断服务
  3. * 入 参 : 无
  4. * 返回值 : 无
  5. **************************************************************************************/
  6. void USART1_IRQHandler(void)
  7. {
  8. if(USART_GetITStatus(USART1,USART_IT_RXNE)!= RESET) //接收中断
  9. {
  10. Rx232buffer= USART_ReceiveData(USART1); //通过外设USART1接收数据
  11. Flag=TRUE; //接收到数据,接收标识符有效
  12. USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除USART1的中断待处理位
  13. }
  14. }

之后,用户设计一个串口通信的应用函数,代码如下。该应用函数实现的功能即是本实验实现的功能的体现。

代码清单:USART1_Tx_Puts接收数据并处理函数

  1. /**************************************************************************************
  2. * 描 述 : USART1接收到数据后串口发送出去
  3. * 入 参 : 无
  4. * 返回值 : 无
  5. **************************************************************************************/
  6. void USART1_Tx_Puts(void)
  7. {
  8. if(Flag) //有新数据通过串口被接收到
  9. {
  10. USART1_SendByte(Rx232buffer); //发送字符
  11. USART1_SendByte(0x0D); //发送换行符
  12. USART1_SendByte(0x0A); //发送换行符
  13. Flag=FALSE; //清除接收标识符
  14. }
  15. }

最后,主函数初始化相关串口配置后,在while循环中调用用户应用函数。如下图所示。

代码清单:主函数

  1. int main(void)
  2. {
  3. //初始化USART1并配置USART1中断优先级
  4. USART1_Init();

  5. //主循环
  6. while(1)
  7. {
  8. USART1_Tx_Puts(); //串口1接收到1个字符后返回该字符
  9. }
  10. }
实验步骤
  1. 解压“…\第3部分:标准库教程和实验源码\ 1 - 基础实验程序\”目录下的压缩文件“实验6-1:USART1串口收发数据”,打开解压后的文件夹,将“USART1”文件夹拷贝到合适的目录,如“D\STM32F103ZET6”。
  2. 启动MDK5.23。
  3. 在MDK5中执行“Project→Open Project”打开“…\ USART1 \projec”目录下的工程“USART1.uvproj”。
  4. 点击编译按钮编译工程。注意查看编译输出栏,观察编译的结果,如果有错误,修改程序,直到编译成功为止。编译后生成的HEX文件“USART1.hex”位于工程目录下的“Objects”文件夹中。
  5. 点击下载按钮下载程序 。如果需要对程序进行仿真,点击Debug按钮,即可将程序下载到STM32F103ZET6中进行仿真。
  6. 程序运行后,打开串口调试助手选择正确的串口号,波特率设置为19200,数据位为8、停止位为1。然后点击打开串口,在发送区任意写一个字符点击发送,则在窗口可看到接收到的字符与发送字符一致。
USART1串口使用printf函数实验工程需要用到的库文件

在使用库函数建“实验6-2: USART1串口使用printf函数”工程时,需要用到的c文件以及添加头文件包含路径的方法与介绍“实验6-1:USART1串口收发数据”完全一样,在此不再赘述。

编写代码

首先初始化USART1,函数名是:USART1_Init。该函数代码与“实验6-1:USART1串口收发数据”中USART1_Init()代码完全一样,在此不再介绍。

其次,串口要使用printf函数,需要重定向两个c库函数到USART1,如下所示。

代码清单:重定向c库函数printf到USART1

  1. /**************************************************************************************
  2. * 描 述 : 重定向c库函数printf到USART1
  3. * 入 参 : 无
  4. * 返回值 : 无
  5. **************************************************************************************/
  6. int fputc(int ch, FILE *f)
  7. {
  8. /* 发送一个字节数据到USART1 */
  9. USART_SendData(USART1, (uint8_t) ch);

  10. /* 等待发送完毕 */
  11. while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);

  12. return (ch);
  13. }

代码清单:重定向c库函数scanf到USART1

  1. /**************************************************************************************
  2. * 描 述 : 重定向c库函数scanf到USART1
  3. * 入 参 : 无
  4. * 返回值 : 无
  5. **************************************************************************************/
  6. int fgetc(FILE *f)
  7. {
  8. /* 等待串口1输入数据 */
  9. while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);

  10. return (int)USART_ReceiveData(USART1);
  11. }

最后,主函数初始化相关串口配置后,直接调用printf函数。如下图所示。

代码清单:主函数

  1. int main(void)
  2. {
  3. //初始化USART1并配置USART1中断优先级
  4. USART1_Init();

  5. printf("\r\n 对PRINTF函数测试OK \r\n");


  6. //主循环
  7. while(1)
  8. {
  9. ;
  10. }
  11. }
实验步骤
  1. 解压“…\第3部分:标准库教程和实验源码\ 1 - 基础实验程序\”目录下的压缩文件“实验6-2:USART1串口使用printf函数”,打开解压后的文件夹,将“USART1”文件夹拷贝到合适的目录,如“D\STM32F103ZET6”。
  2. 启动MDK5.23。
  3. 在MDK5中执行“Project→Open Project”打开“…\ USART1 \projec”目录下的工程“USART1.uvproj”。
  4. 点击编译按钮编译工程。注意查看编译输出栏,观察编译的结果,如果有错误,修改程序,直到编译成功为止。编译后生成的HEX文件“USART1.hex”位于工程目录下的“Objects”文件夹中。
  5. 点击下载按钮下载程序 。如果需要对程序进行仿真,点击Debug按钮,即可将程序下载到STM32F103ZET6中进行仿真。
  6. 打开串口调试助手选择正确的串口号,波特率设置为19200,数据位为8、停止位为1,并点击打开串口。
  7. 按一下复位按键,让程序从新执行,可在串口调试助手的接收窗口显示“对PRINTF函数测试OK”内容。
USART2串口收发数据实验工程需要用到的库文件

在使用库函数建“实验6-3:USART2串口收发数据”工程时,需要用到的c文件以及添加头文件包含路径的方法与介绍“实验6-1:USART1串口收发数据”完全一样,在此不再赘述。

编写代码

首先初始化USART2,完成的操作有:使能GPIO和USART2的时钟,复位USART2,配置USART2用到的PA2和PA3模式,初始化USART2参数,开启USART2并初始化NVIC,使能USART2外设。具体代码如下。

代码清单:初始化USART2并配置USART2中断优先级

  1. /**************************************************************************************
  2. * 描 述 : 初始化USART2并配置USART2中断优先级
  3. * 入 参 : 无
  4. * 返回值 : 无
  5. **************************************************************************************/
  6. void USART2_Init(void)
  7. {
  8. GPIO_InitTypeDef GPIO_InitStructure;
  9. USART_InitTypeDef USART_InitStructure;
  10. USART_ClockInitTypeDef USART_ClockInitStructure;
  11. NVIC_InitTypeDef NVIC_InitStructure;

  12. //打开所用GPIO及串口2的时钟
  13. RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA , ENABLE);
  14. RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART2 , ENABLE);

  15. //配置的IO是PA2,串口2的TXD
  16. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  17. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  18. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
  19. GPIO_Init(GPIOA, &GPIO_InitStructure);
  20. //配置的IO是PA3,串口2的RXD
  21. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  22. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  23. GPIO_Init(GPIOA, &GPIO_InitStructure);

  24. //配置串口2的硬件参数
  25. USART_DeInit(USART2); //将外设USART2寄存器重设为缺省值
  26. USART_InitStructure.USART_BaudRate = 19200; //设置串口2波特率为19200
  27. USART_InitStructure.USART_WordLength = USART_WordLength_8b; //设置一个帧中传输数据位
  28. USART_InitStructure.USART_StopBits = USART_StopBits_1; //定义发送的停止位数目为1
  29. USART_InitStructure.USART_Parity = USART_Parity_No; //奇偶失能
  30. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制失能
  31. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //发送接收使能
  32. USART_Init(USART2, &USART_InitStructure);

  33. USART_ClockInitStructure.USART_Clock = USART_Clock_Disable; //时钟低电平活动
  34. USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low; //设置SCLK引脚上时钟输出的极性为低电平
  35. USART_ClockInitStructure.USART_CPHA = USART_CPHA_1Edge; //时钟第一个边沿进行数据捕获
  36. USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable; //最后一位数据的时钟脉冲不从SCLK输出
  37. USART_ClockInit(USART2, &USART_ClockInitStructure);

  38. USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); //使能USART2接收中断
  39. USART_Cmd(USART2, ENABLE); //使能USART2外设

  40. //配置串口2中断优先级
  41. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //NVIC_Group:先占优先级2位,从优先级2位
  42. NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //配置为串口2中断
  43. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; //先占优先级为3
  44. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级为3
  45. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断通道
  46. NVIC_Init(&NVIC_InitStructure);
  47. }

然后,编写USART2的中断服务函数。代码如下。

代码清单:USART2中断服务函数

  1. /**************************************************************************************
  2. * 描 述 : USART2全局中断服务
  3. * 入 参 : 无
  4. * 返回值 : 无
  5. **************************************************************************************/
  6. void USART2_IRQHandler(void)
  7. {
  8. if(USART_GetITStatus(USART2,USART_IT_RXNE)!= RESET) //接收中断
  9. {
  10. Rx232buffer= USART_ReceiveData(USART2); //通过外设USART2接收数据
  11. Flag=TRUE; //接收到数据,接收标识符有效
  12. USART_ClearITPendingBit(USART2, USART_IT_RXNE); //清除USART2的中断待处理位
  13. }
  14. }

之后,用户设计一个串口通信的应用函数,代码如下。该应用函数实现的功能即是本实验实现的功能的体现

代码清单:USART1_Tx_Puts接收数据并处理函数

  1. /**************************************************************************************
  2. * 描 述 : USART2接收到数据后串口发送出去
  3. * 入 参 : 无
  4. * 返回值 : 无
  5. **************************************************************************************/
  6. void USART2_Tx_Puts(void)
  7. {
  8. if(Flag) //有新数据通过串口被接收到
  9. {
  10. USART2_SendByte(Rx232buffer); //发送字符
  11. USART2_SendByte(0x0D); //发送换行符
  12. USART2_SendByte(0x0A); //发送换行符
  13. Flag=FALSE; //清除接收标识符
  14. }
  15. }

最后,主函数初始化相关串口配置后,在while循环中调用用户应用函数。如下图所示。

代码清单:主函数

  1. int main(void)
  2. {
  3. //初始化USART2并配置USART2中断优先级
  4. USART2_Init();

  5. //主循环
  6. while(1)
  7. {
  8. USART2_Tx_Puts(); //串口2接收到1个字符后返回该字符
  9. }
  10. }
实验步骤
  1. 解压“…\第3部分:标准库教程和实验源码\ 1 - 基础实验程序\”目录下的压缩文件“实验6-3:USART2串口收发数据”,打开解压后的文件夹,将“USART2”文件夹拷贝到合适的目录,如“D\STM32F103ZET6”。
  2. 启动MDK5.23。
  3. 在MDK5中执行“Project→Open Project”打开“…\ USART2 \projec”目录下的工程“USART2.uvproj”。
  4. 点击编译按钮编译工程。注意查看编译输出栏,观察编译的结果,如果有错误,修改程序,直到编译成功为止。编译后生成的HEX文件“USART2.hex”位于工程目录下的“Objects”文件夹中。
  5. 点击下载按钮下载程序 。如果需要对程序进行仿真,点击Debug按钮,即可将程序下载到STM32F103ZET6中进行仿真。
  6. 程序运行后,打开串口调试助手选择正确的串口号,波特率设置为19200,数据位为8、停止位为1。然后点击打开串口,在发送区任意写一个字符点击发送,则在窗口可看到接收到的字符与发送字符一致。
USART2串口使用printf函数实验工程需要用到的库文件

在使用库函数建“实验6-4:USART2串口使用printf函数”工程时,需要用到的c文件以及添加头文件包含路径的方法与介绍“实验6-1:USART1串口收发数据”完全一样,在此不再赘述。

编写代码

首先初始化USART2,函数名是:USART2_Init。该函数代码与“实验6-3:USART2串口收发数据”中USART2_Init()代码完全一样,在此不再介绍。

其次,串口要使用printf函数,需要重定向两个c库函数到USART2,如下所示。

代码清单:重定向c库函数printf到USART2

  1. /**************************************************************************************
  2. * 描 述 : 重定向c库函数printf到USART2
  3. * 入 参 : 无
  4. * 返回值 : 无
  5. **************************************************************************************/
  6. int fputc(int ch, FILE *f)
  7. {
  8. /* 发送一个字节数据到USART2 */
  9. USART_SendData(USART2, (uint8_t) ch);

  10. /* 等待发送完毕 */
  11. while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);

  12. return (ch);
  13. }

代码清单:重定向c库函数scanf到USART2

  1. /**************************************************************************************
  2. * 描 述 : 重定向c库函数scanf到USART2
  3. * 入 参 : 无
  4. * 返回值 : 无
  5. **************************************************************************************/
  6. int fgetc(FILE *f)
  7. {
  8. /* 等待串口1输入数据 */
  9. while (USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == RESET);

  10. return (int)USART_ReceiveData(USART2);
  11. }

最后,主函数初始化相关串口配置后,直接调用printf函数。如下图所示。

代码清单:主函数

  1. int main(void)
  2. {
  3. //初始化USART2并配置USART2中断优先级
  4. USART2_Init();

  5. printf("\r\n 对PRINTF函数测试OK \r\n");

  6. //主循环
  7. while(1)
  8. {
  9. ; //无任务
  10. }
  11. }
实验步骤
  1. 解压“…\第3部分:标准库教程和实验源码\ 1 - 基础实验程序\”目录下的压缩文件“实验6-4:USART2串口使用printf函数”,打开解压后的文件夹,将“USART2”文件夹拷贝到合适的目录,如“D\STM32F103ZET6”。
  2. 启动MDK5.23。
  3. 在MDK5中执行“Project→Open Project”打开“…\ USART2 \projec”目录下的工程“USART2.uvproj”。
  4. 点击编译按钮编译工程。注意查看编译输出栏,观察编译的结果,如果有错误,修改程序,直到编译成功为止。编译后生成的HEX文件“USART2.hex”位于工程目录下的“Objects”文件夹中。
  5. 点击下载按钮下载程序 。如果需要对程序进行仿真,点击Debug按钮,即可将程序下载到STM32F103ZET6中进行仿真。
  6. 打开串口调试助手选择正确的串口号,波特率设置为19200,数据位为8、停止位为1,并点击打开串口。
  7. 按一下复位按键,让程序从新执行,可在串口调试助手的接收窗口显示“对PRINTF函数测试OK”内容。
USART1串口发送数据(DMA)实验工程需要用到的库文件

在使用库函数建“实验6-5:USART1串口发送数据(DMA)”工程时,需要用到的c文件如下表所示。

表7:实验需要用到的C文件

序号

文件名

后缀

功能描述

1

stm32f10x_rcc

.c

复位与时钟控制器。

2

stm32f10x_gpio

.c

通用输入输出。

3

stm32f10x_usart

.c

通用同步/异步收发器。

4

misc

.c

中断向量控制器。

5

stm32f10x_dma

.c

直接内存存取控制器。

可按下图所示在新建工程时添加需要的c文件。

图6:在新建工程中添加所需库函数c文件

表8:实验需要用到的H文件

序号

文件名

后缀

功能描述

1

stm32f10x_rcc

.h

复位与时钟控制器。

2

stm32f10x_gpio

.h

通用输入输出。

3

stm32f10x_usart

.h

通用同步/异步收发器。

4

misc

.h

中断向量控制器。

5

stm32f10x_dma

.h

直接内存存取控制器。

在使用该实验工程时,需要用到的h文件如表5所示。需要在MDK中点击魔术棒,打开工程配置窗口,按照下图所示添加头文件包含路径。

图7:如何添加头文件包含路径

编写代码

首先初始化USART1,函数名是:USART1_Init。该函数代码与“实验6-1:USART1串口收发数据”中USART1_Init()代码不完全一样,本实验中没有使能USART中断。代码如下。

代码清单:初始化USART1

  1. /**************************************************************************************
  2. * 描 述 : 初始化USART1并配置USART1中断优先级
  3. * 入 参 : 无
  4. * 返回值 : 无
  5. **************************************************************************************/
  6. void USART1_Init(void)
  7. {
  8. GPIO_InitTypeDef GPIO_InitStructure;
  9. USART_InitTypeDef USART_InitStructure;
  10. USART_ClockInitTypeDef USART_ClockInitStructure;

  11. //打开所用GPIO及串口1的时钟
  12. RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1 , ENABLE);

  13. //配置的IO是PA9,串口1的TXD
  14. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  15. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  16. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //推挽输出
  17. GPIO_Init(GPIOA, &GPIO_InitStructure);
  18. //配置的IO是PA10,串口1的RXD
  19. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  20. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  21. GPIO_Init(GPIOA, &GPIO_InitStructure);

  22. //配置串口1的硬件参数
  23. USART_DeInit(USART1); //将外设USART1寄存器重设为缺省值
  24. USART_InitStructure.USART_BaudRate = 19200; //设置串口1波特率为19200
  25. USART_InitStructure.USART_WordLength = USART_WordLength_8b; //设置一个帧中传输数据位
  26. USART_InitStructure.USART_StopBits = USART_StopBits_1; //定义发送的停止位数目为1
  27. USART_InitStructure.USART_Parity = USART_Parity_No; //奇偶失能
  28. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制失能
  29. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //发送接收使能
  30. USART_Init(USART1, &USART_InitStructure);

  31. USART_ClockInitStructure.USART_Clock = USART_Clock_Disable; //时钟低电平活动
  32. USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low; //设置SCLK引脚上时钟输出的极性为低电平
  33. USART_ClockInitStructure.USART_CPHA = USART_CPHA_1Edge; //时钟第一个边沿进行数据捕获
  34. USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable; //最后一位数据的时钟脉冲不从SCLK输出
  35. USART_ClockInit(USART1, &USART_ClockInitStructure);

  36. USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //使能USART1接收中断
  37. USART_Cmd(USART1, ENABLE); //使能USART1外设
  38. }

其次初始化DMA,设置有关参数使之操作对象是USART1,代码如下。

代码清单:初始化DMA

  1. /**************************************************************************************
  2. * 描 述 : 初始化DMA
  3. * 入 参 : 无
  4. * 返回值 : 无
  5. **************************************************************************************/
  6. void DMA_USART1_Init(void)
  7. {
  8. DMA_InitTypeDef DMA_InitStructure;

  9. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //开启DMA时钟

  10. DMA_InitStructure.DMA_PeripheralBaseAddr = ( uint32_t ) ( & ( USART1->DR ) ); //设置DMA源:串口1数据寄存器地址
  11. DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SendBuff; //DMA内存基地址(要传输的变量的指针)
  12. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向,从内存读取发送到外设
  13. DMA_InitStructure.DMA_BufferSize = SENDSIZE_MAX; //DMA通道的DMA缓存的大小
  14. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
  15. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
  16. DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据宽度为8位
  17. DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //内存数据宽度为8位
  18. DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循环缓存模式
  19. DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道拥有中优先级
  20. DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //禁止DMA通道内存到内存传输
  21. DMA_Init(DMA1_Channel4, &DMA_InitStructure); //配置DMA1的4通道

  22. DMA_Cmd (DMA1_Channel4,ENABLE); //使能DMA1的4通道
  23. }

然后,用户设计一个向发送缓存区存放数值函数,代码如下。

代码清单:向发送缓存区存放数值

  1. /**************************************************************************************
  2. * 描 述 : 向发送缓存区存放数值
  3. * 入 参 : 无
  4. * 返回值 : 无
  5. **************************************************************************************/
  6. void SendBuff_Init(void)
  7. {
  8. uint16_t i;
  9. for(i=0;i<SENDSIZE_MAX;i )
  10. {
  11. if(i%2)
  12. {
  13. SendBuff[i] = 'O'; //发送缓存奇数空间存放'O'
  14. }
  15. else
  16. {
  17. SendBuff[i] = 'K'; //发送缓存偶数空间存放'K'
  18. }
  19. }
  20. }

最后,主函数初始化相关串口配置后,在while循环中调用用户应用函数。如下图所示。

代码清单:主函数

  1. int main(void)
  2. {
  3. //初始化4个用户指示灯D1、D2、D3、D4
  4. leds_init();
  5. //初始化USART1并配置USART1中断优先级
  6. USART1_Init();
  7. //初始化DMA
  8. DMA_USART1_Init();
  9. //初始化用于检测按键S1的引脚PE2
  10. key_init();
  11. //向发送缓存区存放数值
  12. SendBuff_Init();
  13. //USART1 向 DMA发出TX请求
  14. USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

  15. //主循环 ,该部分占用CPU资源
  16. while(1)
  17. {
  18. //调用库函GPIO_ReadInputDataBit()检测按键S1对应引脚PE2的电平是否为低电平
  19. if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2) == 0 )
  20. {
  21. //软件延时10ms,如果延时后按键S1的电平依然没有变化,说明按键确实被有效操作,简称按键防抖动
  22. sw_delay_ms(10);
  23. //检测按键S1对应引脚PE2的电平依然为低电平,即按键S1确实被按下
  24. if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2) == 0 )
  25. {
  26. led_on(LED_1); //点亮D1
  27. //等待按键S1释放,即如果PE2一直为低电平,会一直执行空命令
  28. while(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2) == 0 )
  29. {
  30. ; //条件GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2) == 0成立,会执行这个空命令
  31. }
  32. //按键S1松开,会执行下一行语句,即熄灭D1
  33. led_off(LED_1);
  34. }
  35. }
  36. }
  37. }
实验步骤
  1. 解压“…\第3部分:标准库教程和实验源码\ 1 - 基础实验程序\”目录下的压缩文件“实验6-5:USART1串口发送数据(DMA)”,打开解压后的文件夹,将“DMA_USART1”文件夹拷贝到合适的目录,如“D\STM32F103ZET6”。
  2. 启动MDK5.23。
  3. 在MDK5中执行“Project→Open Project”打开“…\ DMA_USART1 \projec”目录下的工程“DMA_USART1.uvproj”。
  4. 点击编译按钮编译工程。注意查看编译输出栏,观察编译的结果,如果有错误,修改程序,直到编译成功为止。编译后生成的HEX文件“DMA_USART1.hex”位于工程目录下的“Objects”文件夹中。
  5. 点击下载按钮下载程序 。如果需要对程序进行仿真,点击Debug按钮,即可将程序下载到STM32F103ZET6中进行仿真。
  6. 程序运行后,可按下述操作进行实验:

1)打开串口调试助手选择正确的串口号,波特率设置为19200,数据位为8、停止位为1,并点击打开串口。

2)可在串口调试助手的接收窗口显示“OK”内容。

3)按下用户按键S1可观察到指示灯D1会有相应变化。

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved