STM32之串口

2023-10-30

一些概念

并行通信
一次性一起传,需要引脚比较多,速度快。
串行同行
一个个传,需要引脚比较少,速度较慢

串行通信的通信方式
1、同步(带时钟同步信号),如:SPI,IIC
2、异步(不带时钟同步信号),如:UART,单总线
在这里插入图片描述
UART:通用异步收发传输器
USART:通用同步/异步串行接收/发送器

USART
USART_SRx 状态寄存器
USART_DR 数据寄存器
USART_BRR波特率寄存器,12位的整数和4位小数
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

串口初始化

在文件夹system下的usart.c文件里,已经写了串口的初始化及相关函数,可以直接用。
关于使用串口的步骤
1、时钟使能
2、串口复位
3、设置GPIO端口初始化(就是速度,模式,功率那些)
4、串口初始化
5、初始化NVIC
6、使能串口

1、时钟使能。

TX和RX的复用GPIO口是GPIOA
在这里插入图片描述
在这里插入图片描述
在这里是需要使能两个时钟,USART1和GPIOA的时钟

void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	
2、串口复位
USART_DeInit(USART1);

在sysytem文件夹下的usart.h文件夹下可以找到对应的函数。
在这里插入图片描述

3、GPIO模式配置

(跟之前点灯一样),但是设置的输出输入模式参考那个文档

在这里插入图片描述

  //USART1_TX   GPIOA.9
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
   
  //USART1_RX	  GPIOA.10初始化
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  
4、串口参数初始化

在这里插入图片描述

 //USART 初始化设置

	USART_InitStructure.USART_BaudRate = bound;//串口波特率
	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_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式

  USART_Init(USART1, &USART_InitStructure); //初始化串口1
5、初始化NVIC并开启中断

关于NAVIC的一些概念
https://blog.csdn.net/hongliwong/article/details/111034892

在这里插入图片描述
高优先级的抢占优先级是可以打断正在进行的低抢古优先级中断的。
抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。
抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。
如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;

在这里插入图片描述

//Usart1 NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
6、开启中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
7、使能串口

(我的理解就是开串口了)

  USART_Cmd(USART1, ENABLE);                    //使能串口1 
完整的初始化代码
#if EN_USART1_RX   //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误   	
u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15,	接收完成标志
//bit14,	接收到0x0d
//bit13~0,	接收到的有效字节数目
u16 USART_RX_STA=0;  
void uart_init(u32 bound){
  //GPIO端口设置
  GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
  
	//USART1_TX   GPIOA.9
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
   
  //USART1_RX	  GPIOA.10初始化
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  

  //Usart1 NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
   //USART 初始化设置

	USART_InitStructure.USART_BaudRate = bound;//串口波特率
	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_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式

  USART_Init(USART1, &USART_InitStructure); //初始化串口1
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
  USART_Cmd(USART1, ENABLE);                    //使能串口1 

}

中断函数

在这里插入图片描述

在这里插入图片描述
USART_RX_STA 是接收是否结束的标志位

void USART1_IRQHandler(void)                	//串口1中断服务程序
	{
	u8 Res;
#if SYSTEM_SUPPORT_OS 		//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntEnter();    
#endif
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
		{
		Res =USART_ReceiveData(USART1);	//读取接收到的数据
		
		if((USART_RX_STA&0x8000)==0)//接收未完成
			{
			if(USART_RX_STA&0x4000)//接收到了0x0d
				{
				if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
				else USART_RX_STA|=0x8000;	//接收完成了 
				}
			else //还没收到0X0D
				{	
				if(Res==0x0d)USART_RX_STA|=0x4000;
				else
					{
					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
					USART_RX_STA++;
					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  
					}		 
				}
			}   		 
     } 
#if SYSTEM_SUPPORT_OS 	//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntExit();  											 
#endif
} 
#endif	

一个别人的解释
http://t.csdn.cn/30Lbe

void USART1_IRQHandler(void)                	//串口1中断服务程序
	{
	u8 Res;     //定义unsigned char型字符Res
 
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  
		//接收中断(接收到的数据必须是0x0d 0x0a结尾)
		//这里判断发送接收完成的依据就是串口数据0x0d 0x0a,
		//0x0d是CR(carriage return)回车的意思,光标回到最左边,
		//0x0a是LF(line feed)换行的意思,光标到达下一行,
		//但是在PC上回车和换行是在一起的就是按下回车按键
		//当然可以更改程序使用其他进行判断例如使用0x2a也就是*进行结束判断
		{
		Res =USART_ReceiveData(USART1);//(USART1->DR);	
		//读取接收到的数据,存放到变量Res中
		if((USART_RX_STA&0x8000)==0)
			//判断接收是否未完成
			//接收完成未清除标志位,还是会不断进入到接收中断,所以使用标志进行判断,
		  //当接收完成便不会跳入到判断,从而不执行任何指令,空等待
			//使用条件判断是否已经接收完数据,这里判断接收完的依据就是收到了0x0a;
			//具体判断在后面
			{
			if(USART_RX_STA&0x4000)
			//如果接收到了0x0d,那么再进一步执行是否接收到0x0a的判断
				{
				if(Res!=0x0a)USART_RX_STA=0;
			//没有接收到0x0a那么说明,数据未正确传输或者接收错误,重新开始判断,
			//但是这里没有将接收到的数据进行清空,也没有退出接收中断,此程序只是从头开始执行接收判断
				else USART_RX_STA|=0x8000;	
			//接收完成了,收到了0x0a那么标志位USART_RX_STA将会变成0x8000,将不再进行数据检测与存储
				}
			else 
				//还没收到0X0D,说明数据还未发送结束继续进行数据的检测与存储
				{	
				if(Res==0x0d)USART_RX_STA|=0x4000;
				//收到了数据0x0d,标志位USART_RX_STA变成0x4000
				else
					{
				//如果没有接收到数据0x0d,执行判断是否存储数组已满,已满则重新开始接收
					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
				//将接收到的数据写进数组,标志位USART_RX_STA与上0X3FFF清除前两位以防止标志位与80004000冲突
					USART_RX_STA++;
				//数组地址加一,向后排
					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;
				//接收数据错误,超出数组大小,又开始接收向数组重新写  
					}		 
				}
			}   		 
     } 
 
} 

一个数据后会加上0X0D 0X0A,如果接收到了0X0A就表示接收结束,没接收到0X0D就表示接收错误。

实验接收到A,LED0亮,再接收到关。

在这里插入图片描述

#include "stm32f10x.h"
#include "KEY.h"
#include "LED.h"
#include "delay.h"
#include "usart.h"

 int main(void)
 {	
	u8 t;
	u8 len;	 
	delay_init();	    	 //延时函数初始化	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
	uart_init(9600);	 //串口初始化为9600
	LED_Init();		  	 //初始化与LED连接的硬件接口 
  
	while(1)
	{
		if(USART_RX_STA&0x8000) //接收未完成
		{					   
			len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
			printf("\r\n您发送的消息为:\r\n");
			for(t=0;t<len;t++)
			{
				//USART1->DR=USART_RX_BUF[t];
				USART_SendData(USART1, USART_RX_BUF[t]); //向串口1发送数据
				while((USART1->SR&0X40)==0);//接收到了0X40就发送结束
			}
			printf("\r\n\r\n");//插入换行
			USART_RX_STA=0;	
		}else{  //接收完成
		
			u16 res;
			res = USART_ReceiveData(USART1);
			if(res == '2'){
				LED0 = !LED0;
				delay_ms(10); 
			}
			if(res == 'B'){
				LED1 = !LED1;
				delay_ms(10); 
			}
			if(res == 'X'){
				LED1 = 1;
				LED0 = 1;
				delay_ms(10); 
			}
		}
  }
}

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

STM32之串口 的相关文章

  • 26进制

    问题 在Excel 2003中 用A表示第1列 B表示第2列 Z表示第26列 AA表示第27列 AB表示第28列 以此类推 请写一个函数 输入用字母表示的列号编码 输出它是第几列 思路 这是一道关于进制的题目 其本质是把十进制数字用A Z表
  • Python openCV qt.qpa.plugin: could not find the qt platform plugin "cocoa" in "" 在Mac上的解决方案详解

    这是一个不断踩坑的过程 首先 我开始的诉求是希望可以利用 openCV 实时显示电脑摄像头获取的内容 开始用了 cv2 imshow 结果不行 报错 qt qpa plugin Could not find the Qt platform
  • Windows C盘清理之用户数据清理记录

    今天 突然发现C盘空间只剩余3 4G了 我的电脑总共500G 化了6个分区 如下 80G给了C盘 系统盘 100G给了D盘 软件盘 200G给了E盘 虚拟机盘 20G给F盘 workspace盘 20G给G盘 文档盘 其余给了H盘 MISC

随机推荐

  • 超乎想像的宇宙

    转至youtube 超乎想像的宇宙 1 無限空間 720p The Fabric of the Cosmos 1 What is Space http youtu be dOVp8FypiTo list PL6qRRMFI035qD5 zZ
  • 网络编程之五种I/O模型

    在网络编程中有5中I O模型 今天我们就来聊一聊这5中模型的原理和区别 1 阻塞I O模型 阻塞I O模型通信示意图如下 阻塞I O模型通信示意图 当用户调用了recvfrom这个系统调用后 内核就开始准备数据 对于网络I O来说 很多时候
  • 记录安装mysql5.6到centos6上面的经历

    下载MySql rpm安装包 国外网站下载太慢 国内镜像下载吧 http mirrors sohu com mysql MySQL 5 6 注意下载 el6 版本的包 el7 是linux 7上使用的 不要直接就奔最新版本去了 主要需要下载
  • 自定义注解记录操作日志

    自定义注解 自定义注解首先要知道元注解 也就是注解的注解 是jdk内置的 元注解有四种 Retention 注解保留策略 Retention RetentionPolicy SOURCE 仅存在于源码中 Retention Retentio
  • 本地迅速创建ftp服务器,让其他人获取(下载)你的文件

    我们现在的目的是想要别人共享我们的文件 我们在自己的电脑上创建一个文件服务器ftp 然后别人在浏览器中访问我们的ip地址 或自定义的域名 即可达到别人快速下载我们的资源的目的 1 创建ftp用户 依次点击我的电脑 管理 或者直接cmd下执行
  • 手把手教学,免费不限速内网穿透,zerotier值得拥有

    文章目录 常见的内网穿透原理 frp代理 p2p直连 zero安装说明 1 登录zerotier管理平台创建一个网络 2 windows安装zerotier 并加入到网络 3 linux设备加入到网络 4 安卓设备加入到网络 访问测试 常见
  • QString类型装换为const char*的方法

    QString NewBuildProject ProjectNameLineEdit text toStdString c str 说明 1 NewBuildProject ProjectNameLineEdit text 输出为QStr
  • java实时监控数据变化_银行监控报警系统性能提升50倍,用的全是开源组件

    作者介绍 胖亚鹏 监控技术领域专家 具备十余年监控系统建设经验 精通主流商用及开源监控软件产品的集成应用 专注于监控工具建设 全面支撑传统架构和容器云 分布式架构下的监控管理 探索研究智能化监控 推动分布式架构下以大数据 人工智能技术为基础
  • 【LeetCode-简单】39. 组合总和 (图文详解)

    建议 完全不了解递归的同学 先去学习一下递归 题目 题目地址 https leetcode cn problems combination sum 示例 方法1 回溯算法 思路 来自视频https www bilibili com vide
  • 12.14黄金白银TD行情怎么看;美原油最新交易操作指导

    黄金最新资讯 消息面 周二 12月14日 国际金价上涨 但美元同时走强限制了金价涨势 投资者等待美联储今日晚些时候召开的会议 从中寻找美联储如何加快结束经济刺激措施 除此之外 欧洲央行英国央行也将在本周举行会议 美联储将在当日稍晚开始为期两
  • MQ怎么保证消息不丢失?

    在我们做业务时候很多时候需要用到消息队列 那消息队列中是怎么保证消息的可靠性的 我们今天学习目前主流的消息队列是怎么保证消息可靠性 1 RocketMQ 2 Kafka 3 RabbitMQ RocketMQ 持久化存储 RocketMQ
  • uviewUI中u-popup组件show属性显示和不显示控制问题

    问题 在uviewUI中u popup组件show并不是用来控制弹出层的显示与否 而是用v model来进行控制 注意查看官方的API 解决 在控件上面加入v model控制即可
  • 【C++】 C & C++ 内存管理

    文章目录 C C 内存分布 C 内存管理方式 1 操作内置类型 2 操作自定义类型 operator new 与 operator delete 定位 new C C 内存分布 C 和 C 的内存分布没什么区别 C 是基于 C 语言的 如下
  • bind 用法小技巧

    正常来说 我们写一个回调 因为这个回调方法是在组件内部调用的 我们没有办法把参数传过去 如果 rightMethod 要用到 resp 或者 review 参数的话 可能就要建全局参数 this 的指向也会有问题 很尴尬 使用 bind
  • 脉.濒湖脉学七言诀

    脉学七言诀 浮 脉 体状诗 浮脉惟从肉上行 如循榆荚似毛轻 三秋得令知无恙 久病逢之却可惊 相类诗 浮如木在水中浮 浮大中空乃是芤 拍拍而浮是洪脉 来时虽盛去悠悠 浮脉轻平似捻葱 虚来迟大豁然空 浮而柔细方为濡 散似杨花无定踪 主病诗 浮脉
  • LDV7语音识别模块 LD3320A语言识别说话踩坑

    说真的气到我了 在家里说了一个小时小杰 因为这个模块默认叫说什么 小杰 我人都裂开来这个小杰 在家里说了半个小时小杰 我妈问我怎么了最后解决问题了我来说一下 1 离咪头要远一点 这样说话识别率比较高 默认程序 说明文档说要靠着咪头说话 我个
  • Ubuntu无法检测到外接显示器,无法打开nvidia-settings或者打开nvidia-settings时有报错,ubuntu-drivers devices命令后无显示

    我安装了 nvidia 440 显卡驱动之后 出现了以下问题 手动安装的nvidia 440 Ubuntu无法检测到外接显示器 无法打开nvidia settings或者打开nvidia settings时有报错 ubuntu driver
  • crontab 配置问题 没有执行php文件

    设置了一个crontab 发现不执行 查找了原因是因为PHP的路径不对 首先 确认 PHP 可执行文件的位置 对于大多数 Linux 系统 几乎肯定是 usr bin php 如果不确定其位置 请在命令行中键入 which php 并查看响
  • com.android.ddmlib.AdbCommandRejectedException: device offline Error while Installing APK解决

    com android ddmlib AdbCommandRejectedException device offline Error while Installing APK 这个问题是adb被杀死了 重新启动一下就可以 有三种方法 一
  • STM32之串口

    文章目录 一些概念 串口初始化 1 时钟使能 2 串口复位 3 GPIO模式配置 4 串口参数初始化 5 初始化NVIC并开启中断 6 开启中断 7 使能串口 完整的初始化代码 中断函数 实验接收到A LED0亮 再接收到关 一些概念 并行