zoukankan      html  css  js  c++  java
  • 第三节: 串口通信(用CubeMX学习STM32)

    串口通信


    《用CubeMX学习STM32》

    注释 点击上面蓝字进入完整专栏,这个系列所有文章都会整合到这个专栏


    本篇博客中用的串口调试助手

    链接:https://pan.baidu.com/s/1DN60ojns3Wu88frJ5pqSzA
    提取码:6exl
    复制这段内容后打开百度网盘手机App,操作更方便哦

    时间戳和白字黑字两个比较鸡肋的功能是没有的


    3、STM32串口通信

    前言: STM32串口介绍

    串行通信是单片机与外部设备或其他计算机交换信息的一个方式, 数据一位一位的按顺序传送, 其优点是只需要一条传输线, 协议简单, 但是缺点就是传送速度较慢。
    串口是单片机上非常便捷的一个工具, 当写程序需要调试的时候, 它可以很方便的提供调试方法, 只要在一些关键代码执行的地方, 通过串口给串口调试助手发送相关信息, 就可以使我们很方便的查看代码在这个位置的执行情况。

    下面看一下我所使用的单片机上串口的原理图接线
    在这里插入图片描述

    外部的发送端TXD就是单片机串口的接收端USART_RX,   外部接收端RXD就是单片机串口的发送端USART_TX
    TXD : Transmit(TX) Data(D)  Receive(RX) Data(D))

    USART就是Universal Synchronous/Asynchronous Receiver/Transmitter(通用同步/异步串行接收/发送器)的缩写 就是一个全双工的收发器

    CH340是串口芯片, 当单片机用一根USB串口线接到电脑的时候, TXD就是指电脑通过数据线给单片机发送数据,对应单片机要接收数据, 因此单片机对应引脚就是RX(接收)

    (电脑端发送) TXD -----> USART_RX(单片机接收)

    (单片机发送) USART_TX-----> RXD (电脑端接收)

    单片机上用跳线帽将PA10, PA9和USART1_RX, USART1_TX连接起来了, 所以我们只需对PA10, PA9配置即可
    在这里插入图片描述

    PA9就是USART1_TX, PA10就是USART1_RX
    跳线帽将PA9和CH340的RXD, PA10和CH340的TXD连接起来了

    下面开始Cube配置+IAR编程


    3.1 操作简介

       使用异步串口通信, 分别以轮询、中断、DMA方式使用串口发送数据进行与电脑的通信。 电脑端使用串口调试助手接收单片机发送的信息


    3.2 轮询方式串口通信

    单片机会不断查询串口对应引脚, 有通信需求就进行处理, 这样比较浪费CPU资源, 前面在中断里面也讲过, 中断可以很好地弥补这个。 这里先演示轮询方式


    Step1 : Cube配置

    新建一个工程, 同时也加入LED和按键等对应引脚的配置, 用以配合串口通信

    • (1) RCC和SYS配置
      在这里插入图片描述

    • (2)USART1串口1配置
      在这里插入图片描述

    注释 :

    关于异步传送(Asynchronous)和同步传送(Synchronous)

    1、同步发送 : 发送方和接收方以同一个时钟源控制发送和接收。 就是当发送方发出数据后, 等待接收方发回响应后才发下一个数据包。

    2、异步传送 : 数据在线路上是以一个字为单位传送, 各个字符之间可以是接连传送也可以是间断传送, 这完全由发送方根据需要来决定。 发送和接收双方分别用自己的饿时钟源来控制发送和接收。   也就是说发送方发出数据后, 不等待接收方回应, 随时可以发送下一组数据

    • (3) 按键和LED引脚配置[Pinout & Configuration]
      在这里插入图片描述

       跟第二篇博客写的按键的配置一样的 点击下方蓝字快速回到第二篇博客
       第一节补充: 按键操作(CubeMX加HAL库学STM32系列)

    • (4) 时钟树配置[Clock Configuration]
      在这里插入图片描述

    • (5) 工程配置[Project Manager]
      在这里插入图片描述

    • (6) 生成代码 (Generate)
      在这里插入图片描述


    Step2 : IAR或Keil编程

    • (1) 重定向printf函数
    在学习C语言的时候, 大家肯定都用过printf这个函数, printf可以将指定字符打印到电脑的显示器上。
    但是, 单片机要使用这个就要把他打印的方向改一下, 不是打印在电脑的命令行中, 而是打印到串口里面,传输到串口调试助手. 因此我们需要重定向printf函数。
    重定向后我们要将调试信息打印到USART1中, 需要对printf所依赖的打印函数fputc()重定向

    在usart.c里面添加如下代码
    在这里插入图片描述

    #include "stdio.h"
    
    /******************************************************************
    *@brief  Retargets the C library printf  function to the USART.
    *@param  None 
    *@retval None
    ******************************************************************/
    
    #ifdef __GNUC__
    	#define PUTCHAR_PROTOTYPE int _io_putchar(int ch)
    #else 
    	#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
    #endif /* __GNUC__*/
    	
    PUTCHAR_PROTOTYPE
    {
    	HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
    	return ch;
    }
    

    上面除了重定向的代码, 还包含了一个标准库头函数, 最好加上这个, 因为printf函数就是这个库里面的, 不加的话有时候会出错或者警告

       Tips : HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF); 是通过串口1传输一个字符, ch为字符的地址, 0XFFFF表示超时时间 下面是这个函数的定义 Go to definition进入 stm32f4xx_hal_uart.c可以看这个函数定义
       关于串口通信的其他接口函数都可以在 stm32f4xx_hal_uart.h文件里面找到声明

    在这里插入图片描述

       在stm32f4xx_hal_uart.h里面的一些串口通信相关功能函数
    在这里插入图片描述

    • (2) 主函数
      由于我们CubeMX配置了串口, 所以主函数里面也自动添加了串口初始化函数
      在这里插入图片描述

      • 下面添加测试printf的代码
        在这里插入图片描述
    /* USER CODE BEGIN 3 */
    // 在while(1)里面循环扫描, 判断读取的按键引脚状态
    // 判断 WK_UP 按键是否按下  
    if (HAL_GPIO_ReadPin(WKUP_GPIO_Port, WKUP_Pin) == GPIO_PIN_SET)
    {
        HAL_Delay(10);	// 延时10ms, 做一个软件的消抖, 防止因抖动而检测到按键按下
        if (HAL_GPIO_ReadPin(WKUP_GPIO_Port, WKUP_Pin) == GPIO_PIN_SET)         // 如果确实按下了
        {
            while(HAL_GPIO_ReadPin(WKUP_GPIO_Port, WKUP_Pin) == GPIO_PIN_SET);	// 松手检测, 即当这个按键松开后才进行下面的程序, 下同
            printf("key WK_UP was pressed 
    ");
        }
    }
    
    // 判断 KEY0 按键是否按下 
    if (HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET)
    {
        HAL_Delay(10);	// 延时10ms, 软件消抖
        if (HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET)
        {
            while(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET);
            printf("key KEY0 was pressed 
    ");
        }
    }
      /* USER CODE END 3 */
    
    • (3) 编译下载
      在这里插入图片描述

      what?
      在这里插入图片描述
      在这里插入图片描述

    改错

    在主函数里面包含一个标准库即可
    #include "stdio.h"  
    

    在这里插入图片描述
    注 : 养成习惯, 代码写在规范的位置

    因为 printf是C语言标准库里面的函数, 所以我们要使用就最好加上这个, 当然不加也没事, 主要是加上比较完美

    0 error(s) , 0 warning(s)

    在这里插入图片描述

    • (4) 实际效果展示
      在这里插入图片描述

    3.3 中断方式串口通信

    操作简介 : 通过中断方式传输指定长度的数据


    Step1 : CubeMX配置

    与3.1的轮询方式配置几乎都是一样的, 只需要在串口的配置里面勾选使能串口中断即可
    先退出IAR或者Keil, 然后更改配置再重新Generate Code

    在这里插入图片描述

    Step2 : IAR或Keil编程

    (1) 在main函数外面先增加两个数组用作数据缓冲区

    在这里插入图片描述

    /* USER CODE BEGIN PV */
    uint8_t TX_Buffer[] = "
    ********** 中断方式串口通信 *********
    输入十个字符 (注:一个汉字为两个字符大小)
    ";
    uint8_t Rx_Buffer[20]; //接收数据20个字符
    
    /* USER CODE END PV */
    
    (2) main函数里面

    添加个人代码, 以及通过中断将 TX_Buffer[]里面的数据发送到串口调试助手

    并在while(1) 里面不断等待接收数据

    在这里插入图片描述

    while(1) 外面的是我们通过单片机打印到串口的, while(1)里面接收中断发送的数据并显示

    /* USER CODE BEGIN 2 */
    	printf("串口通信正常...
    
    ");
    	printf("****** Kevin_8_Lee 2020-1-2  ********
    ");
    	printf("        *****         *****         *
    ");
    	printf("      *********     *********       *
    ");
    	printf("    ************* *************     *
    ");
    	printf("   *****************************    *
    ");
    	printf("   *****************************    *
    ");
    	printf("   *****************************    *
    ");
    	printf("    ***************************     *
    ");
    	printf("      ***********************       *
    ");
    	printf("        *******************         *
    ");
    	printf("          ***************           *
    ");
    	printf("            ***********             *
    ");
    	printf("              *******               *
    ");
    	printf("                ***                 *
    ");
    	printf("                 *                  *
    ");
    	printf("*************************************
    ");
    	HAL_Delay(500); // 延时500ms, 等待下一步操作  
    	
    	/* 通过中断发送指定长度数据 */
    	HAL_UART_Transmit_IT(&huart1, (uint8_t *)TX_Buffer, sizeof(TX_Buffer));
    
      /* USER CODE END 2 */
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
      while (1)
      {
        /* USER CODE END WHILE */
    
        /* USER CODE BEGIN 3 */
        HAL_UART_Receive_IT(&huart1, (uint8_t *)Rx_Buffer, 10);
    			
      }
      /* USER CODE END 3 */
    
    (3) 再回到main函数外面

    在main函数外面添加中断回调函数

    在这里插入图片描述

    /* USER CODE BEGIN 4 */
    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
    {
        /* Prevent unused argument(s) compilation warning */
        UNUSED(huart);
        printf("
    您发送的消息为: ");		// 提示你所发送的信息
        HAL_UART_Transmit(&huart1, (uint8_t *)Rx_Buffer, 10,0xFFFF);
    }
    
    /* USER CODE END 4 */
    

    中断回调函数把串口调试助手发送的数据再发送给串口调试助手, 然后显示出来

    (4) 编译下载, 看一下实际效果

    在这里插入图片描述

    关于上述所用到的函数, 大家可以Go to definition去看一下这个函数的定义, 不懂得英文直接谷歌翻译, 问题不大

    最后, 常见问题解决办法

    • 1、串口调试助手打印不是一个心形, 而是显示的比较乱
      • 解决办法: 这个可能是由于不同的串口调试助手数据显示的方法不同导致的, 如果你用的是原子的XCOM, 那就把以上所有 这个换行符换为 我会在下面把我的串口调试助手分享出来, 可以网盘下载使用
      • 本篇博客中用的串口调试助手(2020年2月2号更新,将调试助手程序修改完善了一部分)

    链接:https://pan.baidu.com/s/1DN60ojns3Wu88frJ5pqSzA
    提取码:6exl
    复制这段内容后打开百度网盘手机App,操作更方便哦

    • 2、上位机发送的字符并未显示出来
      • 解决办法: 这个有可能是由于你没有发够十个字符, 没有触发发送功能. 指定长度传输数据时, 你的函数里面设定的几个字符就一定要发够几个字符, 否则发不出来, 发的多了只会显示一部分, 但是发的少了可能不显示

    如果自己试验的时候出现什么问题可以在博客下面评论或者私信我, 知无不言。


    最怕一生碌碌无为, 还说平凡难能可贵! 加油吧
    Author : 李光辉
    date : Thu Jan 2 20:41:56 CST 2020
    blog ID: Kevin_8_Lee
    blog site : https://blog.csdn.net/Kevin_8_Lee
  • 相关阅读:
    【leetcode】1630. Arithmetic Subarrays
    【leetcode】1629. Slowest Key
    【leetcode】1624. Largest Substring Between Two Equal Characters
    【leetcode】1620. Coordinate With Maximum Network Quality
    【leetcode】1619. Mean of Array After Removing Some Elements
    【leetcode】1609. Even Odd Tree
    【leetcode】1608. Special Array With X Elements Greater Than or Equal X
    【leetcode】1603. Design Parking System
    【leetcode】1598. Crawler Log Folder
    Java基础加强总结(三)——代理(Proxy)Java实现Ip代理池
  • 原文地址:https://www.cnblogs.com/kevin-nancy/p/12569381.html
Copyright © 2011-2022 走看看