stm32 串口+DMA+环形FIFO缓存收发数据

2023-05-16

μcos环境例程
freertos环境例程
重要几点
1.配置DMA,串口及环形buff之间的关系;
2.USART_IT_IDLE空闲中断接收完一帧数据,处理环形buff入口指针,通知用户程序接收完一次数据;
3.发送数据无需利用环形buff,直接将待传数据作为DMA的源地址,再使能相应DMA通道,根据串口TC中断判断发送完成;
4.用户程序中读取FIF0;

环形FIFO buff

FIFO实现为一个维护入口下标和出口下标的数组,循环覆写,与DMA的循环模式类似

typedef struct {
	uint8_t* buffer;	//FIFO数据
	uint16_t in;			//入口下标
	uint16_t out;			//出口下标
	uint16_t size;		//FIFO大小
}FIFO_Type;

几个FIFO功能函数

void Fifo_Init(FIFO_Type* fifo, uint8_t* buffer, uint16_t size)
{
	fifo->buffer = buffer;
	fifo->in = 0;
	fifo->out = 0;
	fifo->size = size;
}

uint16_t Fifo_Get(FIFO_Type* fifo, uint8_t* buffer, uint16_t len)
{
	uint16_t lenght;
	uint16_t in = fifo->in;	
	uint16_t i;
	lenght = (in + fifo->size - fifo->out)%fifo->size;
	if(lenght > len)
		lenght = len;
	for(i = 0; i < lenght; i++)
	{
		buffer[i] = fifo->buffer[(fifo->out + i)%fifo->size];
	}
	fifo->out = (fifo->out + lenght)%fifo->size;
	return lenght;
}

uint16_t Fifo_Status(FIFO_Type* fifo)
{
	uint16_t lenght;
	lenght = (fifo->in + fifo->size - fifo->out)%fifo->size;
	return lenght;
}

USART初始化

注意使能串口TC中断IDLE中断串口DMA收发,分别标志传输完成和接受完成,其他配置为常规配置,根据自己需求配置即可,串口1为例

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

  USART_Init(USART1, &USART_InitStructure); //初始化串口1
 USART_ITConfig(USART1, USART_IT_IDLE , ENABLE);//空闲中断
 USART_ITConfig(USART1, USART_IT_TC , ENABLE);//传输完成中断
 USART_DMACmd(USART1, USART_DMAReq_Tx|USART_DMAReq_Rx, ENABLE);//使能串口DMA收发
  USART_Cmd(USART1, ENABLE);                    //使能串口1 

DMA初始化

使能相应的DMA通道,通道表如下在这里插入图片描述
在这里插入图片描述
如上表得知,串口1的DMA收发通道为DMA1的通道4通道5,初始化如下

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);		

	DMA_DeInit(DMA1_Channel5);
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART1->DR);
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart1_Rx_Buffer;  //FIFO的buffer指针指向
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
	DMA_InitStructure.DMA_BufferSize = BSP_UART1_RX_SIZE;  //FIF0的buffer大小
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  //DMA循环覆盖写入
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel5, &DMA_InitStructure);
	/* Enable USART1 DMA TX request */

	DMA_Cmd (DMA1_Channel5,ENABLE); 

	DMA_DeInit(DMA1_Channel4);
	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)0;  //传输再修改地址,并使能该通道
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
	DMA_InitStructure.DMA_BufferSize = 1;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel4, &DMA_InitStructure);

	//接收FIFO初始化
	Fifo_Init(&Uart1_Rx_Fifo,Uart1_Rx_Buffer,BSP_UART1_RX_SIZE);


	//同步量,RTOS相关
	OSMutexCreate (&Uart1TxSem, "uart1 tx mutex", &err); 
	OSSemCreate (&Uart1TxWaitSem, "uart1 tx wait sem", 0,&err); 

串口中断服务函数

处理串口TC中断,IDLE中断

void Bsp_IntHandler(CPU_FNCT_VOID isr)//  RTOS相关
{
    CPU_SR_ALLOC();

    CPU_CRITICAL_ENTER();                                       /* Tell the OS that we are starting an ISR            */

    OSIntEnter();

    CPU_CRITICAL_EXIT();

    if (isr != (CPU_FNCT_VOID)0) {
        isr();
    }
    OSIntExit();  	
}
void USART1_IRQHandler(void)  //中断
{
	Bsp_IntHandler(USART1_IntHandler);
}
void USART1_IntHandler(void)   //   中断服务函数
{
	uint32_t temp = 0;
	OS_ERR err;	
	if(USART_GetITStatus(USART1,USART_IT_IDLE)!= RESET)//空闲中断
	{
		Uart1_Rx_Fifo.in = BSP_UART1_RX_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5);
		OSTaskSemPost(&MyTask_TCB, OS_OPT_POST_NONE, &err);//通知用户任务接收到一次数据帧
		temp = USART1->SR; //软件序列清除IDLE位
		temp = USART1->DR; //先读USART_SR,然后读USART_DR
		USART_ClearITPendingBit(USART1,USART_IT_IDLE);
	}
	else if(USART_GetITStatus(USART1,USART_IT_TC)!= RESET)//发送完成中断
	{
		USART_ClearITPendingBit(USART1,USART_IT_TC);
		DMA_Cmd(DMA1_Channel4, DISABLE);
		OSSemPost (&Uart1TxWaitSem, OS_OPT_POST_NONE, &err);
 		if(err != OS_ERR_NONE)
		{
			temp = err;
		}			
	}	
}

发送函数接收函数

发送,串口资源互斥访问,信号量通知串口发送成功

void Uart_Send(const uint8_t* buf, uint16_t len)
{
	OS_ERR err;
	if(len > BSP_UART1_TX_SIZE || len == 0)
	{
		return;
	}

	OSMutexPend(&Uart1TxSem, 500, OS_OPT_PEND_BLOCKING, (CPU_TS *) 0, &err);
	OSSemSet(&Uart1TxWaitSem, 0, &err);
	if(err != OS_ERR_NONE)
	{
		return err;
	}
	DMA_Cmd(DMA1_Channel4, DISABLE);
	DMA1_Channel4->CNDTR = len;//发送数据大小
	DMA1_Channel4->CMAR = (uint32_t)buf;//发送数据地址
	/* Enable USART1 DMA TX request */
	DMA_Cmd (DMA1_Channel4,ENABLE);
	OSSemPend(&Uart1TxWaitSem, 500, OS_OPT_PEND_BLOCKING, (CPU_TS *) 0, &err);
	 OSMutexPost (&Uart1TxSem, OS_OPT_POST_NONE, &err);
}


uint16_t Uart_1_Get(uint8_t *buffer, uint16_t len)
{
	return Fifo_Get(&Uart1_Rx_Fifo,buffer, len);  //读出长度len的fifo中的数据存在buffer参数中,fifo数据不足则有多少回多少
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

stm32 串口+DMA+环形FIFO缓存收发数据 的相关文章

  • 【RT-Thread】PIN 设备源码分析

    目录 1 获取引脚编号2 设置引脚模式3 设置引脚电平4 绑定 PIN 中断回调函数5 使能引脚中断6 总结7 PIN 设备使用示例 关于 RT Thread 的 PIN 设备驱动应用层面的介绍可以直接参考 RT Thread 的官网 xf
  • 基于VSCode的Linux内核调试环境搭建

    1 安装开发工具 span class token function sudo span span class token function apt span span class token function install span b
  • STM32定时器周期任务函数编写

    在STM32中我们对定时器的周期任务有一定的需求 xff0c 但在使用过程中 xff0c 需要将一些任务写到中断中 xff0c 中断函数会看上去比较复杂 xff0c 并且会有好多标志位 以流水灯为例 xff0c 周期为1s 介绍一下我自己的
  • stm32寄存器封装

    文章目录 前言 一 版本一 二 版本二 三 版本三 前言 本文记录的是用stm32开发的时候 一些底层的寄存器封装 固件库是如何帮我们完成这些工作的 一 版本一 代码如下 示例 span class token comment 外设基地址
  • 使用TI的MSP430实现一个单片机与上位机的数传系统。(西安电子科技大学综合应用开发实验)

    题目要求 xff1a 目标 xff1a 智能控制系统 利用单片机 xff08 开发平台任选 xff09 设计并编程实现一个单片机与上位机的数传系统 要求 xff1a 对单片机和PC 手机 单片机之间的通信进行设计 如果大作业没有设计通信部分
  • NVIDIA Jetson Xavier NX 控制GPIO

    NVIDIA Jetson Xavier NX 控制GPIO 文章目录 NVIDIA Jetson Xavier NX 控制GPIO前言一 简介二 代码实例1 gpio h2 gpio cpp 三 拓展 前言 在linux系统中以文件io的
  • NVIDIA Jetson Xavier NX禁用上电自启,使用按键开关机

    NVIDIA Jetson Xavier NX禁用上电自启 xff0c 使用按键开关机 文章目录 NVIDIA Jetson Xavier NX禁用上电自启 xff0c 使用按键开关机前言一 原理二 拓展 前言 NX默认上电自启 xff0c
  • Linux系统设置共享文件夹

    Linux系统设置共享文件夹 文章目录 Linux系统设置共享文件夹一 设置原理二 设置步骤1 安装samba2 创建 设置共享文件夹 三 测试 一 设置原理 基于Ubuntu16 04 xff0c 采用在线安装samba库的方式设置共享文
  • Linux:复位USB设备

    Linux xff1a 复位USB设备 文章目录 Linux xff1a 复位USB设备前言一 基本原理二 代码实例总结 前言 在Ubuntu16 04下开发SDR设备数据处理程序时 xff0c msi sdr设备有时运行几个小时后就会出现
  • Ubuntu Terminal终端默认常用快捷键总结

    Ubuntu Terminal终端默认常用快捷键总结 Ubuntu Terminal终端快捷键默认设置如下 xff0c 不同的发行版本可能有所出入 xff0c 以下快捷键在Ubuntu18 04LTS下可用 1 文件 快捷键说 明Ctrl
  • 基于c++ boost库实现进程管理

    基于c 43 43 boost库实现进程管理 1 前言 基于c 43 43 boost库与Terminator终端 xff0c 实现启动进程 进程运行状态监听 自动重启进程 杀死进程 设置进程环境变量等基础功能 2 原理 启动 杀死进程基于
  • 【RT-Thread】UART 设备源码分析

    官网介绍 I O 设备模型框架如下图 xff1a 但看到官网写道 设备驱动层是一组驱使硬件设备工作的程序 xff0c 实现访问硬件设备的功能 它负责创建和注册 I O 设备 xff0c 对于操作逻辑简单的设备 xff0c 可以不经过设备驱动
  • 基于c++ boost实现阻塞式ping指定IP

    基于c 43 43 boost实现阻塞式ping指定IP 1 前言 在实际业务场景中 xff0c 可能需要阻塞式检测目标IP连通性 xff0c 本程序基于c 43 43 boost库实现了一个简易的阻塞式ping指定IP例子 2 原理 在循
  • ROS_PACKAGE_PATH相关问题

    在ROS进行跨文件调用功能包时遇到报错 Resource not found The following package was not found span class token keyword in span span class t
  • 基于python批量调整图像大小

    前言 在写论文的时候常常因为截图的尺寸大小不一样 xff0c 导致图片排版很难受 xff0c 在word中又不会批量修改 xff0c 用下面的代码可以批量处理修改成一样的尺寸哦 xff01 代码如下 xff1a 在本文中 xff0c 我将向
  • PX4:【启动流程】

  • 线程池和多线程的区别

    线程池的概念 线程池大类总共分为4种 fixThreadPool 正规线程 xff08 传统线程池 xff09 cacheThreadPool 缓存线程池singleThreadPoll 单线程线程池 xff08 单例线程池 xff09 S
  • C++ libcurl Digest Auth

    C 43 43 libcurl Digest Auth postman操作如下 xff1a 附认证原理如下 xff1a MD5 md5 span class token punctuation span string HA1 span cl
  • 如何安装postman(超简单)

    方法一 xff1a xff08 官网下载 xff09 1 打开https www crx4chrome com crx 1058 2 稍微往下微微一拉就出现 Download crx file from Crx4Chrome gt 的选择
  • 转 curl 参数大全

    curl是一个非常实用的 用来与服务器之间传输数据的工具 xff1b 支持的协议包括 DICT FILE FTP FTPS GOPHER HTTP HTTPS IMAP IMAPS LDAP LDAPS POP3 POP3S RTMP RT

随机推荐

  • DataX mysql同步到mysql

    使用Datax web 创建同步任务 准备工作 创建数据源 配置数据库相关信息 创建执行器 配置执行器执行地址相关信息 1 构建reade 1 1 SQL语句 xff08 querySql xff09 在json文件中此部分配置就是 que
  • MQTT协议简介

    目录 MQTT协议简介一 MQTT协议特点1 1 发布和订阅1 2 QoS Quality of Service levels 二 MQTT数据包结构2 1 MQTT固定头2 2 MQTT可变长 Variable header 2 3 消息
  • vins位姿图优化

    我们 的滑动窗口和边缘化方案限制了计算的复杂性 xff0c 但也给系统带来了累积漂移 更确切地说 xff0c 漂移发生在全局三维位置 x y z 和围绕重力方向的旋转 yaw 为了消除漂移 xff0c 提出了一种与单目VIO无缝集成的紧耦合
  • 基于STM32开发板实现温湿度传感数据采集

    一 实验要求 本实验将选用STM32F407ZGT6开发板进行项目开发 xff0c 选用的传感器为DHT11温湿度传感器 传感器将采集到的数据传输到STM32 xff08 MCU xff09 主控进行数据处理 xff0c 最后通过串口打印出
  • 相机成像模型、内参矩阵、外参矩阵

    相机针孔成像模型 基本的小孔成像过程 xff1a X坐标系是针孔所在坐标系 xff0c Y坐标系为成像平面坐标系 xff0c P为空间一点 xff0c 小孔成像使得P点在图像平面上呈现了一个倒立的像 xff0c 俯视图如下 xff1a 由三
  • 韦东山学习笔记——UART(串口)的使用

    基于jz2440的串口使用 搬砖的文章概述UART的发送和接收串口之间的数据传输UART的用途串口的数据帧参数说明起始位数据位奇偶校验位停止位波特率 怎么发送一字节数据 xff0c 比如 A UART的优缺点优点缺点 UART相关配置寄存器
  • C++源文件的编译流程简介

    概述 C 43 43 C源文件 xff0c 包含 c h cpp hpp等格式的文件 xff0c 经过预处理 编译 汇编 链接后 xff0c 形成可执行文件 xff0c 也就是 exe文件 以一个简单项目MyProject为例 xff0c
  • 无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系

    使用 sudo apt get install 安装软件时 xff0c 出现错误 无法修正错误 xff0c 因为您要求某些软件包保持现状 xff0c 就是它们破坏了软件包间的依赖关系 错误的主要原因是 xff0c 系统中已经安装了被依赖的包
  • kalibr工具的编译与安装

    安装 kalibr提供了两种安装使用的方法 一 直接使用打包好的程序 下载地址 xff0c 选择CDE packages下载 xff08 需要访问Google xff09 使用注意事项 xff1a 只有64位系统可以使用 二 源码编译 安装
  • TCP/IP协议栈协议头

    目录 OSI与TCP IP模型UDP发送数据过程以太网协议头IP协议头UDP协议头UDP包 OSI与TCP IP模型 UDP发送数据过程 以太网协议头 把上面的以太网头用一个结构体表示如下 xff1a span class token ma
  • VLAN标签

    大家好呀 xff0c 我是请假君 xff0c 今天又来和大家一起学习数通了 xff0c 今天要分享的知识是VLAN标签 我们知道 xff0c 以太网交换机根据MAC地址表来转发数据帧 MAC地址表中包含了端口和端口所连接终端主机MAC地址的
  • fastjson的一些用法

    一般情况下 xff0c 在进行redis集群写入时 xff0c 使用jedisCluster set key value value为String类型 xff0c 那么就用到了fastjson进行序列化 以下是一些要点 xff1a 1 序列
  • 【视觉SLAM十四讲】第12讲 回环检测

    12 1 回环检测概述 前面已经介绍过了前端和后端 xff0c 前端用于特征点的提取以及轨迹 地图的初始值 xff0c 而后端负责对这部分数据进行优化 考虑到误差的存在 xff0c 每一个时刻存在的误差会不断累积 xff0c 从而产生累积误
  • LVGL——PC模拟器仿真模拟+VS2017

    目录 LVGL介绍移植说明资源下载环境搭建编译运行 本文只针对当时的LVGL v7 xff0c LVGL迭代过程中变化较大 xff0c 部分接口有可能做调整 本文仅供参考 LVGL介绍 官网 xff1a https lvgl io 官方在线
  • LVGL 优化帧率技巧

    目录标题 前文未优化版本LVGL帧率限制刷屏方法效率代码优化等级编译器版本LVGL显存单buffer非全尺寸双buffer全尺寸双buffer 本文只针对当时的LVGL v7 xff0c LVGL迭代过程中变化较大 xff0c 部分接口有可
  • CMAKE 里PRIVATE、PUBLIC、INTERFACE属性示例详解

    闲扯 cmake 里面target include directories xff0c target link libraries这两个命令里面有三种属性PRIVATE PUBLIC INTERFACE cmake PRIVATE PUBL
  • C++11 返回值优化、移动语义及函数返回值构造的重载决议

    局部变量unique ptr能否作为返回值 记得自己之前在哪写过一篇返回值优化的博客 xff0c 翻了半天csdn xff0c 居然没找到 xff0c 也不知道写在哪了 被问到一个unique ptr 局部变量能不能做返回值的问题 xff0
  • C++ 面试八股分享

    一年半 xff0c 估计又要跳槽了 xff0c 本来还想再积累一两年的 xff0c 结果公司业务线调整 xff0c 同部门三四个同事n 43 1裁了 xff0c 我也要换工作内容 xff0c 现在在来这么一出 xff0c 就准备骑驴找马 x
  • c++ makefile + clangd 生成 compile_command.json

    补充vscode 43 clangd 开发 c c 43 43 一个项目用makefile管理 xff0c 工程很大 xff0c vscode的ms cpp tools代码跳转功能基本处于残废状态 xff0c 有想将makefile 迁移至
  • stm32 串口+DMA+环形FIFO缓存收发数据

    cos环境例程 freertos环境例程 重要几点 1 配置DMA xff0c 串口及环形buff之间的关系 xff1b 2 USART IT IDLE空闲中断接收完一帧数据 xff0c 处理环形buff入口指针 通知用户程序接收完一次数据