STM32串口通信入门

news2024/11/30 14:46:56

文章目录

  • 一、串口协议和RS-232标准,以及RS232电平与TTL电平的区别
    • 1.串口通信协议
    • 2.RS-232标准
    • 3.RS232电平与TTL电平的区别
    • 4.USB/TTL转232“模块(CH340芯片为例)
  • 二、补充实验
    • (一)几个常见的库函数、结构体
      • 1.时钟配置函数
      • 2.GPIO口的初始化类型定义结构体
      • 3.GPIO口的类型定义结构体
      • 4.GPIO口的初始化函数
    • (二)实验
      • 1.标准库实现LED灯闪烁
        • (1)代码
        • (2)Proteus仿真
        • (3)实验现象
      • 2.标准库实现LED流水灯
        • (1)代码
        • (2)Proteus仿真
        • (3)实验现象
      • 3.用STM32发送数据,并用串口助手接收
        • (1)代码
        • (2)串口助手接收
      • 4.串口查询方式点亮LED灯
        • (1)代码
        • (2)实验现象
  • 三、keil波形
      • 1.配置合适的Xtal(External Crystal Oscillator)外部晶振
      • 2.输入正确的芯片参数
      • 3.进入波形仿真界面
      • 4.仿真波形
  • 四、心得体会

一、串口协议和RS-232标准,以及RS232电平与TTL电平的区别

1.串口通信协议

是一种数据传输协议,常用于计算机和其他设备之间的通信。
它定义了数据传输的规则,如数据格式、传输速率等。

2.RS-232标准

是一种标准的串口通信协议。
定义了数据传输的电压范围、信号线功能、连接方式和传输速率等
RS-232 标准主要规定了信号的用途,通讯接口以及信号的电平标准。

由于RS-232电平标准的信号不能直接被控制器直接识别,所以这些信号会经过一个“电平转换芯片”转换成控制器能识别的“TTL校准”的电平信号,才能实现通讯。

3.RS232电平与TTL电平的区别

根据通讯使用的电平标准不同,串口通讯可分为 TTL标准和 RS-232标准。

在这里插入图片描述

从表中可以看出,逻辑电压不同,在电子电路中常使用 TTL 的电平标准,理想状态下,使用 5V 表示二进制逻辑 1,使用 0V 表示逻辑 0;而为了增加串口通讯的远距离传输及抗干扰能力,它使用-15V表示逻辑 1,+15V 表示逻辑 0。

4.USB/TTL转232“模块(CH340芯片为例)

USB主机检测到USB转串口设备插入后,首先会对设备复位,然后开始USB枚举过程。USB枚举时过程会获取设备描述符、配置描述符、接口描述符等。描述符中会包含USB设备的厂商ID,设备ID和Class类别等信息。操作系统会根据该信息为设备匹配相应的USB设备驱动。
USB虚拟串口的实现在系统上依赖于USB转串口驱动,一般由厂家直接提供,也可以使用操作系统自带的CDC类串口驱动等。驱动主要分为2个功能,其一注册USB设备驱动,完成对USB设备的控制与数据通讯,其二注册串口驱动,为串口应用层提供相应的实现方法。

二、补充实验

在上一次寄存器方式点亮LED灯的基础上,改用标准库方式,完成LED的点灯或流水灯实验。

(一)几个常见的库函数、结构体

1.时钟配置函数

APB2外设时钟控制命令函数
定义
在这里插入图片描述

通俗易懂地解释一下参数的含义:
①uint32_t RCC_APB2Periph:要求参数应当是一个无符号的32位整形数,然而在实际调用过程中,它传入的参数是经过“位掩码”技术处理过的RCC_APB2Periph_GPIOA、等外设名称。说直白点就是RCC_APB2Periph_GPIOA代码的就是一个无符号的32位整形数。这样调用起来会更加方便。
②FunctionalState NewState:参数类型名为函数状态,只有两个值可供传入。ENABLE-时钟开启,DISABLE-时钟关闭。

2.GPIO口的初始化类型定义结构体

GPIO口的初始化类型定义结构体定义
定义
在这里插入图片描述
解释一下成员属性
①uint16_t GPIO_Pin:应该也是采用了位掩码的方式,赋的值可以直接传入引脚号码如:GPIO_Pin_3,而不是整形数据。
②GPIOSpeed_TypeDef GPIO_Speed:赋的值如:GPIO_Speed_50MHz,在GPIO_Speed后面加一个下划线和具体的数值。(这部分传入的参数或赋的值都是以这种形式。在实际操作时,可以先列出他的属性,GPIO_InitStructure.GPIO_Speed=,再复制粘贴GPIO_Speed,再按ctrl+alt+空格,进行操作提示。)
③GPIOMode_TypeDef GPIO_Mode:赋的值如GPIO_Mode_Out_PP。
即类型定义结构体的三板斧是引脚号码、速度和输入输出模式。

3.GPIO口的类型定义结构体

定义
在这里插入图片描述

4.GPIO口的初始化函数

①定义
在这里插入图片描述
②参数实例

在这里插入图片描述

定义太复杂了,在这里简单解释一下:就是将初始化结构体的地址和结构体地址综合起来。GPIOx参数指定了目标GPIO端口的引脚名称(是GPIOA,GPIOB还是GPIOC…),而GPIO_InitStruct则提供了是它已初始好的三个成员属性。
即第一个GPIO口的类型定义结构体参数传入的是A、B、C…的哪种类型的引脚,而第二个GPIO口的初始化类型定义结构体参数提供的是它的已配置好的成员属性。
待会GPIO_WriteBit(GPIO_TypeDef GPIOx, uint16_t GPIO_Pin, BitAction B)等函数调用的时候两者都要用。

(二)实验

1.标准库实现LED灯闪烁

(1)代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int main()
	
{	
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启外设GPIOA的时钟
	
	GPIO_InitTypeDef GPIO_InitStructure;   				//调用库函数的中封装好的具体引脚结构体
	
	//分别给结构体的三个成员属性赋初值
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; 		//配置端口为推挽输出模式
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;             //启用0号端口
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;     //端口输出速度为50MHz
	
	GPIO_Init(GPIOA, &GPIO_InitStructure);    //GPIOA的0号口配置完成,准备调试它的高低电平。

	
	while(1)
	{
		GPIO_ResetBits(GPIOA,GPIO_Pin_0);   //设置A0端口为低电平
		Delay_s(1);
		GPIO_SetBits(GPIOA,GPIO_Pin_0);		//设置A0端口为高电平
		Delay_s(1);
	}
}

(2)Proteus仿真

注意:
在这里插入图片描述
得将外时钟频率设置为70Mhz,时钟比例设置为8倍。

在这里插入图片描述

(3)实验现象

2024_05_09_001

2.标准库实现LED流水灯

(1)代码

在这里插入图片描述

(2)Proteus仿真

在这里插入图片描述

(3)实验现象

20240509_002

3.用STM32发送数据,并用串口助手接收

(1)代码

①main.c文件

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Serial.h"

int main()
{	
			Serial_Init();	
			char String[]="hello windons!\r\n";
	
	while(1)
	{
			
			Serial_SendString(String);
			Delay_s(1);              						  						//间隔1s发送
		
	}
}

②Serial.c文件

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>


void Serial_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);	//打开USART1外设的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);	//因为要用到GPIOA引脚,所以打开GPIOA的时钟


	GPIO_InitTypeDef GPIO_InitStructure;  					//用自带的通用输出口结构体,实例化了一个结构体变量

	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;  			//数据发送,选择复用推挽输出模式
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

	GPIO_Init(GPIOA,&GPIO_InitStructure);					//配置好引脚输入输出模式


	USART_InitTypeDef USART_InitStructure;

	//引出该结构体的所有属性,进行赋值。
	USART_InitStructure.USART_BaudRate=9600;          									//波特率
	USART_InitStructure.USART_WordLength=USART_WordLength_8b;         					//不需要校验选择8bit的字长,如果需要一位奇偶校验位,则选择9bit的字长
	USART_InitStructure.USART_StopBits=USART_StopBits_1;         						//选择一位停止位。
	USART_InitStructure.USART_Parity=USART_Parity_No;                      				//奇偶性:奇偶校验,选择不校验。odd是奇校验,even是偶校验。
	USART_InitStructure.USART_Mode=USART_Mode_Tx;           							//选择发送模式 
	USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None; 		//硬件流控制:选择无流控制


	USART_Init(USART1,&USART_InitStructure);					//配置好USART1外设的模式

	USART_Cmd(USART1,ENABLE);									//使能USART1,串口开始运行。第一个参数是要操作的USART外设,第二个参数是指定是否使能该外设
}



void Serial_SendByte(uint8_t Byte)     //int8_t代表字符型
{
	USART_SendData(USART1,Byte);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET)  //USART_GetFlagStatus(USART1,USART_FLAG_TXE)这个函数的返回值先简单地理解为:数据已经发送了,返回SET;数据还没有发送,返回RESET。
	{
		;
	}
}


void Serial_SendString(char *String)				//发送一个字符数组
{

	uint8_t i;
	for(i=0;String[i]!='\0';i++)
	{
		Serial_SendByte(String[i]);
	}
}

(2)串口助手接收

在这里插入图片描述

4.串口查询方式点亮LED灯

(1)代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "LED.h"
#include <string.h>

uint8_t Rdata;


int main()
{
	LED_Init();			//LED初始化
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);	//因为要用到GPIOA引脚,所以打开GPIOA的时钟
	GPIO_InitTypeDef GPIO_InitStructure;  					//用自带的通用输出口结构体,实例化了一个结构体变量

	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;  			//数据发送,选择复用推挽输出模式
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

	GPIO_Init(GPIOA,&GPIO_InitStructure);					//配置好引脚输入输出模式

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);	//打开USART1外设的时钟
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;  			//数据接收,选择上拉输入模式
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

	GPIO_Init (GPIOA,&GPIO_InitStructure);					//配置好引脚输入输出模式
	
	

	USART_InitTypeDef USART_InitStructure;

	//引出该结构体的所有属性,进行赋值。
	USART_InitStructure.USART_BaudRate=9600;          																		//波特率
	USART_InitStructure.USART_WordLength=USART_WordLength_8b;         									//不需要校验选择8bit的字长,如果需要一位奇偶校验位,则选择9bit的字长
	USART_InitStructure.USART_StopBits=USART_StopBits_1;         													//选择一位停止位。
	USART_InitStructure.USART_Parity=USART_Parity_No;                      											//奇偶性:奇偶校验,选择不校验。odd是奇校验,even是偶校验。
	USART_InitStructure.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;           							//选择发送和接收模式 
	USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None; 		//硬件流控制:选择无流控制


	USART_Init(USART1,&USART_InitStructure);					//配置好USART1外设的模式
	USART_Cmd (USART1,ENABLE);									//使能USART1,串口开始运行。第一个参数是要操作的USART外设,第二个参数是指定是否使能该外设
	

	while (1)
	{
		while (	USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
		Rdata = USART_ReceiveData(USART1);
		if (Rdata == '1')
		{
			LED1_ON();
		}
		if (Rdata == '0')
		{
			LED1_OFF();
		}
		while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//USART_GetFlagStatus(USART1,USART_FLAG_TXE)这个函数的返回值先简单地理解为:数据已经发送了,返回SET;数据还没有发送,返回RESET。
		
	}
}

(2)实验现象

20240512_02

三、keil波形

1.配置合适的Xtal(External Crystal Oscillator)外部晶振

在这里插入图片描述

2.输入正确的芯片参数

在这里插入图片描述

3.进入波形仿真界面

在这里插入图片描述

这里第四步输入对应的波形源要重点强调。
在这里我配置的是PA1和PA9引脚,那么创建波形源的时候就分别输入:PORTA.1和PORTA.9即可。如果你按上述输入了,报错。

在这里插入图片描述
那么说明你步骤2的四个参数,没有配置正确,请按步骤2的要求重新配置。

4.仿真波形

在这里插入图片描述
在我实验(二)3.用STM32发送数据,并用串口助手接收代码中,PA9口的波形应该是起伏变化的,PA1时不变的。在我实验(二)4.串口查询方式点亮LED灯中,PA1应该是起伏变化的。但是我的两个实验的波形都如上图所示,我也想了许多办法去改进,但都败不旋踵。我估计应该是晶振的问题,我也改了晶振的值但仍得不到波形。这确实很奇怪,因为我的实验现象是正确的,波形仿真却有问题。还望大佬能够不吝赐教,进行指证。

四、心得体会

串口通信是单片机学习十分必不可少的一环,它关系着单片机之间的数据能否顺利的发送和接收,实现机器与机器的数据交换与数据共享。
在本节使用STM32F103C8T6的串口通信时,我主要遇到了两个问题。
问题1:我犯了一个致命的错误就是在连接USART1的引脚时,将发送数据引脚P9连接到了转串口模块的TXD上,将接收数据P10连接到了RXD上。即单片机发送端连接到了电脑发送端,单片机接收端连接到了电脑接收端。导致我浪费了一个下午的时间,去怀疑并验证STM芯片是不是坏了、转串口模块是否坏了、引脚是否坏了…这对于初学者来说确实是一个极其容易犯错的步骤。
问题2:我的实验现象是正确的,但是得不到波形,波形一直保持低电平不变。这一点希望阅读本文章的大佬能够指正一下。
总的来说,串口通信的学习,和前面点亮小灯泡的实验具有很多相似之处,都要进行时钟的配置,初始化结构体的实例化,并用初始化结构体进行输入输出模式的配置。这在代码中的体现是十分直观的。但是,串口模块的学习难度,还是要大一点,因为它涉及的是双向数据的传输,还要合理展示,并且它和很多STM32学习模块密切相关,例如:中断、OLED显示屏…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1667733.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode—用队列实现栈

一.题目 二.思路 1.后入先出的实现&#xff1a; 创建两个队列来实现栈&#xff08;后入先出&#xff09;&#xff1a; 两个队列&#xff0c;保持一个存数据&#xff0c;另一个为空&#xff0c;入数据&#xff08;push&#xff09;要入不为空的队列&#xff0c;&#xff08;p…

深圳晶彩智能ESP32-1732S019实时观看GPIO的状态

深圳晶彩智能ESP32-1732S019介绍 ESP32-1732S019开发板是基于ESP32-S3-WROOM-1模块作为主控&#xff0c;双核MCU ,集成WI-FI和蓝牙功能&#xff0c;主控频率可达240MHz , 512KB SRAM , 384KB ROM&#xff0c;8M PSRAM&#xff0c;16MB Flash&#xff0c;显示分辨率为170*320 I…

冯喜运:5.12黄金回撤继续上涨,下周原油走势分析

【黄金消息面分析】&#xff1a;本周&#xff0c;黄金市场迎来了自4月中旬以来的最佳单周表现。周五&#xff08;3月9日&#xff09;&#xff0c;金价攀升至2360.54美元/盎司&#xff0c;涨幅0.62%&#xff0c;而纽约商品交易所6月交割的黄金期货价格上涨1.5%&#xff0c;收报2…

Springboot+Vue项目-基于Java+MySQL的毕业就业信息管理系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

其他的 框架安全:Apache Shiro 漏洞序列.(CVE-2016-2807)

什么是 Apache Shiro Apache Shiro 是一个强大且易用的Java安全框架&#xff0c;它为应用程序提供了身份验证、授权、加密和会话管理等常见的安全功能。漏洞大多会发生在登录处&#xff0c;返回包里包含remeberMedeleteMe字段.&#xff08; Shiro 这个属于第三方的&#xff0c…

表的创建与操作表

1. 创建表 创建表有两种方式 : 一种是白手起家自己添&#xff0c;一种是富二代直接继承. 2. 创建方式1 (1). 必须具备条件 CREATE TABLE权限存储空间 (2). 语法格式 CREATE TABLE IF NOT EXISTS 表名(字段1, 数据类型 [约束条件] [默认值],字段2, 数据类型 [约束条件] [默…

Spring高手之路18——从XML配置角度理解Spring AOP

文章目录 1. Spring AOP与动态代理1.1 Spring AOP和动态代理的关系1.2 AOP基本术语 2. 通过XML配置实现Spring AOP2.1 添加Spring依赖2.2 定义业务接口和实现类2.3 定义切面类2.4 配置XML 1. Spring AOP与动态代理 1.1 Spring AOP和动态代理的关系 Spring AOP使用动态代理作为…

用 Python 和 AkShare 进行个股数据清洗:简易多功能方法

标题:用 Python 和 AkShare 进行个股数据清洗:简易多功能方法 简介: 本文介绍了如何使用 Python 和 AkShare 库对个股数据进行清洗和处理。个股数据经常需要进行清洗以用于分析、建模或可视化。我们将介绍一些简单但功能强大的方法,包括数据加载、缺失值处理、重复值检测和…

Gitlab:从其它项目组里导入一个项目

1.首先获取原项目的http地址 http://ip/projectGroup/ProjectX.git其中&#xff0c;ip 为公司gitlab内网地址。 2.进入目的项目组进行创建 首先&#xff0c;需要拥有一个该组拥有者权限的账号&#xff0c;才能进行后续的操作。 2.1.点击创建项目按钮 2.2.选择导入项目 其中…

03c++重载运算符

1、深入理解new和delete原理 #include<iostream> using namespace std;/* new 和 delete 1、malloc和new的区别 new 内存开辟构造函数 2、free和 delete的区别 delete 内存回收析构函数 开辟失败malloc返nullptr ,new抛出bad_alloc异常new->operator new delete -&…

Docker学习(带图详细)

一、安装docker 参考官方文档&#xff1a;https://docs.docker.com/engine/install/centos/ 查看系统版本 [rootlocalhost ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) [rootlocalhost ~]# [rootlocalhost ~]# uname -a Linux localhost.localdomai…

STM32平衡车-MPU6050的DMP库移植

本文目录 一、硬件接线二、需要移植的三个文件夹1. DMP文件夹目录2. IIC文件夹目录3. MPU6050文件夹目录 三、文件内容IO12C.cIO12C.hMPU6050.cMPU6050.hmain.c 四、附录1.更改IIC引脚 一、硬件接线 SCL-- PA11 SDA-- PA12 VCC-- 3.3v GND-- GND INT-- PC9 二、需要移植的三个…

[Kubernetes] Istio on Kubernetes 实践

文章目录 1.Kubernetes 创建2.Istio 部署2.1 下载 Istio2.2 安装 Istio 3.Istio on Kubernetes 实践3.1 部署 Bookinfo 示例应用3.2 确定入站 IP 和端口 1.Kubernetes 创建 主机名内部ip外部ipmaster192.168.66.2139.198.36.40node1192.168.66.3139.198.1.192node2192.168.66.…

数据结构——栈与队列的专题

文章目录 前言一、用队列实现栈二、用栈实现队列三、设计循环队列 前言 本篇是围绕栈与队列来展开&#xff0c;需要知道一定有关它们的相关基础知识 栈的详解 队列的详解 还有一道基础的栈题——有效的括号 一、用队列实现栈 原题链接&#xff1a;用队列实现栈 解题思路&a…

YOLOv5‘YOLOv7涨点必备:改进无参注意力SimAM

论文题目:SimAM: A Simple, Parameter-Free Attention Module for Convolutional Neural Networks 论文地址:http://proceedings.mlr.press/v139/yang21o/yang21o.pdf 源代码:https://github.com/ZjjConan/Sim 1.摘要 本文提出一种概念简单且非常有效的注意力模块。不同于…

攻防世界-web-file_include

题目 解题 通过阅读php代码&#xff0c;我们明显的可以发现&#xff0c;这个一个文件包含的类型题 文件包含漏洞也是一种“注入型漏洞”&#xff0c;其本质就是输入一段用户能够控制的脚本或者代码&#xff0c;并让服务器端执行。 require()&#xff0c;找不到被包含的文件时…

算法提高之单词接龙

算法提高之单词接龙 核心思想&#xff1a;dfs 预处理每两个字符串之间最短的公共部分长度 求最短公共 最终字符串是最长 dfs所有开头字符串 #include <iostream>#include <cstring>#include <algorithm>using namespace std;const int N 25;int g[N][N…

6818Linux内核开发移植

Linux内核开发移植 Linux内核版本变迁及其获得 Linux是最受欢迎的自由电脑操作系统内核&#xff0c; 是一个用C语言写成&#xff0c; 并且符合POSIX标准的类Unix操作系统 Linux是由芬兰黑客Linus Torvalds开发的&#xff0c; 目的是尝试在英特尔x86架构上提供自由免费的类Un…

nowcoder——回文结构

链表的回文结构_牛客题霸_牛客网 (nowcoder.com) 我们来分析该题&#xff1a;我们首先要清楚什么是回文结构&#xff1f;其实就是对称结构。如果一个链表呈对称结构就说明该链表具有回文结构。 下面给上一些例子&#xff1a; 那我们怎么判断该链表是否属于回文结构呢&#xf…

基于springboot的代驾管理系统的设计与实现

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…