STM32笔记:高精度脉冲宽度计 双输入捕获+DMA方式

2023-11-18

本文介绍如何用STM32F107VC(Waveshare Open107V实验板)实现高精度的脉冲宽度计(占空比)。

开发环境:

IDE:STM32CubeIDE 1.8

固件库:STM32Cube_FW_F1_V1.8.4

函数发生:RIGOL DG5072函数信号发生器,产生0-3.3V的方波,10KHz

硬件:Waveshare Open107V,STM32F107VC, 晶振25MHz,工作频率72MHz

思路:

*利用定时器的输入捕获功能测量方波的占空比,时钟为系统时钟72MHz。

*将Channel 1 (CH1)设为上升沿捕获,将Channel 2 (CH2)设为下降沿捕获,信号同时输入到CH1 和CH2.

*分别启用CH1和CH2的DMA,在捕获时刻将对应的捕获值送到对应的内存数组tcBuf[2][1024]。这样,在信号上升沿,CH1的比较寄存器自动获得当前计数值,并通过DMA存入到数组tcBuf[0][n],随后,在信号下降沿,CH2的比较寄存器自动获得当前计数值,通过DMA存入到数组tcBuf[1][n].

*用TIM2定时中断,每1秒钟计算一次脉冲宽度、频率值和占空比,发送到串口1。使用一组数据即可,或者可以多组取平均,或者进行滤波以提高精度。

*在串口1收到"DATA"指令时,停止全局中断,停止DMA,将tcBuf[0][0...1023]和tcBuf[1][0...1023]依次发回计算机。然后开启DMA,开启全局中断,继续。

测试结果:

占空比(%) 脉冲宽度(us) 频率(Hz) 误差(%)
50.014  50.014  10000.000  0.028 
49.993  50.000  9998.611  0.014 
50.000  50.000  10000.000  0.000 
50.000  50.000  10000.000  0.000 
50.021  50.014  10001.389  0.042 
49.993  50.000  9998.611  0.014 
50.000  50.000  10000.000  0.000 
50.014  50.014  10000.000  0.028 
50.014  50.014  10000.000  0.028 
49.993  50.000  9998.611  0.014 
50.000  50.000  10000.000  0.000 
50.014  50.014  10000.000  0.028 
50.000  50.000  10000.000  0.000 

注意:
        *对于1kHz以下的频率,一个周期超过了一次TIM1(16bit)的计数,需要进行更为复杂的处理,本程序没有实现,如果您做了,能否分享一下?感谢!
        *频率越高,精度越低。
        *10kHz信号的理论分辨率:1/7200 * 100% = 0.014%,实验结果符合的很好。

关键代码:  


uint16_t tcBuf[2][BUF_SIZE] = {0}; //全局变量,tcBuf[0][]存放上升沿TC,tcBuf[1][]存放下降沿TC


//main 函数中的TIM1_DMA初始化,没有使用中断
  HAL_TIM_IC_Start_DMA( &htim1,  TIM_CHANNEL_1, (uint32_t*)&(tcBuf[0]), BUF_SIZE);
  HAL_TIM_IC_Start_DMA( &htim1,  TIM_CHANNEL_2, (uint32_t*)&(tcBuf[1]), BUF_SIZE);


//计算脉冲宽度,频率和占空比,发送到串口,每1秒被调用一次
void GetPWM(void)
{
	uint16_t lenPulse = 0, lenPeriod;
	float pr = 0;
	lenPeriod = (tcBuf[0][1] > tcBuf[0][0]) ?  (tcBuf[0][1] - tcBuf[0][0]) : (0xFFFF - tcBuf[0][0] + tcBuf[0][1]);
	lenPulse =  (tcBuf[1][0] > tcBuf[0][0]) ?  (tcBuf[1][0] - tcBuf[0][0]) : (0xFFFF - tcBuf[0][0] + tcBuf[1][0]);
	if(lenPeriod != 0)
	{
		if(lenPulse > lenPeriod)
		{
			lenPulse = 0xFFFF - lenPulse;
			pr = 100.0f - (float)lenPulse * 100.0f / lenPeriod;
		}
		else pr = (float)lenPulse * 100.0f / lenPeriod;

		printf("Duty Ratio: %.3f\n", pr);

		pr = (float)lenPulse / 72.0f;

		printf("Pulse width: %.3f us\n", pr);

		pr = 72000000.0f / lenPeriod;

		printf("Period: %.1f Hz\n\n", pr);
	}
	else printf("Period: 0 Hz. No Input?? \n\n");
}


//Main while(1)中的串口指令相应程序段,将tcBuf内容发回计算机
		if(buf_uart1.index >= 1)
		{
			BSP_LED1_Blink(3, 100);//For delay and indication
			//HAL_Delay(300);
			strx = strstr((const char*)buf_uart1.buf,(const char*)"DATA");
			printf("%s\n", buf_uart1.buf);
			if(strx)
			{
				__disable_irq();
				  HAL_TIM_IC_Stop_DMA( &htim1,  TIM_CHANNEL_1);		//DMA should be stopped!!
				  HAL_TIM_IC_Stop_DMA( &htim1,  TIM_CHANNEL_2);
				printf("Rising Edge:\n");
				for(i = 0; i < BUF_SIZE; i++)
				{
					printf("%d\n", tcBuf[0][i]);
				}
				printf("Falling Edge:\n");
				for(i = 0; i < BUF_SIZE; i++)
				{
					printf("%d\n", tcBuf[1][i]);
				}
				  HAL_TIM_IC_Start_DMA( &htim1,  TIM_CHANNEL_1, (uint32_t*)&(tcBuf[0]), BUF_SIZE);
				  HAL_TIM_IC_Start_DMA( &htim1,  TIM_CHANNEL_2, (uint32_t*)&(tcBuf[1]), BUF_SIZE);
				__enable_irq();
			}
			Clear_Buffer_UART1();
		}

详细代码请见:

高精度脉冲宽度计双输入捕获+DMA方式-硬件开发文档类资源-CSDN下载

抛砖引玉,如果程序有Bug或者您有改进意见,请您积极留言,非常感谢!
    
 

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

STM32笔记:高精度脉冲宽度计 双输入捕获+DMA方式 的相关文章

  • 在 ARMv7 的上下文中,当 mmu 必须进行页表转换时,Linux 内核一对一映射内存的优势是什么

    Linux内核虚拟地址是一对一映射 所以通过减去一个PAGE OFFSET到虚拟地址我们将得到物理地址 就是那样virt to phys http lxr free electrons com source arch arm include
  • Windows 8 ARM(A.K.A.)吗? “Windows RT”有可供第三方开发人员使用的 Winapi (win32) 吗?

    Windows 8 for ARM 也称为 Windows RT 它是否具有与 Win32 API 等效的功能 I don t意味着它是否可以运行 Win32 x86 代码 但如果它具有 Win32 API可用的给第三方开发商 是的 ARM
  • STM32 上的位置无关代码 - 指针

    我已成功在 STM32 上构建并运行位置无关的代码 向量表和 GOT 已修补 一切正常 但我对这样的代码有问题 double myAdd double x return x 0 1 double ptrmyAdd double myAdd
  • ARM 未定义指令错误

    我在运行嵌入式系统 无协处理器 无 MMU Atmel 9263 时收到未定义指令错误 嵌入式系统的内存范围为 0x20000000 0x23FFFFFF 目前为止我遇到过两个案例 SP 0x0030B840 LR 2000AE78 LR指
  • 抢占和上下文切换的区别

    一点介绍 我目前正在编写一个小型 读微型 RTOS 内核 它应该与内核中的大多数内容是一体的 然而 我找不到关于下面列出的一些事情的太多信息 这会很有帮助 除此之外 它实际上不是某种大学项目 而是我按照自己的意愿做的事情 回答所有问题的一个
  • 在 Contiki 程序中使用 malloc

    考虑以下 Contiki 程序 include
  • Android 上原生的自修改代码

    我正在尝试在 Android 上制作一些自修改本机代码并在模拟器中运行它 我的示例基于 android ndk 中的 Hello JNI 示例 它看起来像这样 define NOPE LENGTH 4 typedef void FUNC v
  • ARM 9处理器的opencv交叉编译

    我需要为 ARM 9 处理器交叉编译 opencv 我有处理器的工具链 但不知道如何交叉编译 请告诉我为arm板交叉编译的过程 谢谢大家 看这个参考 http www airs com ian configure configure 5 h
  • 将ELF文件加载到内存中

    我正在尝试将 elf 文件放入内存然后执行它 步骤如下 1 要放入内存的文件 int main printf Hello world n return 0 2 编译它gcc o hello hello c static ELF Header
  • 如何在 ARM 架构上从 RAM 运行代码

    我正在对 ARM Cortex R4 进行编程 并且有一些二进制文件 我想从 TCRAM 执行它们 只是为了看看性能的提升是否足够好 我知道我必须编写一个函数来将二进制文件复制到 RAM 这可以通过链接器脚本来完成 并且知道二进制文件的大小
  • 如何修改内核DTB文件

    Summary 我目前正在为定制板编译 Linux 内核 内核 模块和 DTB 以及一些定制驱动程序 有时 我会编译内核并意识到 DTB 文件中的兼容性字符串不是自定义驱动程序正在寻找的内容 现在 我可以解决此问题的唯一方法是修改 DTS
  • ARM 汇编分支到寄存器或内存内部的地址

    我想知道在 ARM 汇编中我可以使用哪条指令分支到存储在某个内存地址中的地址或标签 例如 我们可以使用B LABEL来跳转到LABEL 但现在目的地只能在运行时知道 并且它存储在某个已知的内存位置 是否有类似 B 地址 的东西 Thanks
  • 在 ARM 处理器上执行存储在外部 SPI 闪存中的程序

    我有一个 ARM 处理器 能够与外部闪存芯片连接 写入芯片的是为 ARM 架构编译的程序 可供执行 我需要知道如何将这些数据从外部闪存获取到 ARM 处理器上以供执行 我可以提前运行某种复制例程 将数据复制到可执行内存空间吗 我想我可以 但
  • 小型 ARM 微控制器的 RTOS 内核之间的可量化差异 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 有许多不同的 RTOS 可用于微控制器 我专门寻找支持 ARM Cortex M 处理器的 RTOS 另外 我对闭源解决方案不感兴趣 试图从网站
  • DSP 库 - RFFT - 奇怪的结果

    最近我一直在尝试在我的STM32F4 Discovery评估板上进行FFT计算 然后将其发送到PC 我已经调查了我的问题 我认为我对制造商提供的 FFT 函数做错了 我正在使用 CMSIS DSP 库 现在我一直在用代码生成样本 如果工作正
  • 在嵌入式设备上使用new或malloc引起的段错误[关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我正在尝试
  • ARM 中只有两个操作数的 ADD 或 SUB

    我正在学习ARM汇编语言 我读过 ADD 应该有 3 个操作数 然而 我见过很多案例 现实中只有两种 例如 STR R1 SP 0x20 var 1C LDR R1 a lua 0x1DE4E6 MOVS R0 R4 haystack AD
  • 读取和打印手臂组件中的字符串

    我正在使用 ARMSim 刚刚开始学习汇编 所以如果我看起来一无所知 请原谅我 但我正在尝试从输入文件中读取字符串 然后将其打印到输出屏幕 到目前为止我有 equ SWI Open 0x66 open a file equ SWI Clos
  • 有没有办法在 Xcode 4 中为 ARM 而不是 Thumb 进行编译?

    如果有很多浮点运算正在进行 Apple 建议针对 ARM 进行编译 而不是针对拇指进行编译 我的整个应用程序几乎是一个大型浮点运算 iOS 应用程序开发工作流程指南中是这样说的 iOS 设备支持两种指令集 ARM 和 Thumb Xcode
  • 使用 Android NDK 使用 -fsigned-char 进行构建安全吗?

    为了与其他平台保持一致 我需要使用signed char在我正在处理的一些本机代码中 但默认情况下在Android NDK上char类型是unsigned 我尝试明确使用signed char类型 但它生成太多警告differ in sig

随机推荐

  • java.awt.Color类

    Color类概述 Color是用来封装颜色的 支持多种颜色空间 默认为RGB颜色空间 每个Color对象都有一个alpha通道 值为0到255 代表透明度 当alpha通道值为255时 表示完全不透明 当alpha通道值为0时 表示完全透明
  • Cordova环境搭建/win10下必备依赖环境配置(Android开发)

    Cordova环境依赖 1 win10系统 2 Java环境 3 Node环境 4 AndroidStudio 5 Ant 6 Gradle 安装node环境 1 使用node官网网址下载node包 最好使用稳定版本 https nodej
  • 从C过渡到C ++的3个理由

    几十年来 嵌入式软件工程师之间一直在争论他们应该使用C还是C 根据2020年嵌入式市场调查 在大多数情况下 微控制器制造商提供的软件都以C语言提供 实际上 有56 的嵌入式软件是用C语言编写的 但是 C 逐渐流行起来 大约23 的新嵌入式软
  • Java面向对象编程

    主机甲和乙已建立了TCP连接 甲始终以MSS 1KB大小的段发送数据 并一直有数据发送 乙每收到一个数据段都会发出一个接收窗口为10KB的确认段 若甲在t时刻发生超时时拥塞窗口为8KB 则从t时刻起 不再发生超时的情况下 经过10个RTT后
  • Ubuntu安装git

    使用 apt get install git 安装git 报错 这个错误信息通常表示您的系统上没有可用的 git 软件包 这可能是因为您的软件源列表中没有包含 git 软件包所在的软件源 或者您的软件源列表已经过期 解决 如果您使用的是 U
  • RuntimeError: Attempting to deserialize object on CUDA device 1 but torch.cuda.device_count() is 1.

    成功解决 RuntimeError Attempting to deserialize object on CUDA device 1 but torch cuda device count is 1 报错内容 程序在这一步报错 check
  • Android kotlin自定义自动换行LinearLayout

    目录 1 概述 2 实现步骤 3 kotlin自定义自动换行LinearLayout核心代码实现功能 3 1自定义LinearLayout
  • spring快速入门

    1 导入坐标
  • stack容器

    stack容器 1 stack 基本概念 概念 stack是一种先进后出 First In Last Out FILO 的数据结构 它只有一个出口 栈中只有顶端的元素才可以被外界使用 因此栈不允许有遍历行为 栈中进入数据称为 入栈 push
  • dll load failed: 找不到指定的模块_【已解决】“由于找不到xinput1_3.dll,无法继续执行代码”...

    许多小伙伴在玩游戏或者使用电脑的过程中 电脑突然提示 由于找不到xinput1 3 dll 无法继续执行代码 导致游戏等程序无法正常启动运行 并且导致电脑系统弹窗报错 那xinput1 3 dll丢失怎么修复呢 下面让小编手把手教你解决方法
  • CentOS7安装OpenStack(Liberty)

    1 安装yum源 yum install https buildlogs centos org centos 7 cloud x86 64 openstack liberty centos release openstack liberty
  • 百度智能云千帆大模型三连击:接入LLaMA2等33个模型、上线插件功能和103个Prompt模板

    作为全球首个一站式企业级大模型平台 百度智能云 千帆大模型平台 在提供包括文心一言在内的大模型服务及第三方大模型服务的同时 还提供大模型开发和应用的整套工具链 帮助企业解决大模型从训练到开发过程中的全链条问题 自2023年3月发布以来 千帆
  • 看懂android中的adapter适配器

    首先需要知道一共有4个文件 fragment类 adapter fragment的布局文件 adapter中的item的布局文件 1 首先声明一个控件 RecyclerView 2 然后声明一个adapter类 3 在initView 上
  • python中typeerror_详解python中的TypeError错误解决办法

    新手在学习python时候 会遇到很多的坑 下面来具体说说其中一个 在使用python编写面向对象的程序时 新手可能遇到TypeError this constructor takes no arguments这个错误 例如下面的程序 cl
  • gtest 单元测试工具的基本使用

    gtest 单元测试 gtest 简介 gtest 优点 安装 gtest 测试 demo 总结 gtest 简介 gtest是Google的一套用于编写C 测试的框架 可以运行在很多平台上 包括Linux Mac OS X Windows
  • 获取时间和脸颊、下颚线灯模式

    电流检测的应用 电路检测电路常用于 高压短路保护 电机控制 DC DC换流器 系统功耗管理 二次电池的电流管理 蓄电池管理等电流检测等场景 对于大部分应用 都是通过感测电阻两端的压降测量电流 一般使用电流通过时的压降为数十mV 数百mV的电
  • android动画内存优化,Android 性能优化之内存优化

    定义 内存泄漏 Memory Leak 指 程序在申请内存后 当该内存不需再使用但却无法被释放的现象 内存溢出 OOM 应用程序所需的内存超出了为其分配的内存限额 Android将进程分为5个优先等级 前台进程 可见进程 服务进程 后台进程
  • google.api.http

    Http 定义api服务的http配置 它包含一个httprule列表 每个列表指定一个rpc方法到一个或多个http rest api方法的映射 字段 描述 rules HttpRule 一个适用于各个API方法的http配置规则列表 注
  • 编译优化之 - 向量化优化入门

    1 介绍 2 Intel高级向量扩展 3 GCC中向量化 4 ICC中向量化 5 AOCC LLVM中向量化 1 介绍 什么是自动向量化 自动向量化 automatic vectorization 是自动并行化 automatic para
  • STM32笔记:高精度脉冲宽度计 双输入捕获+DMA方式

    本文介绍如何用STM32F107VC Waveshare Open107V实验板 实现高精度的脉冲宽度计 占空比 开发环境 IDE STM32CubeIDE 1 8 固件库 STM32Cube FW F1 V1 8 4 函数发生 RIGOL