STM32串口通信(发送与接收数据)

2024-03-01 04:20

本文主要是介绍STM32串口通信(发送与接收数据),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 前言
  • 一、介绍部分
    • 通信接口
      • 术语解释
    • 串口通信简介
    • 硬件电路
    • 电平标准
    • 串口参数
    • 串口时序
    • USART简介
      • USART框图
      • USRAT基本结构
      • 数据帧
      • 起始位检测
      • 波特率发生器
      • CH340G
  • 二、实例部分
    • 使用串口发送数据
    • 接线图
      • 代码实现
      • 重定向printf需要勾上Use MicroLIB
      • 中文不乱码方法
    • 串口的发送与接收数据
      • 线路连接与上面一致
      • 代码实现


前言

串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。本文主要接收使用串口发送接收数据,波特率设置,串口的基本时序等。


一、介绍部分

通信接口

在这里插入图片描述

术语解释

在这里插入图片描述

串口通信简介

在这里插入图片描述

硬件电路

在这里插入图片描述

电平标准

在这里插入图片描述

串口参数

在这里插入图片描述

串口时序

在这里插入图片描述

USART简介

在这里插入图片描述

USART框图

在这里插入图片描述

USRAT基本结构

在这里插入图片描述

数据帧

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

起始位检测

在受到噪声影响后,采用2:1策略,选择更多的作为所接收到的数据,并使噪声标志位NE置1

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

波特率发生器

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

CH340G

在这里插入图片描述

二、实例部分

使用USART1来作为例子,根据引脚定义,选择正确的接口
在这里插入图片描述

使用串口发送数据

接线图

在这里插入图片描述

代码实现

配置串口Serial.c

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>void Serial_Init(void){// 开启时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);// 初始化引脚,发送数据引脚GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;		// 复用推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;	// A9GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度GPIO_Init(GPIOA, &GPIO_InitStructure);// 初始化串口配置USART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate = 9600; // 串口波特率USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 不使用流控USART_InitStructure.USART_Mode = USART_Mode_Tx; // 串口模式,发送USART_InitStructure.USART_Parity = USART_Parity_No; // 无校验USART_InitStructure.USART_StopBits = USART_StopBits_1; // 选择一位停止位USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 不需要校验位,八位字长USART_Init(USART1,&USART_InitStructure);// USART1使能USART_Cmd(USART1,ENABLE);
}// 发送函数
void USART_SendByte(uint8_t Byte){USART_SendData(USART1,Byte);// 等待写入完成,写入完成之后会将标志位自动清0while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}// 发送数组函数
void USART_SendArray(uint8_t *Array,uint16_t Length){uint8_t i = 0;for(i=0;i<Length;i++){USART_SendData(USART1,Array[i]);// 等待写入完成,写入完成之后会将标志位自动清0while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);}
}// 发送字符串函数
void USART_SendString(uint8_t *String){uint8_t i = 0;for(i=0;String[i]!='\0';i++){USART_SendData(USART1,String[i]);// 等待写入完成,写入完成之后会将标志位自动清0while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);}
}// 返回X的Y次方
uint32_t Serial_Pow(uint32_t X,uint32_t Y){uint32_t Result = 1;while(Y--){Result *= X;}return Result;
}
// 发送数字函数
void USART_SendNum(uint32_t Num,uint16_t Length){uint8_t i = 0;for(i=0;i<Length;i++){USART_SendByte(Num / Serial_Pow(10,Length-i-1) % 10 + 0x30);// 等待写入完成,写入完成之后会将标志位自动清0while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);}
}//重定向fputc函数,fputc是printf函数的底层,printf通过不停的调用fputc来达到输出的效果
//重定向到串口
int fputc(int ch,FILE *f){USART_SendByte(ch);return ch;
}// 封装使用sprintf输出到串口
void Serial_Printf(char *format, ...)
{char String[100];va_list arg;							// 可变参数列表va_start(arg, format);		// 从format开始接收可变参数vsprintf(String, format, arg);va_end(arg);USART_SendString((uint8_t*)String);
}

主函数main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"int main(void)
{OLED_Init();Serial_Init();//USART_SendByte();
//	uint8_t Array[] = {0x41,0x42,0x43,0x44};
//	USART_SendArray(Array,4);
//	uint8_t String[] = {"hello world"};
//	USART_SendString(String);
//	USART_SendNum((uint32_t)12345,5);
//	printf("Num = %d\r\n",666);
//	char String[100];
//	sprintf(String,"Num = %d\r\n",666);
//	USART_SendString((uint8_t*)String);Serial_Printf("一程山水");while (1){}
}

重定向printf需要勾上Use MicroLIB

在这里插入图片描述

中文不乱码方法

  1. 代码与串口都使用utf8格式,并在如下图位置加上–no-multibyte-chars
  2. 使用GB2312支持中文编码格式,串口使用GBK编码格式接收即可。

串口的发送与接收数据

线路连接与上面一致

代码实现

串口配置Serial.c

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>uint8_t RxData;
uint8_t RxFlag;void Serial_Init(void){// 开启时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);// 初始化引脚GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;		// 复用推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;	// A9 发送数据GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;		// 上拉输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;	// A10 接收数据GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度GPIO_Init(GPIOA, &GPIO_InitStructure);// 初始化串口配置USART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate = 9600; // 串口波特率USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 不使用流控USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 串口模式,发送+接收USART_InitStructure.USART_Parity = USART_Parity_No; // 无校验USART_InitStructure.USART_StopBits = USART_StopBits_1; // 选择一位停止位USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 不需要校验位,八位字长USART_Init(USART1,&USART_InitStructure);// 开启中断USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//初始化NVICNVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	// 分组NVIC_InitTypeDef NVIC_InitStructure;// 中断通道NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;// 中断通道使能NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;// 抢占优先级NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;// 响应优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);// USART1使能USART_Cmd(USART1,ENABLE);
}// 发送函数
void USART_SendByte(uint8_t Byte){USART_SendData(USART1,Byte);// 等待写入完成,写入完成之后会将标志位自动清0while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}// 发送数组函数
void USART_SendArray(uint8_t *Array,uint16_t Length){uint8_t i = 0;for(i=0;i<Length;i++){USART_SendData(USART1,Array[i]);// 等待写入完成,写入完成之后会将标志位自动清0while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);}
}// 发送字符串函数
void USART_SendString(uint8_t *String){uint8_t i = 0;for(i=0;String[i]!='\0';i++){USART_SendData(USART1,String[i]);// 等待写入完成,写入完成之后会将标志位自动清0while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);}
}// 返回X的Y次方
uint32_t Serial_Pow(uint32_t X,uint32_t Y){uint32_t Result = 1;while(Y--){Result *= X;}return Result;
}
// 发送数字函数
void USART_SendNum(uint32_t Num,uint16_t Length){uint8_t i = 0;for(i=0;i<Length;i++){USART_SendByte(Num / Serial_Pow(10,Length-i-1) % 10 + 0x30);// 等待写入完成,写入完成之后会将标志位自动清0while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);}
}//重定向fputc函数,fputc是printf函数的底层,printf通过不停的调用fputc来达到输出的效果
//重定向到串口
int fputc(int ch,FILE *f){USART_SendByte(ch);return ch;
}// 封装使用sprintf输出到串口
void Serial_Printf(char *format, ...)
{char String[100];va_list arg;							// 可变参数列表va_start(arg, format);		// 从format开始接收可变参数vsprintf(String, format, arg);va_end(arg);USART_SendString((uint8_t*)String);
}// 获取RxFlag
uint8_t USART_GetRxFlag(void){if(RxFlag == 1){RxFlag = 0;return 1;}return 0;
}// 获取RxData
uint8_t USART_GetRxData(void){return RxData;
}//中断函数
void USART1_IRQHandler(void){if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET){RxData = USART_ReceiveData(USART1);RxFlag = 1;USART_ClearITPendingBit(USART1,USART_IT_RXNE);}
}

主函数main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"uint8_t Serial_RxData;int main(void)
{OLED_Init();OLED_ShowString(1, 1, "RxData:");Serial_Init();while (1){if (USART_GetRxFlag() == 1){Serial_RxData = USART_GetRxData();USART_SendByte(Serial_RxData);OLED_ShowHexNum(1, 8, Serial_RxData, 2);}}
}

这篇关于STM32串口通信(发送与接收数据)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/761198

相关文章

如何使用C#串口通讯实现数据的发送和接收

《如何使用C#串口通讯实现数据的发送和接收》本文详细介绍了如何使用C#实现基于串口通讯的数据发送和接收,通过SerialPort类,我们可以轻松实现串口通讯,并结合事件机制实现数据的传递和处理,感兴趣... 目录1. 概述2. 关键技术点2.1 SerialPort类2.2 异步接收数据2.3 数据解析2.

Windows server服务器使用blat命令行发送邮件

《Windowsserver服务器使用blat命令行发送邮件》在linux平台的命令行下可以使用mail命令来发送邮件,windows平台没有内置的命令,但可以使用开源的blat,其官方主页为ht... 目录下载blatBAT命令行示例备注总结在linux平台的命令行下可以使用mail命令来发送邮件,Win

使用Java发送邮件到QQ邮箱的完整指南

《使用Java发送邮件到QQ邮箱的完整指南》在现代软件开发中,邮件发送功能是一个常见的需求,无论是用户注册验证、密码重置,还是系统通知,邮件都是一种重要的通信方式,本文将详细介绍如何使用Java编写程... 目录引言1. 准备工作1.1 获取QQ邮箱的SMTP授权码1.2 添加JavaMail依赖2. 实现

Qt实现发送HTTP请求的示例详解

《Qt实现发送HTTP请求的示例详解》这篇文章主要为大家详细介绍了如何通过Qt实现发送HTTP请求,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、添加network模块2、包含改头文件3、创建网络访问管理器4、创建接口5、创建网络请求对象6、创建一个回复对

Java中Springboot集成Kafka实现消息发送和接收功能

《Java中Springboot集成Kafka实现消息发送和接收功能》Kafka是一个高吞吐量的分布式发布-订阅消息系统,主要用于处理大规模数据流,它由生产者、消费者、主题、分区和代理等组件构成,Ka... 目录一、Kafka 简介二、Kafka 功能三、POM依赖四、配置文件五、生产者六、消费者一、Kaf

Python手搓邮件发送客户端

《Python手搓邮件发送客户端》这篇文章主要为大家详细介绍了如何使用Python手搓邮件发送客户端,支持发送邮件,附件,定时发送以及个性化邮件正文,感兴趣的可以了解下... 目录1. 简介2.主要功能2.1.邮件发送功能2.2.个性签名功能2.3.定时发送功能2. 4.附件管理2.5.配置加载功能2.6.

解决Cron定时任务中Pytest脚本无法发送邮件的问题

《解决Cron定时任务中Pytest脚本无法发送邮件的问题》文章探讨解决在Cron定时任务中运行Pytest脚本时邮件发送失败的问题,先优化环境变量,再检查Pytest邮件配置,接着配置文件确保SMT... 目录引言1. 环境变量优化:确保Cron任务可以正确执行解决方案:1.1. 创建一个脚本1.2. 修

Django中使用SMTP实现邮件发送功能

《Django中使用SMTP实现邮件发送功能》在Django中使用SMTP发送邮件是一个常见的需求,通常用于发送用户注册确认邮件、密码重置邮件等,下面我们来看看如何在Django中配置S... 目录1. 配置 Django 项目以使用 SMTP2. 创建 Django 应用3. 添加应用到项目设置4. 创建

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2