STM32串口数据接收 --环形缓冲区

2023-05-16

STM32串口数据接收 --环形缓冲区

环形缓冲区简介

  在单片机中串口通信是我们使用最频繁的,使用串口通信就会用到串口的数据接收与发送,环形缓冲区方式接收数据可以更好的保证数据丢帧率第。
  在通信程序中,经常使用环形缓冲器作为数据结构来存放通信中发送和接收的数据。环形缓冲区是一个先进先出的循环缓冲区,可以向通信程序提供对缓冲区的互斥访问。
  环形缓冲区的一个有用特性是:当一个数据元素被用掉后,其余数据元素不需要移动其存储位置。相反,一个非圆形缓冲区(例如一个普通的队列)在用掉一个数据元素后,其余数据元素需要向前搬移。换句话说,环形缓冲区适合实现先进先出缓冲区,而非环形缓冲区适合后进先出缓冲区。
在这里插入图片描述

STM32环形缓冲区示例

  • 串口配置示例
#include "usart.h"
/********************串口初始化函数封装*********************
****硬件接口:USART1_TX -- PA9(发送)
**						USART1-RX --PA10(接收)
**						USART2_TX -- PA2(发送)
**						USART2-RX --PA3(接收)
**						USART3_TX -- PB10(发送)
**						USART3_RX -- PB11(接收)
形参:USART_TypeDef *USARTx -- 要配置的哪个串口
**			u32 baud  --波特率
**			u32 sysclk --时钟频率(USART1 --72MHZ ,USAT2\USART3 --36MHZ)
**
***********************************************************/
void Usartx_Init(USART_TypeDef *USARTx,u32 baud,u32 sysclk)
{
	if(USART1 == USARTx)
	{
			/*1.开时钟*/
		RCC->APB2ENR|=1<<2;//PA时钟
		RCC->APB2ENR|=1<<14;//串口时钟
		RCC->APB2RSTR|=1<<14;//串口复位
		RCC->APB2RSTR&=~(1<<14);//取消复位
		/*2.配置GPIO口*/
		GPIOA->CRH&=0xFFFFF00F;
		GPIOA->CRH|=0x000008B0;//上下拉输入,复用推挽输出	
		#ifdef USART1_IQR
			USART1->CR1|=1<<5;//开启串口接收中断
			STM32_NVIC_SetPriority(USART1_IRQn,0,1);//设置优先级
		#endif
	}
	else if(USART2 == USARTx)
	{
		/*1.开时钟*/
		RCC->APB2ENR|=1<<2;//PA时钟
		RCC->APB1ENR|=1<<17;//USART2时钟
		RCC->APB1RSTR|=1<<17;//开复位时钟
		RCC->APB1RSTR&=~(1<<17);//取消复位
		/*2.配置GPIO口*/
		GPIOA->CRL&=0xFFFF00FF;//清除原来寄存器中的值
		GPIOA->CRL|=0x00008B00;		
		#ifdef USART2_IRQ
			USART2->CR1|=1<<5;//串口2接收中断
			STM32_NVIC_SetPriority(USART2_IRQn,1,2);//设置优先级
		#endif
	}
	else if(USART3 == USARTx)
	{
		/*1.开时钟*/
		RCC->APB2ENR|=1<<3;//PB时钟
		RCC->APB1ENR|=1<<18;//USART3时钟
		RCC->APB1RSTR|=1<<18;//开复位时钟
		RCC->APB1RSTR&=~(1<<18);//取消复位
		/*2.配置GPIO口*/
		GPIOB->CRH&=0xFFFF00FF;
		GPIOB->CRH|=0x00008B00;	
		#ifdef USART3_IRQ
			USART3->CR1|=1<<5;//开启接收中断
			STM32_NVIC_SetPriority(USART3_IRQn,0,0);//设置优先级
		#endif
	}
	else return;
	/*3.配置串口核心寄存器*/
	USARTx->BRR=sysclk*1000000/baud;//设置波特率
	USARTx->CR1|=1<<2;//接收使能
	USARTx->CR1|=1<<3;//发送使能
	USARTx->CR1|=1<<13;//使能串口3
}
/************************串口发送字符************************/
void Usartx_SendString(USART_TypeDef *USARTx,u8 *str,u8 len)
{
	while(len--)
	{
		USARTx->DR=*str;
		while((USARTx->SR&1<<7)==0){}//等待数据发送完成
		str++;
	}
}
/***************printf重定向**************/
int fputc(int c,FILE *stream)
{
	USART1->DR=c;
	while(!(USART1->SR&1<<7)){}
	return c;
}
  • 中断接收数据 - - 环形缓冲区接收
/********************串口接收数据结构体********************/
#define USART1_LEN 200 //缓冲区大小
typedef struct 
{
	char buff[USART1_LEN];//缓冲区
    u8 usart1_rx_len;//保存的数据长度
    u8 usart1_flag;//数据接收完成标志
	u8 w;//写
	u8 r;//读
}USART1_RX;
USART1_RX USART1_rx={{0},0,0,0,0};//串口接收数据缓冲区初始化
void USART1_IRQHandler(void)
{
	u8 c;
	if(USART1->SR&1<<5)
	{
        c=USART1->DR;
        //当写入的数据长度==缓冲区长度,表示缓冲区满
        if(USART1_rx.usart1_rx_len<USART1_LEN)
        {            
            //写入数据到缓冲区
            USART1_rx.buff[USART1_rx.w]=c;
            USART1_rx.w=(USART1_rx.w+1)%USART1_LEN;//防止地址越界
            USART1_rx.usart1_rx_len++;
            TIM2->CNT=0;//清空计数器值   
			TIM2->CR1|=1<<0;
        }
        else USART1_rx.usart1_flag=1;//缓冲区满	
	}
	USART1->SR=0;//清除标志位
}
  • 读取缓冲区数据
/**********************从缓冲区读取数据******************
**
**形参:u8 *tx_data -- 读取数据保存地址
**
*********************************************************/
u8 Usart1_Annular_txdata(u8 *tx_data)
{   
    u8 len=0;
    //缓冲区为空 或者 USART1_rx.usart1_flag 数据接收完成标志(为了兼容字符串接收处理)
    if(USART1_rx.usart1_rx_len==0 || USART1_rx.usart1_flag==0)return 0;
    while(USART1_rx.usart1_rx_len)
    {
        *tx_data=USART1_rx.buff[USART1_rx.r];//读取缓冲区数据
        USART1_rx.r= (USART1_rx.r+1)%USART1_LEN;
        USART1_rx.usart1_rx_len--;//缓冲区长度-1
        tx_data++;
        len++;
    }
    USART1_rx.usart1_flag=0;//清除标志位
    *tx_data='\0';//接收到的字符保存为字符串
    return len;//返回读取到的字符个数
}
  • 主函数
#include "stm32f10x.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
u8 buff[200];
int main()
{
    u8 stat=0;
	Led_Init();//LED初始化
	Usartx_Init(USART1,115200,72);
	TIMx_Init(TIM2,72,20000);//通过定时器2辅助串口接收数据,20ms
	printf("串口初始化完成\r\n");
	/*轮询*/
	while(1)
	{
        stat=Usart1_Annular_txdata(buff);
        if(stat)
        {
            Usartx_SendString(USART1,buff,stat);
        }
	}
}
  • 效果展示
    在这里插入图片描述

示例工程

  示例工程链接:https://download.csdn.net/download/weixin_44453694/14981774

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

STM32串口数据接收 --环形缓冲区 的相关文章

随机推荐

  • vue2 -- 子组件访问父组件的数据方法汇总

    场景 当一个父组件下 有多个子组件需要共享父组件内的某一项数据时 可以使用如下方法实现需求 方法一 使用props 在 Vue 2 中 子组件可以通过 props 属性接收父组件传递的数据 在子组件中使用 emit 方法来触发父组件的事件
  • 简单好用的在线接口 MOCK 平台

    挺好用的一个线上工具 基本mock用法 邮箱登录记录一下
  • nodejs -- koa框架

    koa下载安装 Koa 是一个基于 Node js 的 Web 框架 它提供了一组简洁而优雅的 API 使得编写 Web 应用程序变得更加容易和快捷 以下是如何使用 Koa 创建一个 Node js 项目的步骤 安装 Node js 首先
  • 高德、百度地图互联网可访问的瓦片地址

    ArcGIS上对外开放的瓦片地址网站 传送门 span class token literal property property http span span class token operator span span class to
  • VScode+Remote-SSH搭建远程开发环境

    最近项目需要 xff1a 多台本机控制远程电脑 xff0c 因此学习了一下在VScode中搭建一个远程调试环境 简单总结了一下 xff01 远程开发环境搭建 xff1a VScode 43 Remote SSH 1 下载Visual Stu
  • java.sql.SQLException: url not set

    出现这个问题的主要原因 xff0c 是因为代码中的 64 ConfigurationProperties prefix 61 34 spring datasource druid 34 和application properties配置文件
  • 交叉编译器--笔记

    一般我们用PC电脑上的ubuntu的gcc编译器是针对x86架构 xff0c 而再开发板上的编译是ARM架构的 xff0c 故需要一个可以在PC上运行的ARM架构的GCC编译器 xff08 交叉编译器 xff09 用这个GCC编译ARM架构
  • ensp配置FTP进行文件操作

    ensp配置FTP进行文件操作 首先配置设备之间的连通 接下来配置路由器为FTP Client 在本地创建一个FTP Huawei文件夹 xff0c 然后再创建一个子文件夹Config xff0c 再在里面创建一个test txt文件 xf
  • 改变世界的五位顶级程序员!

    点击上方 Java基基 xff0c 选择 设为星标 做积极的人 xff0c 而不是积极废人 xff01 源码精品专栏 原创 Java 2020 超神之路 xff0c 很肝 中文详细注释的开源项目 RPC 框架 Dubbo 源码解析网络应用框
  • 你知道ping命令是如何工作的吗?

    点击上方 Java基基 xff0c 选择 设为星标 做积极的人 xff0c 而不是积极废人 xff01 每天 14 00 更新文章 xff0c 每天掉亿点点头发 源码精品专栏 原创 Java 2021 超神之路 xff0c 很肝 中文详细注
  • dashboard疏散主机提示报错:无法疏散主机...处理方法、openstack虚拟机状态卡在重启处理方法、openstack在数据库修改虚拟机状态的方法

    文章目录 dashboard疏散主机提示报错 无法疏散主机 处理方法 报错说明 状态卡在reboot状态 解决方法 登录nova数据库修改虚拟机信息 首先获取nova数据库的密码 登录nova数据库并做修改 验证信息是否修改成功 再次迁移并
  • 自学VUE(4)创建项目

    创建项目 1 检查电脑环境 node v npm v vue V cnpm v 2 创建项目 xff0c cd到桌面 xff0c 执行命令 xff1a vue init webpack firstVue 初始化一个项目 3 桌面获得一个项目
  • 前端请求后台报错400

    报错原因 xff1a 前端请求的字段名称或者字段类型和后台编写的实体类不一样 xff0c 或者前端提交的参数和后台需要的参数个数不匹配 xff0c 导致无法封装 xff0c 报错400 解决方法 xff1a 仔细对照前后端字段类型 xff0
  • Ubuntu终端文件管理工具ranger

    一 xff0c 安装 xff1a ubuntu使用apt get 安装 sudo apt get install ranger 二 xff0c 使用 ranger ranger 中有按键和命令两种操作方式 xff0c 按键是直接键入键盘上的
  • C# list根据字段生成排名

    需求分析 xff0c 我们要根据一个变量来生成排名 xff0c 变量数值相同则在同一名 xff0c 名数则跳过 xff0c 比如第一有两个 xff0c 那就不会有第二名 xff0c 直接到第三名 直接上代码 span class token
  • .net 6 web api项目添加日志(Serilog)管理,将日志输出到控制台、文件、数据库

    1 在nuget安装下面几个包 Serilog Serilog AspNetCore 用于日志输出到控制台 Serilog Formatting Compact 用于日志输出到mysql数据库 Serilog Sinks MySQL 用于日
  • GDB调试-新手笔记3

    ldd命令 43 readelf ldd 在制作自己的发行版时经常需要判断某条命令需要哪些共享库文件的支持 xff0c 以确保指定的命令在独立的系统内可以可靠的运行 ldd stack0 可以找到stack0程序使用的共享库 xff0c l
  • Spring源码分析(一)Spring的环境搭建与架构

    目录 一 Spring的基本信息1 1 Spring 概述1 2 架构 二 环境搭建2 1 gradle的安装与配置2 2 Spring源码构建 本图 xff1a 川西旅游中拍摄的 xff08 业余摄影 xff09 官网 xff1a Hom
  • RNA-seq:转录组数据分析处理(上)

    RNA seq xff1a 转录组数据分析处理 xff08 上 xff09 目录 RNA seq xff1a 转录组数据分析处理 xff08 上 xff09 一 流程概括二 准备工作1 fastq测序文件2 注释文件和基因组文件的获取 三
  • STM32串口数据接收 --环形缓冲区

    STM32串口数据接收 环形缓冲区 环形缓冲区简介 在单片机中串口通信是我们使用最频繁的 xff0c 使用串口通信就会用到串口的数据接收与发送 xff0c 环形缓冲区方式接收数据可以更好的保证数据丢帧率第 在通信程序中 xff0c 经常使用