DMA发送全部历史记录数据到串口
背景
博主参与的项目中,有个读取全部历史记录的功能,如果下位机在主程序中将全部历史记录单纯地通过串口传输会比较占用cpu资源,影响主程序中别的功能。最后商量得出以下实现方案:
定义两个发送缓冲区DMATxbuf1和DMATxbuf2,以及这两个发送缓冲区的标志DMATxbuf1Flag和DMATxbuf2Flag,发送缓冲区的标志取值有三种:可搬运、可发送和发送中。主main中负责搬运数据到这两个发送缓冲区中以及如果存在可发送的缓冲区且不存在发送中的缓冲区,那么主main开启一下这个DMA的通道使能。在DMA传输完成中断中,需要更新刚刚发送缓冲区的标志即可。
相关代码
初始化串口和DMA
void InitDebug_Sub(void)
{
// stc_gpio_cfg_t stcGpioCfg;
// stc_uart_cfg_t stcCfg;/***********************RAM口初始化******************************************/Rxput_232 = 0;Rxget_232 = 0;Txput_232 = 0;Txget_232 = 0;TXing_232 = 0;/***********************GPIO口初始化**********************************************/ stc_gpio_cfg_t stcGpioCfg;DDL_ZERO_STRUCT(stcGpioCfg);Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE);/***********TX************/stcGpioCfg.enDir = GpioDirOut;Gpio_Init(GpioPortA,GpioPin0,&stcGpioCfg);Gpio_SetAfMode(GpioPortA,GpioPin0,GpioAf2); //配置PC10为LPUART1_TX/**********RX**************/stcGpioCfg.enDir = GpioDirIn;Gpio_Init(GpioPortA,GpioPin1,&stcGpioCfg);Gpio_SetAfMode(GpioPortA,GpioPin1,GpioAf2); //配置PC11为LPUART1_RX/***********************串口初始化**********************************************/ stc_lpuart_cfg_t stcCfg;DDL_ZERO_STRUCT(stcCfg);Sysctrl_SetPeripheralGate(SysctrlPeripheralLpUart1,TRUE); //<外设模块时钟使能 stcCfg.enStopBit = LPUart1bit; ///<1停止位 stcCfg.enMmdorCk = LPUartEven; ///<偶校验stcCfg.stcBaud.enSclkSel = LPUartMskPclk; ///<传输时钟源stcCfg.stcBaud.u32Sclk = Sysctrl_GetPClkFreq(); ///<PCLK获取stcCfg.stcBaud.enSclkDiv = LPUartMsk4Or8Div; ///<采样分频stcCfg.stcBaud.u32Baud = 38400; ///<波特率stcCfg.enRunMode = LPUartMskMode1; ///<工作模式1,异步模式全双工LPUart_Init(M0P_LPUART1, &stcCfg);/***********************DMA初始化**********************************************/ Sysctrl_SetPeripheralGate(SysctrlPeripheralDma,TRUE); //开启DMA外设时钟stc_dma_cfg_t dmaCfg;//CONFB配置dmaCfg.enMode = DmaMskBlock; //Block传输dmaCfg.enTransferWidth = DmaMsk8Bit; // 传输宽度 8bit(适用于 UART)dmaCfg.enSrcAddrMode = DmaMskSrcAddrInc; // 源地址递增dmaCfg.enDstAddrMode = DmaMskDstAddrFix; // 目标地址固定dmaCfg.enSrcAddrReloadCtl = DmaMskSrcAddrReloadEnable;//使能源地址重载dmaCfg.enDestAddrReloadCtl = DmaMskDstAddrReloadEnable;//使能目标地址重载dmaCfg.enSrcBcTcReloadCtl = DmaMskBcTcReloadEnable; //使能BC/TC重载dmaCfg.enTransferMode = DmaMskOneTransfer; // 单次传输模式//CONFA配置dmaCfg.u16BlockSize = 1; // 每次传输 1 字节dmaCfg.u16TransferCnt = 131; //实际传输的时候会设置长度dmaCfg.enRequestNum = DmaLpUart1TxTrig; //触发源配置:LPUART1 SBUF为空dmaCfg.u32SrcAddress = (uint32_t)&DMATxbuf1.DATA[0]; // 源地址:发送缓冲区dmaCfg.u32DstAddress = (uint32_t)&M0P_LPUART1->SBUF; // 目标地址:LPUART1 发送寄存器dmaCfg.enPriority = DmaMskPriorityFix; // 固定优先级Dma_InitChannel(DmaCh1, &dmaCfg); //初始化DMA通道Dma_EnableChannelIrq(DmaCh1); //使能DMA传输完成中断NVIC_EnableIRQ(DMAC_IRQn); //使能NVIC DMA中断sendingHistoryRemaingTime = 0; //初始化发送历史记录剩余时间为0carryHistoryFinishFlag = 1; //初始化不需要搬运历史记录DMATxbuf1Flag = 1; //初始化DMA缓冲区1可搬运DMATxbuf2Flag = 1; //初始化DMA缓冲区2可搬运/**********************LPUART 中断使能*********************************/LPUart_ClrStatus(M0P_LPUART1,LPUartRC); //<清接收中断请求LPUart_ClrStatus(M0P_LPUART1,LPUartTC); //<清发送中断请求LPUart_EnableIrq(M0P_LPUART1,LPUartRxIrq); //<使能接收中断LPUart_DisableIrq(M0P_LPUART1,LPUartTxIrq); //发送完成之后关闭发送中断// LPUart_EnableIrq(M0P_LPUART1,LPUartTxIrq); //<不使能发送中断,EnableNvic(LPUART1_IRQn,IrqLevel3,TRUE); //<系统中断使能LPUart_EnableFunc(M0P_LPUART1,LPUartDmaTxFunc); //DMA发送LPUART使能P_RD_DBG = 0;//初始化调试口485方向为接收
收到获取全部指令时
case 12: //读取全部历史记录sendingHistoryRemaingTime = 2000; //设置发送超时时间,同时也标记着此时在传输历史及记录FlashReadSP = W25QX_RECSTART_ADDR; //初始化历史记录读取地址为开始地址//重置两个缓冲区状态为可搬运DMATxbuf1Flag = 1;DMATxbuf2Flag = 1;carryHistoryFinishFlag = 0;//重置历史记录没有搬运完break;
主main中的搬运、发送历史数据
//发送历史记录期间且历史记录没有搬运完if(sendingHistoryRemaingTime){//尝试搬运历史记录到缓冲区if(!carryHistoryFinishFlag){carryHistory();}//尝试并触发DMA发送dmaSendHistoryRecord();}
搬运、发送历史数据方法详情
void carryHistory()
{typedef_DMATXBUF* dmaTxbuf;u8 carryBufType = 0; //记录搬的是哪个缓冲区//选择可搬运的缓冲区if(DMATxbuf1Flag == 1){dmaTxbuf = &DMATxbuf1;carryBufType = 1;}else if(DMATxbuf2Flag == 1){dmaTxbuf = &DMATxbuf2;carryBufType = 2;}else{//目前没有可搬运的return;}u8 count = 0;dmaTxbuf->LEN = 0;while(count < 3 && !carryHistoryFinishFlag){u8 cmd2=0;u8 buf[300];structHistory_TypeDef* ptr = (structHistory_TypeDef*)buf;//历史记录已经读完了if(FlashReadSP>=W25QX_RECEND_ADDR){cmd2 = 0x01;FlashReadSP = W25QX_RECSTART_ADDR; //首条记录carryHistoryFinishFlag = 1;}W25QX_BufferRead((u8*)&ptr->HistoryData,FlashReadSP,sizeof(structEEP_GET_HISTOR_TypeDef)); //读取记录if(ptr->HistoryData.FLAG != 0x7e){FlashReadSP += 4096;FlashReadSP &= 0xfffff000;W25QX_BufferRead((u8*)&ptr->HistoryData,FlashReadSP,sizeof(structEEP_GET_HISTOR_TypeDef)); //读取记录索引if(ptr->HistoryData.FLAG != 0x7e) {cmd2 = 0x01;FlashReadSP = W25QX_RECSTART_ADDR; //首条记录carryHistoryFinishFlag = 1;}}ptr->CMD1 = 0x8c;ptr->CMD2 = cmd2;ptr->ADDR = 0x01;ptr->SoftVer = SOFTVER; ptr->checksum = CRC16(buf,sizeof(structHistory_TypeDef)-2);dmaTxbuf->DATA[dmaTxbuf->LEN++] = 0x10;dmaTxbuf->DATA[dmaTxbuf->LEN++] = 0x02;for(u16 i = 0; i < sizeof(structHistory_TypeDef); i++){u8 qq = buf[i];dmaTxbuf->DATA[dmaTxbuf->LEN++] = qq;/* -----0x10加发一个 -----*/if(qq == DLE) dmaTxbuf->DATA[dmaTxbuf->LEN++] = DLE;}dmaTxbuf->DATA[dmaTxbuf->LEN++] = DLE;dmaTxbuf->DATA[dmaTxbuf->LEN++] = ETX;dmaTxbuf->DATA[dmaTxbuf->LEN++] = 0x16; count++;FlashReadSP += 128;}//说明搬运了一些历史记录,需要发送,更新标记if(count > 0){//更新缓冲区1的标志if(carryBufType == 1){DMATxbuf1Flag = 2;//缓冲区1可发送}if(carryBufType == 2){DMATxbuf2Flag = 2;//缓冲区2可发送}//说明还有数据待发送,更新过期时间sendingHistoryRemaingTime = 2000;}
}void dmaSendHistoryRecord()
{//存在发送中的数据if(DMATxbuf1Flag == 3 || DMATxbuf2Flag == 3){return;}if(DMATxbuf1Flag == 2){UART_DMA_Send_History(1);}else if(DMATxbuf2Flag == 2){UART_DMA_Send_History(2);}
}
DMA发送中断处理函数
void DMAC_IRQHandler(void)
{
#if (INT_CALLBACK_ON == INT_CALLBACK_DMAC) Dmac_IRQHandler();
#endif // DMA 中断处理代码if (M0P_DMAC->CONFB1_f.STAT == 5) // 传输完成标志101{// 清除传输完成标志M0P_DMAC->CONFB1_f.STAT = 0; //更新缓冲区标志if(DMATxbuf1Flag == 3){DMATxbuf1Flag = 1;}else if (DMATxbuf2Flag == 3){DMATxbuf2Flag = 1;}}M0P_DMAC->CONFB1_f.STAT = 0;
}
相关文章:
DMA发送全部历史记录数据到串口
背景 博主参与的项目中,有个读取全部历史记录的功能,如果下位机在主程序中将全部历史记录单纯地通过串口传输会比较占用cpu资源,影响主程序中别的功能。最后商量得出以下实现方案: 定义两个发送缓冲区DMATxbuf1和DMATxbuf2&…...
蓝桥杯好题推荐-----高精度减法
🌈个人主页:羽晨同学 💫个人格言:“成为自己未来的主人~” 题目链接 记录详情 - 洛谷 | 计算机科学教育新生态https://www.luogu.com.cn/record/205122671 思路讲解 这个题目的解题思路,其实是和高精度加法是非常像的。怎么说…...
SpringMVC (3)
目录 1. 传递对象 2. 后端参数重命名(后端参数映射) 3. 传递数组 4. 传递集合 5. 传递JSON数据 5.1 JSON概念 5.2 JSON语法 5.3 JSON字符串和Java对象互转 5.4 JSON优点 5.5 传递JSON对象 6. 获取URL中参数PathVariable 7. 上传文件RequestP…...
vscode使用豆包MARSCode----集成doubao1.5 DeepSeekR1 DeepseekV3模型的ai编程插件
引入扩展 打开VSCode扩展窗口,在搜索窗口搜索MarsCode,找到MarsCode 插件单击「install」,完成安装,登录即可使用MarsCode 编程助手。 主要功能 主要快捷键 / explain 解释项目代码,AI 返回的内容有结构分类&#…...
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_buf_t
ngx_buf_t 定义在 src/core/ngx_buf.h typedef struct ngx_buf_s ngx_buf_t;struct ngx_buf_s {u_char *pos;u_char *last;off_t file_pos;off_t file_last;u_char *start; /* start of buffer */u_char …...
分布式开源协调服务之zookeeper
Zookeeper简介 Zookeeper是什么? Zookeeper官网中对Zookeeper的定义还是比较明确的: ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services…...
ubuntu系统安装playhouse三方库
ubuntu系统python3.10安装playhouse三方库 问题描述 问题描述 虚拟环境中使用pip install playhouse,返回安装成功 用pip list查看,能看到playhouse及版本号 导包时提示没有找到playhouse我那件目录,能发现 检查site-package发现问题&#x…...
【星云 Orbit-F4 开发板】04.一触即发:GPIO 外部中断
【星云 Orbit-F4 开发板】04. 一触即发:外部中断控制 摘要 本文详细介绍了如何使用STM32F407微控制器的HAL库实现外部中断功能。通过配置GPIO引脚作为外部中断源,并在中断回调函数中处理按键事件,实现了按键控制LED状态翻转的功能。本文旨在…...
笔记二:整数和浮点数在内存中存储
目录 一、数据类型介绍 二、类型的基本归类 1.整形家族: 2.浮点数家族: 3.构造类型: 4.指针类型 5.空类型: 三、整形在内存中的存储 3.1 原码,反码、补码 3.2 大小端介绍 四、浮点数在内存中的存储 编辑 4.…...
PyQT(PySide)的上下文菜单策略设置setContextMenuPolicy()
在 Qt 中,QWidget 类提供了几种不同的上下文菜单策略,这些策略通过 Qt::ContextMenuPolicy 枚举类型来定义,用于控制控件(如按钮、文本框等)在用户右键点击时如何显示上下文菜单。 以下是 Qt::ContextMenuPolicy 枚举中…...
BladeX框架接口请求跨域
前端使用代理请求接口,接口可以正常访问。如果换全路径请求就跨域。 除了后端要配置跨域 还需要修改配置文件对OPTIONS请求的限制...
如何在Apple不再支持的MacOS上安装Homebrew
手头有一台2012年产的Macbook Pro,系统版本停留在了10.15.7(2020年9月24日发布的)。MacOS 11及后续的版本都无法安装到这台老旧的电脑上。想通过pkg安装Homebrew,发现Homebrew releases里最新的pkg安装包不支持MacOS 10.15.7&…...
本地大模型编程实战(26)用langgraph实现基于SQL数据构建的问答系统(5)
本文将将扩展上一篇文章完成的 langgraph 链,继续使用基于 langgraph 链 ,对结构化数据库 SQlite 进行查询的方法。该系统建立以后,我们不需要掌握专业的 SQL 技能,可以用自然语言询问有关数据库中数据的问题并返回答案。主要完善…...
数据结构与算法:滑动窗口
前言 滑动窗口一般主要用于解决子数组或子串问题,这类的题目更看重对题目的分析和转化。 一、原理 在整个数组上,用l和r分别控制窗口的左右边界,r就扩大,l就减小。 当窗口的范围和题目中某个指标间存在单调关系时,…...
江协科技/江科大-51单片机入门教程——P[2-1] 点亮一个LED
本节将向大家介绍如何用 51 单片机去控制开发板上的 LED。开发板上的 LED 位置标注有 “LED 模块”。 第二章要写 3 个程序代码:第一个代码实现点亮开发板上的第一个 LED;第二个代码让第一个 LED 以 1 秒为周期闪烁;第三个代码使 8 个 LED 以…...
leetcode hot 100 41. 缺失的第一个正数
代码 测试用例 测试用例 测试结果 41. 缺失的第一个正数 已解答 困难 相关标签 相关企业 提示 给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。 请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。 示例 1…...
UniApp 使用 u-loadmore 完整步骤
文章目录 一、前期准备1. 安装 uView - UI 二、使用 u-loadmore组件1. 创建页面2. 编写页面代码模板部分(loadmore-demo.vue)样式部分脚本部分 三、要点补充1. u-loadmore 状态说明2. 数据请求优化3. 性能优化4. 兼容性问题 在 UniApp 开发中,…...
设置电脑一接通电源就主动开机
文章目录 1、进入BIOS2、设置4、功能弊端5、电脑自动开机的设置 1、进入BIOS 在电脑重启时,这时屏幕上会显示按XXX键到BIOS界面 没有进入BIOS提示的,按下面方法操作: 方法一 在开机显示logo的时候,立即按下面这几个按键…...
优艾智合机器人日本子公司成立,加速推进国际化布局
2月27日,工业移动机器人解决方案商优艾智合宣布日本子公司Youibot Robotics Japan株式会社(以下简称“Youibot Japan”)成立,并于东京举行开业典礼。此举标志着优艾智合在日本市场的现地服务能力进一步深化,是其全球化…...
自然语言处理NLP入门 -- 第七节预训练语言模型
1 什么是预训练模型? 在自然语言处理(NLP)里,训练一个好模型通常需要很多数据和计算资源。为了解决这个难题,就出现了“预训练模型”。 预训练模型 是指我们先在海量文本(比如网络上爬到的大量文章、对话…...
三步破解百度网盘限速:免费获取真实下载链接的终极指南
三步破解百度网盘限速:免费获取真实下载链接的终极指南 【免费下载链接】baidu-wangpan-parse 获取百度网盘分享文件的下载地址 项目地址: https://gitcode.com/gh_mirrors/ba/baidu-wangpan-parse 还在为百度网盘几十KB的龟速下载而苦恼吗?想要彻…...
BurpSuite+SqlMap深度集成:构建高可信SQL注入检测流水线
1. 这不是“点几下就出结果”的玩具,而是你真正能放进渗透流程里的SQL注入检测流水线很多人第一次看到“BurpSuiteSqlMap插件5分钟搞定SQL注入检测”这个标题,第一反应是:又一个标题党?点开全是截图堆砌、参数照抄、报错就卡住的半…...
抖音批量下载神器:5分钟学会免费无水印视频下载
抖音批量下载神器:5分钟学会免费无水印视频下载 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback support. 抖…...
Wand-Enhancer:完全免费解锁WeMod专业版功能的终极指南
Wand-Enhancer:完全免费解锁WeMod专业版功能的终极指南 【免费下载链接】Wand-Enhancer Advanced UX and interoperability extension for Wand (WeMod) app 项目地址: https://gitcode.com/gh_mirrors/we/Wand-Enhancer 还在为WeMod专业版的高昂订阅费用而烦…...
GraphpostgresQL高级用法:JSON、JSONB和HStore复杂数据类型的查询技巧
GraphpostgresQL高级用法:JSON、JSONB和HStore复杂数据类型的查询技巧 【免费下载链接】GraphpostgresQL GraphQL for Postgres 项目地址: https://gitcode.com/gh_mirrors/gr/GraphpostgresQL GraphpostgresQL作为PostgreSQL的GraphQL扩展,为开发…...
通过用量看板清晰观测Taotoken的API调用成本与消耗
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 通过用量看板清晰观测Taotoken的API调用成本与消耗 对于将大模型能力集成到产品中的团队而言,API调用成本是项目预算与…...
024、NPU指令集架构(ISA)概述:从CISC到VLIW
024、NPU指令集架构(ISA)概述:从CISC到VLIW 去年冬天调试一块国产NPU芯片的卷积算子,跑ResNet-50前向推理,死活比理论算力低了一个数量级。抓了三天波形,最后发现是指令发射槽的冲突——两条MAC指令争同一个数据总线,硬件自动插入三个空泡周期。那一刻我盯着逻辑分析仪…...
别光看手册!手把手教你读懂气体放电管(GDT)的6个关键参数,选型不踩坑
气体放电管实战选型指南:从参数表到电路设计的6个关键决策点 每次打开气体放电管(GDT)的英文数据手册,面对密密麻麻的参数表格和波形图,不少工程师都会陷入选择困难——这些数值到底如何影响实际电路保护效果…...
UE5 UMG界面开发避坑指南:WidgetComponent的ZOrder和图层管理到底怎么用?
UE5 UMG界面开发避坑指南:WidgetComponent的ZOrder和图层管理实战解析在虚幻引擎5的UMG界面开发中,WidgetComponent的渲染层级管理是一个看似简单却暗藏玄机的技术点。许多开发者在处理复杂UI系统时,常常会遇到控件遮挡混乱、图层顺序失控的问…...
崩坏星穹铁道自动化终极指南:3分钟学会解放双手的游戏助手
崩坏星穹铁道自动化终极指南:3分钟学会解放双手的游戏助手 【免费下载链接】StarRailAssistant 崩坏:星穹铁道自动化 | 崩坏:星穹铁道自动锄大地 | 崩坏:星穹铁道锄大地 | 自动锄大地 | 基于模拟按键 项目地址: https://gitcode…...
