立即注册 找回密码

微雪课堂

搜索
微雪课堂 STM32 STM32CubeMX系列教程 查看内容

STM32CubeMX系列教程5:串行通信(USART)

2016-5-3 11:40| 发布者: MyMX1213| 查看: 162235| 评论: 58|原作者: MyMX1213

摘要: 本章以串口为例讲解,HAL 库轮询,中断,DMA 三种编程模型。
本章以串口为例讲解,HAL 库轮询,中断,DMA 三种编程模型。
1.前情回顾
       在串行通信中,一个字符一个字符地传输,每个字符一位一位地传输,并且传输一个字符时,总是以“起始位”开始,以“停止位”结束。在进行传输之前,双方一定要使用同一个波特率设置。波特率就是每秒钟传输的数据位数。
       常用的两种基本串行通信方式包括同步通信和异步通信。我们通常使用的是异步通信.异步通信规定传输的数据格式由起始位(start bit)、数据位(data bit)、奇偶校验位(parity bit)和停止位(stop bit)组成。


2.重定义printf函数。
        打开STM32CubeMX新建工程,选择STMF746IGT6芯片,选择外部高速晶振(HSE)。USART1选择为异步通信方式。PA10设置RX接收,PA9设置为TX发送。

配置时钟系统时钟为216MHz,STMF746可以单独配置USART时钟,默认为108Mhz。


串口配置设置波特率为115200 Bits/s。传输数据长度为8 Bit。奇偶检验无,停止位1.其他参数默认。


        生成报告以及代码,编译程序。在usart.c文件中可看到串口1的初始化函数MX_USART1_UART_Init(void),以及管脚配置函数HAL_UART_MspInit()

        C语言中的标准库中所用的标准输出函数,默认的输出设备是显示器,要实现串口或LCD的输出,必须重新定义标准库函数里与输出函数相关的函数。例如:printf输出到串口,需要将fputc里面的输出指向串口(重定向),方法如下:只要自己添加一个int fputc(int ch, FILE *f)函数,能够输出字符就可以了。

        在usart.c文件后面添加如下代码,代码中添加了#ifdef宏定义进行条件编译,如果使用GUNC编译,则PUTCHAR_PROTOTYPE 定义为int __io_putchar(int ch)函数,否则定义为int fputc(int ch, FILE *f)函数。

/* USER CODE BEGIN 1 */
#ifdef __GNUC__
  /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
     set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
 
  return ch;
}
/* USER CODE END 1 */

其中HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);这个语句表示通过串口1发个一个字符。ch为字符的存储地址,0xFFFF为超时时间。在stm32f7xx_hal_uart.c文件中可以找到HAL_UART_Transmit函数。


在main.c文件中添加应用函数。

  /* USER CODE BEGIN 2 */
    printf("\n\r UART Printf Example: retarget the C library printf function to the UART\n\r");
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */
 
  /* USER CODE BEGIN 3 */
        printf("\n\r welcome to www.waveshere.com !!!\n\r");
        HAL_Delay(1000);
  }
  /* USER CODE END 3 */

编译程序并下载到开发板。用USB线连接开发板到电脑,在电脑上打开串口调试助手。选择对应的串口号,设置波特率为115200。按下复位按键会接收到如图信息。


打开stm32f7xx_hal_uart.h头文件,在文件后最后面可以看到有如下操作串口的函数。


串口的发送接收函数:
HAL_UART_Transmit();串口轮询模式发送,使用超时管理机制。
HAL_UART_Receive();串口轮询模式发送,使用超时管理机制。
HAL_UART_Transmit_IT();串口中断模式发送,
HAL_UART_Receive_IT();串口中断模式发送
HAL_UART_Transmit_DMA();串口DMA模式发送
HAL_UART_Receive_DMA();串口DMA模式发送

串口相关的中断函数:
HAL_UART_TxHalfCpltCallback():一半数据(half transfer)发送完成后,通过中断处理函数调用。
HAL_UART_TxCpltCallback():发送完成后,通过中断处理函数调用。
HAL_UART_RxHalfCpltCallback():一半数据(half transfer)接收完成后,通过中断处理函数调用。
HAL_UART_RxCpltCallback():接收完成后,通过中断处理函数调用。
HAL_UART_ErrorCallback():传输过程中出现错误时,通过中断处理函数调用。

可看到串口发送和就是有三种通信模式:
       第一种是上面用到的轮询的模式。CPU不断查询IO设备,如设备有请求则加以处理。例如CPU不断查询串口是否传输完成,如传输超过则返回超时错误。轮询方式会占用CPU处理时间,效率较低。
       第二种就是中断控制方式。当I/O操作完成时,输入输出设备控制器通过中断请求线向处理器发出中断信号,处理器收到中断信号之后,转到中断处理程序,对数据传送工作进行相应的处理。
       第三种就是直接内存存取技术(DMA)方式。所谓直接传送,即在内存与IO设备间传送一个数据块的过程中,不需要CPU的任何中间干涉,只需要CPU在过程开始时向设备发出“传送块数据”的命令,然后通过中断来得知过程是否结束和下次操作是否准备就绪。

3.中断模式。
        打开STM32CubeMX重新建工程,配置和前面一样。只是这个工程中,开启了串口中断。



生成报告以及代码,编译程序。在main函数前面添加两个数组变量。

/* Private variables ---------------------------------------------------------*/
 
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
uint8_t aTxStartMessage[] = "\r\n****UART-Hyperterminal communication based on IT ****\r\nEnter 10 characters using keyboard :\r\n";
 
/* Buffer used for reception */
uint8_t aRxBuffer[20];
/* USER CODE END PV */

在main函数中添加两个语句通过串口中断发送aTxStartMessage数组的数据和接收数据10个字符,保存在数组aRxBuffer中

/* USER CODE BEGIN 2 */
    HAL_UART_Transmit_IT(&huart1, (uint8_t *)aTxStartMessage, sizeof(aTxStartMessage));
    HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 10);
/* USER CODE END 2 */

在main.c文件后面添加中断接收完成回调函数。中断回调函数中将接收到的数据又通过串口发送回去。

/* USER CODE BEGIN 4 */
/**
  * @brief Rx Transfer completed callbacks
  * @param huart: uart handle
  * @retval None
  */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(huart);
  
  /* NOTE : This function should not be modified, when the callback is needed,
            the HAL_UART_RxCpltCallback can be implemented in the user file
   */
    HAL_UART_Transmit(&huart1, (uint8_t *)aRxBuffer, 10,0xFFFF);
}
/* USER CODE END 4 */

编译程序并下载到开发板。用USB线连接开发板到电脑,在电脑上打开串口调试助手。选择对应的串口号,设置波特率为115200。按下复位按键会接收到aTxStartMessage数组的数据。通过串口助手发送10个字符,串口助手回显示发送的数据。注意:串口要发够10个字符串,才会触发中断。少于10个字符则不会触发中断,串口不会显示发送的数据。超过10个字符,串口只会发送10个字符回来显示。

串口不定长接收程序:USART CMD - 不定长接受.zip


1068

顶一下

刚表态过的朋友 (1068 人)

相关阅读

发表评论

最新评论

引用 游客 2020-9-17 09:45
我用LSE作为LPUART时钟源,串口发送数据会进入硬件hardfault,好像是超时或者标志读取的问题,HAL库貌似有问题,有谁遇到这个问题解决了的
引用 pengqiangyou 2020-9-16 14:24
: 记得添加 这 不然会报错啊: /* USER CODE BEGIN 0 */ #include "stdio.h" /* USER CODE END 0 */
是的  HAL更新了是需要添加#include "stdio.h"  之前版本是不需要添加的
引用 游客 2020-9-14 14:53
记得添加 这 不然会报错啊:
/* USER CODE BEGIN 0 */
#include "stdio.h"
/* USER CODE END 0 */
引用 游客 2020-8-9 21:05
请教一下,中文乱码怎么解决?
引用 游客 2020-7-1 15:25
调试发现就是靠这个实现不定长回复的,接收是按长度RX_LEN接收,CNDTR理解为待接收长度,两者相减刚好是接收长度
jackis: 请问一下不定长接收数据里面         temp = huart1.hdmarx->Instance->CNDTR;   // DMA 传输的数据大小         UsartType.RX_Size =  RX_LEN - temp; 这两行代 ...
引用 游客 2020-6-16 17:17
1、没有生成uart.c文件,将对应添加的内容直接添加到main.c前面即可;
2、串口中断可以重复触发,且设置了20个字节后,少于20个字节也可以返回,多于20个字节也可以正常反馈输出。
3、也是刚开始接触,欢迎交流学习。
引用 游客 2020-5-26 16:07
好吧,原来是板子上usart1的pin做了重映射,映射到另外一组pin上去了...
引用 游客 2020-5-25 22:52
什么都输出不了是咋回事啊,串口也配置了,printf也重定向了,波特率,极性,检验都对的,串口就是没输出。程序有在跑,跑马灯点上了
引用 游客 2020-5-20 14:02
为什么我的串口出不来,怎么连线的谁能说一下。。。
引用 jackis 2020-4-25 09:06
请问一下不定长接收数据里面
        temp = huart1.hdmarx->Instance->CNDTR;   // DMA 传输的数据大小
        UsartType.RX_Size =  RX_LEN - temp;
这两行代码我一直没看懂,CNDTR 为 DMA 需要传输的字节数,RX_Size 为接收的字节数,那为什么要用 RX_LEN - temp 呢?
谢谢解答
引用 游客 2020-1-14 20:15
给力
: 如果使用了HAL_UART_Receive_IT(),最好不用HAL_UART_Transmit(),因为发送过程会锁定串口,这时来了读取中断,其中的下一次HAL_UART_Receive_IT()会因为获得不 ...
引用 游客 2020-1-14 18:14
: 如果使用了HAL_UART_Receive_IT(),最好不用HAL_UART_Transmit(),因为发送过程会锁定串口,这时来了读取中断,其中的下一次HAL_UART_Receive_IT()会因为获得不 ...
引用 游客 2020-1-10 16:59
如果使用了HAL_UART_Receive_IT(),最好不用HAL_UART_Transmit(),因为发送过程会锁定串口,这时来了读取中断,其中的下一次HAL_UART_Receive_IT()会因为获得不了设备而失败,因此中断的链条就打断了。个人猜测最好换成HAL_UART_Transmit_IT(),或者调用HAL_UART_Transmit()前关中断,或者HAL_UART_Receive_IT()失败时做个标记,HAL_UART_Transmit()执行完毕后若标记存在就调用一次HAL_UART_Receive_IT()
引用 游客 2019-11-8 10:44
HAL_UART_Receive_IT 我試著打10個字元都沒有印出來  是甚麼設定上沒有弄好呢?   另外有沒有接收 不定長度的方法?
引用 游客 2019-11-4 11:06
:
引用 游客 2019-8-5 21:24
: PUTCHAR_PROTOTYPE 报错 显示unknown  type  name  ‘file’ 怎么回事
#include "stdio.h"
引用 游客 2019-7-10 17:33
PUTCHAR_PROTOTYPE
报错
显示unknown  type  name  ‘file’



#include "stdio.h"
引用 游客 2019-8-3 16:08
uart.c文件没有生成,哪位知道是哪里出了问题么
引用 游客 2019-7-25 17:32
: PUTCHAR_PROTOTYPE 报错 显示unknown  type  name  ‘file’ 怎么回事
#include "stdio.h"
引用 游客 2019-7-10 17:33
PUTCHAR_PROTOTYPE
报错
显示unknown  type  name  ‘file’
怎么回事
引用 游客 2019-5-9 17:04
:
看看你PC机和哪个串口连接的,不一定是串口1吧

查看全部评论(58)

CubeMX教程

微雪官网|产品资料|手机版|小黑屋|微雪课堂. ( 粤ICP备05067009号 )

GMT+8, 2020-9-29 03:48 , Processed in 0.017990 second(s), 18 queries .

返回顶部