USART使用

news2024/11/25 23:26:57

USART软件配置

具体步骤如下:(USART 相关库函数在 stm32f10x_usart.c 和 stm32f10x_usart.h 文件中)

(1)使能串口时钟及 GPIO 端口时钟

前面说过 STM32F103C8T6 芯片具有 3 个串口,对应不同的引脚,串口 1 挂接在 APB2 总线上,串口 2-串口 3 挂接在 APB1 总线上,根据自己所用串口使能总线时钟和端口时钟。

例如使用 USART1,其挂接在 APB2 总线上,并且 USART1 对应 STM32 芯片管脚的 PA9 和 PA10,因此使能时钟函数如下:

 

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能 GPIOA 时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能 USART1 时钟

(2)GPIO 端口模式设置,设置串口对应的引脚为复用功能

因为使用引脚的串口功能,所以在配置 GPIO 时要将设置为复用功能,这里

把串口的 Tx 引脚配置为复用推挽输出, Rx 引脚为浮空输入,数据完全由外部

输入决定。如下:

 

GPIO_InitTypeDef GPIO_InitStructure;//定义结构体变量 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; //TX //串口输出 PA9 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化串口输入 IO */ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; //RX //串口输入 PA10 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模拟输入 GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化 GPIO */

(3)初始化串口参数,包含波特率、字长、奇偶校验等参数

要使用串口功能,必须对串口通信相关参数初始化,其库函数如下:

 

void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);

想必不用说,大家也知道第一个参数是什么意思,它是用来选择串口。

第二个参数是一个结构体指针变量,结构体类型是 USART_InitTypeDef,

其内包含了串口初始化的成员变量。下面我们就来看下这个结构体:

 

typedef struct { uint32_t USART_BaudRate; //波特率 uint16_t USART_WordLength; //字长 uint16_t USART_StopBits; //停止位 uint16_t USART_Parity; //校验位 uint16_t USART_Mode; //USART 模式 uint16_t USART_HardwareFlowControl; //硬件流控制 } USART_InitTypeDef;

USART_BaudRate:

波特率设置。常用的波特率为 4800、9600、115200 等。

标准库 函 数 会 根 据 设 定 值 计 算 得 到 USARTDIV 值 , 并 设 置USART_BRR 寄存器值。

USART_WordLength:

数据帧字长。可以选择为 8 位或者 9 位,

通过 USART_CR1 寄存器的 M 位的值决定。如果没有使能奇偶校验控制,一般使用 8 数据位;

如果使能了奇偶校验则一般设置为 9 数据位。

USART_StopBits:

停止位设置。可选 0.5 个、 1 个、 1.5 个和 2 个停止 位,

它设定 USART_CR2 寄存器的 STOP[1:0]位的值,一般我们选择 1 个停止位。

通常使用1

USART_Parity:

奇偶校验控制选择。可选 USART_Parity_No( 无 校 验 ) 、

USART_Parity_Even( 偶 校 验 ) 以 及 USART_Parity_Odd( 奇 校 验 ) ,

它设 定 USART_CR1 寄存器的 PCE 位和 PS 位的值。

USART_Mode:

USART 模式选择。

可以为 USART_Mode_Rx 和 USART_Mode_Tx, 允许使用逻辑或运算选择两个,

它设定 USART_CR1 寄存器的 RE 位和 TE 位。

USART_HardwareFlowControl:

硬件流控制选择。

只有在硬件流控制模式才 有效,

可以选择无硬件流 USART_HardwareFlowControl_None、

RTS 控制USART_HardwareFlowControl_RTS、

CTS 控制 USART_HardwareFlowControl_CTS、 RTS 和 CTS 控制 USART_HardwareFlowControl_RTS_CTS。 了解结构体成员功能后,就可以进行配置,例如我们配置 USART1,如下:

 

USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate =115200;//波特率设置 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为 8 位数据格式 USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位 USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_No ne;//无硬件数据流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式 USART_Init(USART1, &USART_InitStructure); //初始化串口 1

(4)使能串口

配置好串口后,我们还需要使能它,使能串口库函数如下

void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);

例如我们要使能 USART1,如下:

 

USART_Cmd(USART1, ENABLE);//使能串口 1

(5)设置串口中断类型并使能

 

// 第五步:设置串口中断类型并使能 USART_ClearFlag(USART1, USART_FLAG_TC); // 清除中断 USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//开启接收中断

(6)设置串口中断优先级,使能串口中断通道

 

// 第六步:设置串口中断优先级,使能串口中断通道 NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; // 中断通道 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 3; // 抢占 NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3; // 响应 NVIC_Init(&NVIC_InitStruct);

(7)编写串口中断服务函数

 

//编写串口中断服务函数 void USART1_IRQHandler(void) { u8 r =0; if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) // 接受中断 不等于0 就是RESET { r = USART_ReceiveData(USART1); // 接收数据 if((USART1_RX_STA&0x8000)==0) { if((USART1_RX_STA&0x4000)==1) { if(r!=0x0a)USART1_RX_STA = 0; //接收错误,重新开始 else USART1_RX_STA |= 0x80000;//接收完成了 } else //还没收到0X0D { if(r==0x0d)USART1_RX_STA|=0x4000; // 是否为0d 次高位设置 else { USART_RX_BUF[USART1_RX_STA&0x3fff] = r; USART1_RX_STA++; if(USART1_RX_STA>(USART_REC_LEN-1))USART1_RX_STA=0; //接收数据错误,重新开始接收 } } } } }

为了确认 USART1 是否发生接收中断,调用了读取串口中断状态标志位函数

USART_GetITStatus,如果确实产生接收中断事件,那么就会执行 if 内的语句,

将串口接收到的数据保存在变量 r 内,然后有通过串口发送出去,通过

USART_GetFlagStatus 函数读取串口状态标志,如果数据发送完成,则退出 while

循环语句。

这里我们设计了一个小小的接收协议:通过这个函数,配合一个数组

USART1_RX_BUF[],一个接收状态变量 USART1_RX_STA 实现对串口数据的接收管

理。USART1_RX_BUF 的大小由 USART1_REC_LEN 定义,也就是一次接收的数据最

大不能超过 USART1_REC_LEN 个字节。USART1_RX_STA 是一个接收状态变量,其

各的定义如下图所示:

设计思路如下:

当接收到从电脑发过来的数据,把接收到的数据保存在 USART1_RX_BUF 中,同时在接收状态寄存器(USART1_RX_STA)中计数接收到的有效数据个数,

当收到回车(回车的表示由 2 个字节组成:0X0D 和 0X0A)的第一个字节 0X0D 时,计数器将不再增加,等待 0X0A 的到来,而如果 0X0A 没有来到,

则认为这次接收失败,重新开始下一次接收。

如果顺利接收到 0X0A,则标记 USART1_RX_STA 的第 15 位,这样完成一次接收,并等待该位被其他程序清除,从而开始下一次的接收,

而如果迟迟没有收到 0X0D,那么在接收数据超过 USART1_REC_LEN 的时候,则会丢弃前面的数据,重新接收。

软件设计

usart.c

#include "usart.h"


u16 USART1_RX_STA =0;
u8 USART_RX_BUF[USART_REC_LEN];



void USART1_Init(u32 bound)
{
	GPIO_InitTypeDef GPIO_InitStructure;//定义结构体变量
	USART_InitTypeDef USART_InitStruct;
	NVIC_InitTypeDef NVIC_InitStruct;

	
	// 第一步 使能串口时钟及 GPIO 端口时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能 GPIOA 时钟 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能 USART1 时钟
	
	/*  配置GPIO的模式和IO口 */
	// 第二步 GPIO 端口模式设置,设置串口对应的引脚为复用功能
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;        //TX    //串口输出 PA9 
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; 
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;     //复用推挽输出 
	GPIO_Init(GPIOA,&GPIO_InitStructure);         /* 初始化串口输入 IO */
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;            //RX //串口输入 PA10 
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;  //模拟输入
	GPIO_Init(GPIOA,&GPIO_InitStructure);     /* 初始化 GPIO */
	
	
	// 第三步:初始化串口参数,包含波特率、字长、奇偶校验等参数
	USART_InitStruct.USART_BaudRate = bound; // 波特率
	USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 字长
	USART_InitStruct.USART_StopBits = USART_StopBits_1; // 停止位
	USART_InitStruct.USART_Parity = USART_Parity_No; // 奇偶校验位
	USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None; // 不使用硬件流
	USART_InitStruct.USART_Mode =USART_Mode_Rx|USART_Mode_Tx; // //收发模式
	USART_Init(USART1,&USART_InitStruct);
	
	// 第四步:使能串口 可以放到最后
	USART_Cmd(USART1,ENABLE);
	
	
	// 第五步:设置串口中断类型并使能
	USART_ClearFlag(USART1, USART_FLAG_TC); // 清除中断
	
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//开启接收中断
	
	
	
	// 第六步:设置串口中断优先级,使能串口中断通道
	NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; // 中断通道
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 3; // 抢占
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3; // 响应
	NVIC_Init(&NVIC_InitStruct);

	
	
}





//编写串口中断服务函数
void USART1_IRQHandler(void)
{
	u8 r =0;
	
	if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)  // 接受中断 不等于0 就是RESET
	{
		r = USART_ReceiveData(USART1);  // 接收数据
		
		if((USART1_RX_STA&0x8000)==0)
		{
			if((USART1_RX_STA&0x4000)==1)
			{
				if(r!=0x0a)USART1_RX_STA = 0; //接收错误,重新开始
				else USART1_RX_STA |= 0x80000;//接收完成了
			}
			else   //还没收到0X0D
			{
				if(r==0x0d)USART1_RX_STA|=0x4000;  // 是否为0d 次高位设置
				else
				{
					USART_RX_BUF[USART1_RX_STA&0x3fff] = r;
					USART1_RX_STA++;
					if(USART1_RX_STA>(USART_REC_LEN-1))USART1_RX_STA=0;     //接收数据错误,重新开始接收	
				}
			}				
		}			
	}	
}

usart.h

#ifndef _usart_H
#define _usart_H
#include "system.h"

#define USART_REC_LEN	200

extern u8 USART_RX_BUF[USART_REC_LEN];
extern u16 USART1_RX_STA;	
void USART1_Init(u32 bound);
 

#endif

main.c

#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"


int main()
{
	u8 i =0;
	u16 len;
	u16 t=0;
	
	SysTick_Init(72);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	LED_Init();	
	USART1_Init(115200);
	
	while(1)
	{
		if(USART1_RX_STA&0x8000)
		{
			len =USART1_RX_STA&0x3fff;	//得到此次接收到的数据长度
			for(t=0;t<len;t++)
			{
				USART_SendData(USART1,USART_RX_BUF[t]);
				 while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET); // 获取标记 SET不等于1
			}
			USART1_RX_STA = 0;
		}
		
		i++;
		if(i%10==0)
		{
			LED0=!LED0;
		}	
		delay_ms(10);
	}
}

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

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

相关文章

Vue3分支语法-登录注销

点击登录 点击注销登录 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><!-- vue.js --><script src"https://unpkg.com/vue3/dist/vue.global.js"><…

基于RuoYi-Flowable-Plus的若依ruoyi-nbcio支持自定义业务表单流程(四)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 自定义业务表单里的流程历史需要单独设计&#xff0c;所以下面就这部分进行介绍。 1、后端部分&#xff…

基于SSM的流浪狗收容领养管理平台设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

汇川Easy521PLC与压力传感器485通讯实例

本例是汇川Easy521PLC与支持485通讯的压力传感器进行通讯的实例记录。对于初次使用汇川PLC的朋友,可能有借鉴的意义。 配置: 1、汇川Easy521PLC 2、美控压力变送器 3、汇川Autoshop编程软件 将压力变送器的485线与PLC本体的485端子一一连接: 485+:A+ 485-:B- 一般485的标…

数字孪生技术在智慧城市应用的推进建议

&#xff08;一&#xff09;坚持需求牵引&#xff0c;强场景重实效 必须始终坚持以人为本、场景导向、需求牵引&#xff0c;站在供给侧结构性改革的角度&#xff0c;突出以用促建&#xff0c;强调建用并重&#xff0c;真正发挥数字孪生城市应用建设的实效。从构建数字孪生创新…

手撕Vue-查找指令和模板

接着上一篇文章&#xff0c;我们已经实现了提取元素到内存的过程&#xff0c;接下来我们要实现的是查找指令和模板。 大致的思路是这样的&#xff1a; 遍历所有的节点需要判断当前遍历到的节点是一个元素还是一个文本如果是一个元素, 我们需要判断有没有v-model属性如果是一个文…

Linux——多线程,互斥与同步

目录 一.linux互斥 1.进程线程间的互斥相关背景概念 2.互斥量mutex 3.加锁互斥锁mutex 4.锁的底层原理 二.可重入VS线程安全 1.概念 2.常见的线程不安全的情况 3.常见的线程安全的情况 4.常见不可重入的情况 5..常见可重入的情况 6.可重入与线程安全联系 三.死锁 …

华为云应用中间件DCS系列—Redis实现(视频直播)消息弹幕

云服务、API、SDK&#xff0c;调试&#xff0c;查看&#xff0c;我都行 阅读短文您可以学习到&#xff1a;应用中间件系列之Redis实现&#xff08;视频直播&#xff09;消息弹幕 1 什么是DEVKIT 华为云开发者插件&#xff08;Huawei Cloud Toolkit&#xff09;&#xff…

为什么智能相机需要搭配镜头使用?

镜头作用是将光学图像聚焦在图像传感器的光敏面阵上。不同类型的工业镜头&#xff0c;成像质量也各不相同&#xff0c;成像质量也有差异&#xff0c;影响工业镜头的因素有哪些呢 图像中心与边缘的影响图像中心较边缘分辨率高&#xff1b;图像中心较边缘光场照度高&#xff1b;像…

springboot配置swagger

springboot配置swagger Swagger 是什么Swagger配置springboot代码展示总结 Swagger 是什么 Swagger 是一个用于构建、文档和调用 RESTful Web 服务的强大工具。它提供了以下几方面的好处&#xff1a; 自动生成 API 文档: Swagger 可以自动生成 API 文档&#xff0c;包括接口的…

JS代码控制台临时测试

在进行js修改测试时&#xff0c;有可能需要我们不断的清楚缓存去加载我们修改的js文件&#xff0c;这样操作对于频繁的js修改测试很不友好&#xff0c;实际上&#xff0c;我们可以通过控制台覆盖原js代码段进行测试&#xff0c;接下来&#xff0c;以本平台为例&#xff0c;我实…

React高级特性之HOC高阶组件

一、概念 把一个组件当成另外一个组件的参数传入&#xff0c;然后通过一定的判断&#xff0c;返回新的组件。 二、基本用法 三、实战 例1&#xff1a;监听鼠标位置 App.js import React from react import HOCDemo from ./6.高级特性/4.HOCDemofunction App() {return (<…

redis(普通连接和连接池、字符串类型、hash类型、列表类型)

1 redis普通连接和连接池 1.1 普通连接 1.2 连接池 2 redis字符串类型 3 redis hash类型 4 redis列表类型 1 redis普通连接和连接池 #1 python 代码作为客户端---》连接# 2 安装模块&#xff1a;pip install redis1.1 普通连接 from redis import Redisconn Redis(host&qu…

【vim 学习系列文章 10 -- vim 将代码中空格高亮显示方法】

文章目录 vim 高亮空格使用背景如何配置vim 可以自动显示空格呢&#xff1f;vim highlight 命令使用介绍vim 空白行的处理vim match 命令详细介绍 vim 高亮空格使用背景 开发人员在编写代码之后&#xff0c;在review通过之后会将代码推到服务器然后merge&#xff0c;但是有些代…

02、RocketMQ -- 应用场景、核心概念

目录 1、消息中间件应用场景场景一&#xff1a;异步解耦同步调用异步调用 场景二&#xff1a;流量削峰 2、常用消息中间件ActiveMQKafkaRabbitMQRocketMQ 3、RocketMQ的核心概念生产者Producer消费者Consumer名字服务Name Server代理服务器Broker Server消息主题Topic消息队列M…

idea使用Spring Initializer创建springboot项目的坑【保姆级教学】

项目场景&#xff1a; 提示&#xff1a;这里先简述项目创建后遇到的问题和解决方案&#xff1a; idea 使用 Spring Initializer 创建springboot项目后&#xff0c; 有以下问题&#xff1a; ① 右键没有Run ② 右键New新建文件发现无Java Class选项 然后解决掉 ①② 问题后出…

AbortController中止请求通信[模糊搜索案例]

AbortController中止请求通信[模糊搜索案例] AbortController中止请求通信(模糊搜索案例) AbortController中止请求通信(模糊搜索案例) 这里用模糊搜索来做示例&#xff0c;这里是调用后端模糊搜索接口 该案例的中止请求可以用于很多地方&#xff0c;比如取消上传/下载文件等 完…

【分享】哇,不愧是国家出品!逆袭必备!!

哈喽&#xff0c;大家好&#xff0c;木易巷又发现好东西了 你还在为学习技能花&#x1f4b0;吗&#xff1f; 别傻了&#xff0c;偷偷告诉你&#x1f92b;&#xff0c;国家早就为我们提供了免费的学习网站&#xff01;不仅可以免费学习各种技能&#xff0c;还可以拿职业证书&a…

华为数通方向HCIP-DataCom H12-831题库(单选题:281-300)

第281题 如图所示,某工程师利用4台路由器进行网络互通测试,其中R1、R2、R3部署OSPF (Area0)实现网络互通,R2、R3、R4部署IS-IS(均部署为Level-2路由器)实现网络互通,现在该工程师在R1的OSPF进程中引入直连路由,在R2的IS-IS进程中引入OSPF路由,则以下关于该场景的描述,正…