STM32CubeMX系列|串口通讯

2023-05-16

串口通讯

1. 串口简介

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

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

在这里插入图片描述

  • 串口通讯过程

在这里插入图片描述

2. 硬件设计

本实验通过CH340芯片把STM32F1的串口1与PC的USB口进行连接,实现串口连接。串口通讯需要将数据收发管脚交叉连接,电路中的其他部分是自动下载电路部分,目的是控制BOOT的启动模式与复位
在这里插入图片描述

3. 软件设计

3.1 STM32CubeMX设置
  • RCC设置外接HSE,时钟设置为72M
  • PC0设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
  • USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位

在这里插入图片描述

  • 若使用中断通讯方式,还需要开启串口中断

在这里插入图片描述

  • 若使用直接内存存取(DMA)方式,除以上步骤外(串口中断要开启,否则程序只能发送一次数据,且不能判断DMA传输是否完成,USART一直处于busy状态)还需要设置DMA传输方向、通道、优先级、数据长度以及指针递增与否

在这里插入图片描述

  • 输入工程名,选择工程路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码
3.2 MDK-ARM软件编程
  • 轮询方式
/*****usart.c文件中的UART初始化函数以及IO口配置函数*****/
void MX_USART1_UART_Init(void){
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK){
    Error_Handler();
  }
}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle){
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1){
  /* USER CODE BEGIN USART1_MspInit 0 */
  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration    
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX*/
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  /* USER CODE BEGIN USART1_MspInit 1 */
  /* USER CODE END USART1_MspInit 1 */
  }
}

C语言中的标准库中所用的标准输出函数,默认的输出设备是显示屏,要实现串口或LCD的输出,必须重新定义标准库函数里与输出函数相关的函数,例如printf输出到串口,需要将fputc函数里面的输出指向串口(重定向)

/*****在usart.c中添加如下函数*****/
int fputc(int ch, FILE *f){
	HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
	return ch;
}
/*****main.c文件中编写相关代码*****/
while (1){
    HAL_UART_Transmit(&huart1,"HAL_UART_Transmit Test...",25,0xffff);
    printf("\r\n printf test...\r\n");
    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
	HAL_Delay(1000);
    /* USER CODE END WHILE */
}
  • 中断方式
/*****usart.c文件中的UART初始化函数以及IO口配置函数*****/
void MX_USART1_UART_Init(void){
	//....该函数与轮询方式的UART初始化函数相同....
}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle){
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1){
  /* USER CODE BEGIN USART1_MspInit 0 */
  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration    
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX*/
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspInit 1 */
  /* USER CODE END USART1_MspInit 1 */
  }
}

找到弱符号中断接收完成回调函数原型,并在usart.c中自定义该回调函数
__weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
	if(huart->Instance == USART1){
		HAL_UART_Transmit(&huart1,RxMsg,10,0xffff);	//将接收的数据通过串口1发送回去
		HAL_UART_Receive_IT(&huart1,RxMsg,10);		//再次开启接收中断
	}
}
/*****main.c文件中编写相关代码*****/
/* USER CODE BEGIN PV */
uint8_t TxMsg[] = "\r\n*****USART communication based on IT*****\r\n";
uint8_t RxMsg[20];
/* USER CODE END PV */
/* USER CODE BEGIN 2 */
	HAL_UART_Transmit_IT(&huart1,TxMsg,sizeof(TxMsg));
	HAL_UART_Receive_IT(&huart1,RxMsg,10);
/* USER CODE END 2 */
while (1){
    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
	HAL_Delay(1000);
    /* USER CODE END WHILE */
}
  • DMA方式
/*****dma.c文件中的DMA初始化函数*****/
void MX_DMA_Init(void) {
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();
  /* DMA interrupt init */
  /* DMA1_Channel4_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
  /* DMA1_Channel5_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
}
/*****usart.c文件中的UART初始化函数以及IO口和DMA配置函数*****/
void MX_USART1_UART_Init(void){
	//....该函数与轮询方式的UART初始化函数相同....
}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle){
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1){
  /* USER CODE BEGIN USART1_MspInit 0 */
  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration    
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX */
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    /* USART1 DMA Init */
    /* USART1_RX Init */
    hdma_usart1_rx.Instance = DMA1_Channel5;
    hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_rx.Init.Mode = DMA_NORMAL;
    hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK){
      Error_Handler();
    }

    __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx);
    /* USART1_TX Init */
    hdma_usart1_tx.Instance = DMA1_Channel4;
    hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_tx.Init.Mode = DMA_NORMAL;
    hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK){
      Error_Handler();
    }

    __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);
    /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspInit 1 */
  /* USER CODE END USART1_MspInit 1 */
  }
}
/*****main.c文件中编写相关代码*****/
/* USER CODE BEGIN PV */
uint8_t TxMsg[] = "\r\n*****USART communication based on DMA*****\r\n";
/* USER CODE END PV */
while (1){
    HAL_UART_Transmit_DMA(&huart1,TxMsg,sizeof(TxMsg));
    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
	HAL_Delay(1000);
    /* USER CODE END WHILE */
}

4. 下载验证

  • 轮询方式

在这里插入图片描述

  • 串口中断:使用串口助手发送10个字符,串口助手回显发送的数据;串口要发够10个字符才会触发中断;超过10个字符,串口只会发送10个字符(注意不要勾选‘发送新行’)

在这里插入图片描述

  • DMA方式

在这里插入图片描述

关注我的公众号,在公众号里发如下消息,即可获取相应的工程源代码:

玩转STM32CubeMX | 串口通讯

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32CubeMX系列|串口通讯 的相关文章

  • STM32CubeMx+freeRTOS的使用

    目录 第一步 xff0c 利用CubeMx创建工程并修改一些必要设置 第二步 xff0c 测试LED灯和HAL库延时 第三步 xff0c 选择和配置freeRTOS选项 3 1 选择RTOSV1版本 3 2 配置内核参数 3 3 设置Tas
  • c++ 调用python clion mac_用clion自带的嵌入式开发功能和stm32cubeMX开发stm32!!!

    起因 因为keil的难用 以前开发stm32 我都是使用stm32cube生成了项目文件之后 用clion编辑 然后用keil编译下载加Debug 说实话 整体感觉还不错 但总感觉怪怪的 也曾尝试过SW4STM32和TrueStudio等
  • STM32CubeMX介绍、下载与安装

    推荐 分享一个大神的人工智能教程 零基础 xff01 通俗易懂 xff01 风趣幽默 xff01 还带黄段子 xff01 希望你也加入到人工智能的队伍中来 xff01 http www captainbed net strongerhuan
  • 使用 Keil uVision 和 STM32CubeMX 对 STM32F103C8 进行编程

    采用ARM Cortex M架构的STM32微控制器因其特性 成本和性能而在许多应用中得到广泛应用 在之前的教程中 xff0c 我们已经使用Arduino IDE编程了STM32F103C8 使用Arduino IDE编程STM32很简单
  • 用Stm32CubeMX在STM32F107上移植LWIP(PHY:DM9161A)

    背景 有一块吃灰7年的神州IV号开发板 xff0c 主控芯片STM32F107VCT6 xff0c PHY芯片DM9161A xff0c 配套的资料都是当年ST的标准库 这个开发板应该是因为当年上市太匆忙 xff0c 资料和代码的细节部分做
  • ros串口通讯(读取串口数据)

    ros串口通讯是非常重要的通讯手段 xff0c 通常跟下位机或者各种usb口外设都是通过串口进行通讯的 那么我们跟着教程来学习一下如何读取手机通过无线串口发送给电脑的数据 这里我通过一个usb ttl工具将蓝牙连接到电脑上 xff0c 然后
  • stm32cubeMX+FreeRTOS(4)—— main函数while循环

    0 发现 想在主函数中打印一下串口数据 xff0c 发现一直打印不出来 xff0c 试了下开关小灯 xff0c 发现没有进main函数的while循环 xff0c 阿西吧 xff0c 我大概要重新看一下CubeMX的rtos架构了 本来打算
  • STM32CubeMX驱动4x4键盘模块

    文章目录 1 4x4键盘模块简介2 4x4键盘模块原理2 1 独立按键的原理2 2 矩阵键盘的原理 3 移植源码到工程4 实验 1 4x4键盘模块简介 4x4键盘模块是一种常用的电子组件 xff0c 它由16个按钮或开关以矩阵方式排列而成
  • STM32CubeMX安装

    一 STM32CubeMX下载 官网地址 xff1a STM32CubeMX STM32Cube初始化代码生成器 意法半导体STMicroelectronics 官网下载需要注册账号 网盘链接 xff08 6 8 xff09 xff1a 链
  • micropython中断优先级_stm32cubemx 配置freertos中断优先级

    stm32cubeMx 直接集成freertos xff0c 可以不需要自己手动移植只需要把freertos的选项勾选就可以 但是生成的代码工程中 xff0c freertos暴露给用户的API接口并不是原生的freertos接口 xff0
  • STM32CubeMX在FreeRTOS下使用串口进行数据收发(不定长度)

    STM32CubeMX gt FreeRTOS 43 USART接收不定长数据 由于本人做的一个项目功能相对复杂 xff0c 要求使用操作系统 xff0c 且项目工程中有很多需要串口操作的外设 xff0c 所以需要对串口设计不定长的收发功能
  • STM32CubeMX在F103上的ADC注入通道配置异常问题

    前言 最近业余时间在搞无刷电机FOC的控制 xff0c 其中有一部分是关于流过电机三相绕组电流采集的 xff0c 需要用到STM32内置的ADC xff0c 核心是需要使用注入通道以确保ADC数据采集的实时性 xff0c 但是我在STM32
  • STM32cubeMX将STM32F767+LAN8720+LwIP+FreeRTOS的以太网实现

    通过STM32cubeMX将STM32F767 43 LAN8720 43 LwIP 43 FreeRTOS的以太网实现 本文使用了正点原子的阿波罗开发板 xff0c 接下来我将粗略的对STM32F767通过STM32cubeMX进行以太网
  • STM32CubeMX配置串口DMA传输实现不定长数据收发

    串口简介 串口是全双工的串行通信协议 串口通信指串口按位 xff08 bit xff09 发送和接收字节 xff08 一个字节有8位 xff09 尽管比特字节 xff08 byte xff09 的串行通信慢 xff0c 但是串口可以在使用一
  • 【STM32】串口通讯USART串口中断配置

    目录 STM32 USART 简介 程序编写 硬件接线 实际波形 STM32 USART 简介 STM32的USART通用同步异步收发器是一个串行通信设备 xff0c 可以灵活的与外部设备进行全双工数据交换 有别于USART xff0c 还
  • STM32CubeMX串口USART中断发送接收数据

    本文代码使用 HAL 库 文章目录 前言一 中断控制二 USART中断使用1 中断优先级设置 xff1a 2 使能中断3 使能UART的发送 接收中断4 中断收发函数5 中断处理函数6 中断收发回调函数 三 串口中断实验串口中断发送数据点亮
  • 基于STM32的串口通讯

    基于STM32的串口通讯 设备之间通信的方式 串行通信一般是以帧格式传输数据 xff0c 即一帧一帧的传输 xff0c 每一帧都含有起始信号 xff0c 数据信息以及停止信息等 并行通信 数据各个位同时传输 xff0c 速度快 xff0c
  • 《STM32单片机开发应用教程(HAL库版)—基于国信长天嵌入式竞赛实训平台(CT117E-M4)》第四章4.8 TIM---PWM输出实验

    写在前面 STM32单片机开发应用教程 HAL库版 基于国信长天嵌入式竞赛实训平台 CT117E M4 第四章4 8 TIM PWM输出实验 讲解TIM 定时与PWM输出的STM32CubeMX配置和程序设计方法 官方例程下载 https
  • 使用STM32CubeMX生成源码工程后,使用ST-LINK下载出现问题的解决方法

    第一次使用STM32CubeMX生成源码工程文件 各种时钟引脚资源配置好后 点击生成了Keil的工程 编译通过 连接ST LINK下载程序 第一次下载 一切正常 然后修改了一下程序 再次下载 出现找不到设备的提示 以为板子出了问题 又拿过来
  • STM32CubeMX学习六 之ADC配置

    文章目录 前言 一 本地环境 二 开始 1 定时器配置 2 引脚配置 在这里插入图片描述 https img blog csdnimg cn e5b6f155a1b8468cb15046a0a9d031cd png 3 内部时钟配置 4 A

随机推荐