stm32---dma串口发送+fifo队列框架

之前分享了一个关于gd32的fifo框架,这次就用stm32仿照写一个,其实几乎一样,这次说的更详细点,我全文都写上了注释,大家直接cv模仿我的调用方式即可

uasrt.c

#include "stm32f10x.h"                  // Device header
#include "queue.h"void myDMA_init(void);
void myNVIC_Config(void);queue_t  uart1_queue_in,uart1_queue_out ;  //定义2个结构体变量,分别是入、出栈
uint8_t recv_buf[256] = {0};  			   //接收缓冲区大小256  byte
static uint8_t send_buf[256] = {0};        //发送缓冲区大小256  byte
static uint8_t usart1_tx_buf[64];
static uint8_t uart1_send_ready = 1;void uart1_queue_init(void)
{queue_init(&uart1_queue_in,recv_buf,sizeof(recv_buf));//初始化压栈的缓冲区queue_init(&uart1_queue_out,send_buf,256);		      //初始化出栈的缓冲区
}
/* **************************************************************************************
*	函 数 名: uart_get_queue_data
*	功能说明: 拿取uart in队列的数据
*	形    参: p_buf : 数据存储地址
*			size : 拿取个数
*	返 回 值: 无
*   备    注: 无
*****************************************************************************************/
uint16_t uart1_get_queue_data(uint8_t * p_buf,uint16_t size)
{return queue_out_data(&uart1_queue_in,p_buf,size);
}/* **************************************************************************************
*	函 数 名: uart_get_data_len
*	功能说明: 返回uart in 队列的储存数据长度
*	形    参: 无
*			
*	返 回 值: 数据长度
*   备    注: 无
*****************************************************************************************/
uint16_t uart1_get_data_len(void)
{return queue_get_num(&uart1_queue_in);
}/* **************************************************************************************
*	函 数 名: uart_put_queue_data
*	功能说明: 把数据压进uart out队列
*	形    参: p_buf : 数据存储地址
*				size : 压的个数
*	返 回 值: 无
*   备    注: 无
*****************************************************************************************/
uint16_t uart1_put_queue_data(uint8_t * p_buf,uint16_t size)
{return queue_in_data(&uart1_queue_out,p_buf,size);
}/* **************************************************************************************
*	函 数 名: uart_send_poll
*	功能说明: 轮询uart out 队列并通过dma发送
*	形    参: 
*			
*	返 回 值: 发送数据个数
*   备    注: 无
*****************************************************************************************/
uint8_t uart0_send_poll(void)
{uint8_t n = 0;	if(uart1_send_ready)//串口tx缓冲区是否有数据并传输完成?{n = queue_out_data(&uart1_queue_out,usart1_tx_buf,sizeof(usart1_tx_buf));	//计算大小if(n){uart1_send_ready=0;DMA_Cmd(DMA1_Channel4,DISABLE);DMA_SetCurrDataCounter(DMA1_Channel4,n);DMA_Cmd(DMA1_Channel4,ENABLE);return n;}}return 0;
}void USART1_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);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);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 = 115200;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;USART_InitStructure.USART_Parity = USART_Parity_No;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_Init(USART1, &USART_InitStructure);USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;NVIC_Init(&NVIC_InitStructure);USART_Cmd(USART1, ENABLE);USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); // 使能USART1的DMA发送请求(关键!)myDMA_init();myNVIC_Config();uart1_queue_init();	
}void myDMA_init(void)
{	DMA_InitTypeDef DMA_InitStructure;// 使能DMA1时钟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);// 配置DMA1通道4(USART1_TX)DMA_DeInit(DMA1_Channel4);  // 复位DMA通道4到默认值DMA_InitStructure.DMA_PeripheralBaseAddr 	= (uint32_t)&USART1->DR;  			 // 外设基址:USART1数据寄存器DMA_InitStructure.DMA_MemoryBaseAddr 		= (uint32_t)usart1_tx_buf;           // 内存基址:发送缓冲区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; // 外设数据宽度8位DMA_InitStructure.DMA_MemoryDataSize 		= DMA_MemoryDataSize_Byte;     // 内存数据宽度8位DMA_InitStructure.DMA_Mode 					= DMA_Mode_Normal;                       // 普通模式(非循环)DMA_InitStructure.DMA_Priority 				= DMA_Priority_High;               // 中等优先级DMA_InitStructure.DMA_M2M					= DMA_M2M_Disable;                        // 非内存到内存模式DMA_Init(DMA1_Channel4, &DMA_InitStructure);// 使能DMA1通道4传输完成中断DMA_ITConfig(DMA1_Channel4, DMA_IT_TE, ENABLE);	
}void myNVIC_Config(void)
{NVIC_InitTypeDef NVIC_InitStructure;// 配置DMA1_Channel4_IRQn的中断优先级NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  // 抢占优先级1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;         // 子优先级1NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}void USART1_IRQHandler(void)
{uint8_t Res;if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET){Res = USART_ReceiveData(USART1);//接收到的数据进行入栈,压栈queue_in_data(&uart1_queue_in,&Res,1);USART_ClearITPendingBit(USART1, USART_IT_RXNE);}
}
void DMA1_Channel4_IRQHandler(void)
{if (DMA_GetITStatus(DMA1_IT_TC4) != RESET) // 检查DMA1通道4传输完成中断标志{		uart1_send_ready  = 1;DMA_ClearITPendingBit(DMA1_IT_TC4); // 清除中断标志}
}

queue.c

#include "queue.h"/*** @brief  Initialize the circular queue* @param  queue: Queue* @param  buffer: Queue's buffer* @param  size: buff size* @retval None*/
void queue_init(queue_t *queue,uint8_t *buffer, uint16_t size)
{queue->buffer = buffer;queue->size = size;queue->head = 0;queue->tail = 0;queue->length = 0;queue->GetLen = 0;queue->PutLen = 0;
}/*** @brief  Insert element into the circular queue* @param  queue: Queue* @param  buffer: Queue's buffer* @param  count: element length* @retval Number of elements inserted successfully*/
uint16_t queue_in_data(queue_t *queue, const uint8_t *buffer, uint16_t count)  //Zhixing Change 250430
{uint16_t i = 0;for(i=0; i<count; i++){if(queue->GetLen == 0){if(queue->PutLen == (queue->size - 1)) return i; }else{if(queue->PutLen == (queue->GetLen - 1)) return i;  }queue->buffer[queue->PutLen++] = *buffer++;queue->PutLen %= queue->size;}return i;
}/*** @brief  Delete element from the circular queue* @param  queue: Queue* @param  buffer: Queue's buffer* @param  count: element length* @retval Number of elements deleted successfully*/
uint16_t queue_out_data(queue_t *queue,uint8_t *buffer, uint16_t count)  //Zhixing Change 250430
{uint16_t i = 0;//__disable_irq();for(i=0; i<count; i++){/*if(queue->length == 0)//empty{__enable_irq();return i;}*/if(queue->PutLen == queue->GetLen) return i;*buffer++ = queue->buffer[queue->GetLen++];if(queue->GetLen == queue->size) queue->GetLen = 0;}//__enable_irq();return i;
}/*** @brief  Get the remaining amount of data length from queue* @param  queue: Queue* @retval data length*/
uint16_t queue_get_num(queue_t *queue)
{return queue->length;
}/******************** (C)Copyright MidiPlus Software ********************/

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

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

相关文章

【生产就曲篇】让应用可观测:Actuator监控端点与日志最佳实践

摘要 本文是《Spring Boot 实战派》系列的终章&#xff0c;我们将探讨如何让应用真正达到**“生产就绪” (Production-Ready)** 的标准。文章的核心是可观测性 (Observability)&#xff0c;即从外部了解一个系统内部运行状态的能力。 我们将深度挖掘 Spring Boot Actuator 的…

操作系统知识(1)

操作系统的分类总结 1、批处理操作系统:单道批处理和多道批处理(主机与外设可并行) 2、分时操作系统:一个计算机系统与多个终端设备连接。将CPU的工作时间划分为许多很短的时间片&#xff0c;轮流为各个终端的用户服务。 3、实时操作系统:实时是指计算机对于外来信息能够以足…

一.Sharding分库分表-基因法+自定义多key分片实现多字段查询

前言 当下遇到这样一个场景&#xff0c;由于订单数据量达到千万级别&#xff0c;采用分库分表进行优化&#xff0c;根据订单的热查条件&#xff1a;order_no订单编号进行分表&#xff0c;但是这样带来一个问题&#xff0c;用户查询自己的订单怎么查&#xff1f;由于分片键使用…

【leetcode】543. 二叉树的直径

二叉树的直径 题目题解解释 题目 543. 二叉树的直径 给你一棵二叉树的根节点&#xff0c;返回该树的 直径 。 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。 两节点之间路径的 长度 由它们之间边数表示。 题解 …

AI基础知识(07):基于 PyTorch 的手写体识别案例手册

目录 实验介绍 实验对象 实验时间 实验流程 实验介绍 随着人工智能技术的飞速发展&#xff0c;图像识别技术在众多领域得到了广泛应用。手写体识别作为图像 识别的一个重要分支&#xff0c;其在教育、金融、医疗等领域具有广泛的应用前景。本实验旨在利用深度 学习框架 PyTorc…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…

信号(瞬时)频率求解与仿真实践(2)

引言 本文是信号(瞬时)频率求解与仿真实践专题的第二篇文章&#xff0c;在上一篇博文 [1]信号(瞬时)频率求解与仿真实践(1)-CSDN博客中&#xff0c;我构建了信号瞬时频率求解的基本框架&#xff0c;并且比较详细地讨论了瞬时频率法。这篇博文探讨适用于信号瞬时频率求解的另一种…

Linux运行发布jar文件携带哪些参数

在 CentOS 8 上运行发布的 JAR 文件时,可以根据不同需求携带以下参数: 1. 基本运行方式 bash 复制 下载 java -jar your-application.jar 2. 常用 JVM 参数 参数说明-Xms256m初始堆内存大小(如 256MB)-Xmx1024m最大堆内存大小(如 1GB)-XX:MaxMetaspaceSize=256m元空间…

在GIS 工作流中实现数据处理(4)

结果输出与可视化 最后&#xff0c;我们将统计结果输出为一个 Excel 文件&#xff0c;并在 ArcMap 中对城市中心区域的土地利用情况进行可视化展示。 import pandas as pd# 将统计表格转换为 pandas DataFrame df pd.read_csv(statistics_table, sep"\t")# 输出为…

【术语解释】网络安全((SAST, DAST, SCA, IAST),Hadoop, Spark, Hive 的关系

## OWASP Top 10等 OWASP Top 10&#xff1a;OWASP (Open Worldwide Application Security Project&#xff0c;开放全球应用程序安全项目) Top 10 是一份由全球安全专家定期更新的报告&#xff0c;列出了当前 Web 应用程序面临的十大最关键安全风险。 它是一个广受认可的意识文…

NY197NY205美光闪存固态NY218NY226

NY197NY205美光闪存固态NY218NY226 美光科技作为全球领先的半导体存储解决方案供应商&#xff0c;其闪存固态硬盘&#xff08;SSD&#xff09;产品线一直备受业界关注。NY197、NY205、NY218和NY226是美光近期推出的几款重要固态硬盘型号&#xff0c;它们在性能、容量和适用场景…

MinHook 对.NET底层的 SendMessage 拦截真实案例反思

一&#xff1a;背景 1. 讲故事 上一篇我们说到了 minhook 的一个简单使用&#xff0c;这一篇给大家分享一个 minhook 在 dump 分析中的实战&#xff0c;先看下面的线程栈。 0:044> ~~[138c]s win32u!NtUserMessageCall0x14: 00007ffc5c891184 c3 ret 0:061&g…

qt配合海康工业相机取图开发

1.最近开发海康工业相机&#xff0c;做取图demo 2.在MVS运行目录下找到Development文件夹&#xff0c;找到下图两个文件夹一个是头文件一个是库文件 3.引用到qt项目中 4.下面是头文件跟源文件 头文件 #ifndef MVSCAMERA_H #define MVSCAMERA_H#include <QObject> #incl…

JavaScript基础学习与应用(后端了解部分)

JavaScript JavaScript原名liveScrip,由美国网景公司开发的一种用于对网页操作的脚本语言 脚本语言:(不需要编译 sql html css)由某种解释器直接解释运行的 JavaScript是一种解释性的脚本语言 JavaScript是网页的行为,可以为网页提供各种行为(图片操作) JavaScript一般一对…

Linux环境下安装和使用RAPIDS平台的cudf和cuml - pip 安装方法

‌ cuDF 和 cuML 是 RAPIDS平台 的两个核心组件&#xff0c;它们共同构成了RAPIDS平台的主要功能 1.linux环境下pip安装 pip install cuml-cu1224.6.0 --extra-index-urlhttps://pypi.nvidia.com 安装过程中可能会提示缺少包之类的&#xff0c;按提示进行包的缺失安装 2.安装…

基于 Redis 的幂等性设计:SpringBoot @Async 在高并发 MySQL 日志存储中的应用

一、问题描述 在高并发场景下,大量设备实时上报状态数据,需要异步保存到MySQL,同时需要解决幂等性校验和线程池耗尽问题。 二、解决方案 1. 幂等性控制 作用:确保同一请求无论执行多少次,结果都一致,避免重复处理。 实现方式: 唯一标识:设备ID + 时间戳组合Redis原…

ELK日志采集系统

ELK 日志采集系统指的是由 Elasticsearch、Logstash 和 Kibana 三个核心开源软件组成的套件&#xff0c;用于集中式日志的采集、处理、存储、搜索、分析和可视化。它现在更常被称为 Elastic Stack&#xff0c;因为其组件生态已经扩展&#xff08;尤其是引入了 Beats&#xff09…

什么是音频?

引言&#xff1a;声音的本质 什么是音频&#xff1f;振动与感知 音频&#xff0c;在其最核心的层面&#xff0c;即是我们通常所说的声音。它起源于物体的振动。这些振动扰动了其周围的介质&#xff08;例如空气或水&#xff09;&#xff0c;在介质中产生了微小的压力变化&…

接口 RESTful 中的超媒体:REST 架构的灵魂驱动

在 RESTful 架构中&#xff0c;** 超媒体&#xff08;Hypermedia&#xff09;** 是一个核心概念&#xff0c;它体现了 REST 的 “表述性状态转移&#xff08;Representational State Transfer&#xff09;” 的本质&#xff0c;也是区分 “真 RESTful API” 与 “伪 RESTful AP…

centos clamav 扫描及告警配置

centos clamav 扫描及告警配置 1 下载1.1官网下载1.2 在线下载2 配置3 扫描3.1 更新病毒库3.2 扫描4 告警4.1 安装 Postfix4.2 安装mail邮件工具4.3 配置4.4 发送告警邮箱信息5 定时配置(cronie)5.1 定时更新病毒库5.2 定时扫描1 下载 1.1官网下载 官网下载地址,下载rpm包…