基于STM32的心率计(1):DMA方式获取传感器数据

原创 电子电路开发学习 2024-06-25 21:13


前言

最近利用下班后的时间,做了个心率计,从单片机程序到上位机开发,到现在为止完成的差不多了,实现很简单,uFUN开发板外加一个PulseSensor传感器就行,又开发了配套的串口上位机,实现数据的解析和显示,运行界面如下:

其实PulseSensor官方已经配备的了Processing语言编写的上位机软件,串口协议的,界面还蛮好看,只要按照它的通信协议,就可以实现心跳波形和心率的显示。刚好最近学习了Qt,所以就用这个小软件来练手了。本篇文章是这个小项目的第一篇,介绍一下如何使用DMA方式获取传感器的数据,至于后面几篇文章会写什么,欢迎大家保持关注哈!

传感器介绍

PulseSensor 是一款用于脉搏心率测量的光电反射式模拟传感器。将其佩戴于手指、耳垂等处,利用人体组织在血管搏动时造成透光率不同来进行脉搏测量。传感器对光电信号进行滤波、放大,最终输出模拟电压值。单片机通过将采集到的模拟信号值转换为数字信号,再通过简单计算就可以得到心率数值。

信号输出引脚连接到示波器,看一下是什么样的信号:

可以看出信号随着心跳起伏变化,周期大概为:1.37/2 = 0.685s。计算出心率值为:600 / 0.685 = 87,我的心率在正常范围内(废话!),这个传感器测心率还是可以的。手头上没有传感器的朋友,可以看一下这篇自制心率传感器的教程:手指检测心跳设计——传感器制作篇,这篇文章介绍的使用一个红外发射管和一个红外接收管,外加放大滤波电路,效果还是挺不错的。

AD采集电路的分析

大家在使用ADC接口的时候要注意了,线别插错了。我第一次使用就是测不到电压值,后来用万用表量了一下,才发现是入门指南中引脚功能标示错了,要采集AD电压,输入脚应该接DCIN这个,对应的是PC3-ADC_IN13。如下图。可能是由于原理图版本的迭代,入门指南没有来得及更新吧!手动@管理员 更改一下。

从原理图中可以看出,直流电压采集电路前级采用双T陷波滤波器滤除50Hz工频干扰,后级为运放电路:

关于前级的双T陷波滤波器S域分析,可以参考这篇文章:双T陷波器s域计算分析(纯手算,工程版!)

大学期间学得信号与系统都忘了,所以这部分计算我没有看懂。其实了解电路的S域分析,更有利于理解电路的特性,大家还是要掌握好理论基础。

后面的运放电路,还是大概能看懂的,下面来分析一下直流通路,把电容看作断路:

所有的运放电路分析,就记住两个要点就行了:虚短和虚断。(感觉又回到了大学。。。。)

虚短:理解成短路,运放处于线性状态时,把两输入端视为等电位,即运放正输入端和负输入端的电压相等,即U+ = U-。

虚断:理解成断路,运放处于线性状态时,把两输入端视为开路,即流入正负输入端的电流为零。

总结一句话:虚短即U+=U-;虚断即净输入电流为0。

好了,有了这两把利器,我们来看一下这部分电路的分析,直流通路可进一步简化为:

很明显,可计算出

  1. U+ = 0.5 * VCC = 1.65v

应用虚短:

  1. U- = U+ = 1.65v

应用虚断,即没有电流流入运放,根据串联电流相等:

以上三式联立,可得:

  1. Uo = 3.368 - 1.205*Ui

即:

  1. Ui = 3 - 0.83 * Uo

只要得到单片机采集到的电压值Uo,就可以反推出实际的传感器电压值Ui。

通过使用示波器测量Ui和Uo的波形,近似可以认为是反向的,但是明显可以看出,Uo的峰值比Ui的峰值小一点。

而且通过绘制 Ui=3-0.83*UoUi=3.3-Uo的曲线,也可以看出,两条直线几乎重合,即输入和输出近似为反向。

DMA简介

DMA,即直接存储器,用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须 CPU任何干预,通过DMA数据可以快速地移动。这就节省了CPU的资源来做其他操作。STM32共有两个DMA控制器有12个通道(DMA1有7个通道,DMA2有5个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。

关于DMA通道和外设的对应,可以查看STM32参考手册,心率传感器使用的PC3-ADC_IN13,对应的是DMA1的通道1

STM32 DMA程序配置

获取ADC通道的电压值主要有两种方式,一种是直接使用ADC,然后在需要使用的地方,先启动AD转换,然后读取AD值。另一种更好的方式是使用DMA方式,就是先定义一个保存AD值的全局变量,而全局变量是对应内存中的一个地址的。只要初始时,把DMA和ADC配置好了,DMA会自动把获取到的AD值,存入这个地址中,我们在需要的时候,直接读取这个值就可以了。

0.定义一个全局变量

必须是全局变量,用于存放AD值。

  1. uint16_t ADC_ConvertedValue;

1.配置GPIO和使能时钟

使能外设对应的时钟,注意时钟总线的不同:

  1. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  2. RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);

引脚配置成模拟输入模式:

  1. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;

  2. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //设置为模拟输入

  3. GPIO_Init(GPIOC, &GPIO_InitStructure);

2.配置DMA

配置ADC对应的DAM1通道1:

  1. DMA_DeInit(DMA1_Channel1);

  2. DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC1->DR)); //设置源地址

  3. DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_ConvertedValue; //设置内存地址

  4. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 设置传输方向

  5. DMA_InitStructure.DMA_BufferSize = 1;

  6. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

  7. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;

  8. DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

  9. DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

  10. DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //循环模式

  11. DMA_InitStructure.DMA_Priority = DMA_Priority_High; //高优先级

  12. DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

  13. DMA_Init(DMA1_Channel1, &DMA_InitStructure);

  14. DMA_Cmd(DMA1_Channel1, ENABLE); //使能DMA1通道1

3.配置ADC

由于只有1个通道,不需要配置成扫描模式:

  1. ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

  2. ADC_InitStructure.ADC_ScanConvMode = DISABLE ;

  3. ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

  4. ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

  5. ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

  6. ADC_InitStructure.ADC_NbrOfChannel = 1;

  7. ADC_Init(ADC1, &ADC_InitStructure);

PC3对应ADC输入通道13,注意采样周期不能太短:

  1. ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 1, ADC_SampleTime_55Cycles5);

  2. ADC_DMACmd(ADC1, ENABLE);

  3. ADC_Cmd(ADC1, ENABLE);

  4. ADC_ResetCalibration(ADC1);

  5. while(ADC_GetResetCalibrationStatus(ADC1));

  6. ADC_StartCalibration(ADC1);

  7. while(ADC_GetCalibrationStatus(ADC1));

  8. ADC_SoftwareStartConvCmd(ADC1, ENABLE);

4.主程序调用

DMA和ADC配置好之后,只需要初始化一次。然后就可以随时获取电压值了。

  1. int main(void)

  2. {

  3. float Sensor_Voltage;

  4. float Uo_Voltage;

  5. delay_init();

  6. UART1_Config(115200);

  7. ADC1_Init();

  8. while(1)

  9. {

  10. Uo_Voltage = ADC_ConvertedValue * 3.3 / 4096;

  11. Sensor_Voltage = 3.3 - Uo_Voltage; //近似值

  12. // Sensor_Voltage = 3 - 0.83 * Uo_Voltage; //实际传感器输出电压值

  13. ANO_SendFloat(0xA1, Sensor_Voltage);

  14. delay_ms(10);

  15. }

  16. }

为了方便查看数据的波形,这里直接使用了匿名上位机来显示电压值的波形。

函数实现

  1. //匿名上位机,波形显示一个浮点型数据ANO_SendFloat(0xA1, ad);

  2. void ANO_SendFloat(int channel, float f_dat)

  3. {

  4. u8 tbuf[8];

  5. int i;

  6. unsigned char* p;

  7. for(i = 0; i <= 7; i++)

  8. tbuf[i] = 0;

  9. p = (unsigned char*)&f_dat;

  10. tbuf[0] = 0x88;

  11. tbuf[1] = channel; //0xA1

  12. tbuf[2] = 4;

  13. tbuf[3] = (unsigned char)(*(p + 3)); //取float类型数据存储在内存中的四个字节

  14. tbuf[4] = (unsigned char)(*(p + 2));

  15. tbuf[5] = (unsigned char)(*(p + 1));

  16. tbuf[6] = (unsigned char)(*(p + 0));

  17. for(i = 0; i <= 6; i++)

  18. tbuf[7] += tbuf[i]; //校验和

  19. printf("%s", tbuf);

  20. }

实际的显示

没有调试器,如何下载程序呢?可以参考我之前发的一篇帖子:如何使用串口来给STM32下载程序,详细介绍了如何通过串口来给uFUN开发板下载程序。

匿名上位机的帧格式配置

实际的显示效果:

总结

传感器数据的获取,只是心率计实现的第一步,传感器放置位置的不同,波形的振幅也会不同,所以,对获得数据的处理、分析,才是最关键的部分。

资料下载

  • STM32工程下载:STM32工程

  • STM32参考手册下载:STM32参考手册

  • 匿名上位机下载: 匿名上位机

参考资料

  • PulseSensor官网:

    https://pulsesensor.com/

  • 手指检测心跳设计——传感器制作篇:

    https://blog.csdn.net/qq_34445388/article/details/79781181

  • 玩的就是心跳 —— 使用 PulseSensor 脉搏传感器测量心率:

    http://www.shaoguoji.cn/2017/06/29/use-pulsesensor-with-stm32/

  • 双T陷波器s域计算分析(纯手算,工程版!)

    http://bbs.eeworld.com.cn/thread-498219-1-1.html


电子电路开发学习 单片机点灯小能手,电子行业从业者。开发板评测、嵌入式开源项目分享、学习笔记记录。可能不会经常更新,但每一篇都是精心编写。
评论
  • 在智能家居领域中,Wi-Fi、蓝牙、Zigbee、Thread与Z-Wave等无线通信协议是构建短距物联局域网的关键手段,它们常在实际应用中交叉运用,以满足智能家居生态系统多样化的功能需求。然而,这些协议之间并未遵循统一的互通标准,缺乏直接的互操作性,在进行组网时需要引入额外的网关作为“翻译桥梁”,极大地增加了系统的复杂性。 同时,Apple HomeKit、SamSung SmartThings、Amazon Alexa、Google Home等主流智能家居平台为了提升市占率与消费者
    华普微HOPERF 2025-01-06 17:23 88浏览
  • 在快速发展的能源领域,发电厂是发电的支柱,效率和安全性至关重要。在这种背景下,国产数字隔离器已成为现代化和优化发电厂运营的重要组成部分。本文探讨了这些设备在提高性能方面的重要性,同时展示了中国在生产可靠且具有成本效益的数字隔离器方面的进步。什么是数字隔离器?数字隔离器充当屏障,在电气上将系统的不同部分隔离开来,同时允许无缝数据传输。在发电厂中,它们保护敏感的控制电路免受高压尖峰的影响,确保准确的信号处理,并在恶劣条件下保持系统完整性。中国国产数字隔离器经历了重大创新,在许多方面达到甚至超过了全球
    克里雅半导体科技 2025-01-03 16:10 122浏览
  • 光耦合器,也称为光隔离器,是一种利用光在两个隔离电路之间传输电信号的组件。在医疗领域,确保患者安全和设备可靠性至关重要。在众多有助于医疗设备安全性和效率的组件中,光耦合器起着至关重要的作用。这些紧凑型设备经常被忽视,但对于隔离高压和防止敏感医疗设备中的电气危害却是必不可少的。本文深入探讨了光耦合器的功能、其在医疗应用中的重要性以及其实际使用示例。什么是光耦合器?它通常由以下部分组成:LED(发光二极管):将电信号转换为光。光电探测器(例如光电晶体管):检测光并将其转换回电信号。这种布置确保输入和
    腾恩科技-彭工 2025-01-03 16:27 171浏览
  • 这篇内容主要讨论三个基本问题,硅电容是什么,为什么要使用硅电容,如何正确使用硅电容?1.  硅电容是什么首先我们需要了解电容是什么?物理学上电容的概念指的是给定电位差下自由电荷的储藏量,记为C,单位是F,指的是容纳电荷的能力,C=εS/d=ε0εrS/4πkd(真空)=Q/U。百度百科上电容器的概念指的是两个相互靠近的导体,中间夹一层不导电的绝缘介质。通过观察电容本身的定义公式中可以看到,在各个变量中比较能够改变的就是εr,S和d,也就是介质的介电常数,金属板有效相对面积以及距离。当前
    知白 2025-01-06 12:04 110浏览
  • 车身域是指负责管理和控制汽车车身相关功能的一个功能域,在汽车域控系统中起着至关重要的作用。它涵盖了车门、车窗、车灯、雨刮器等各种与车身相关的功能模块。与汽车电子电气架构升级相一致,车身域发展亦可以划分为三个阶段,功能集成愈加丰富:第一阶段为分布式架构:对应BCM车身控制模块,包含灯光、雨刮、门窗等传统车身控制功能。第二阶段为域集中架构:对应BDC/CEM域控制器,在BCM基础上集成网关、PEPS等。第三阶段为SOA理念下的中央集中架构:VIU/ZCU区域控制器,在BDC/CEM基础上集成VCU、
    北汇信息 2025-01-03 16:01 193浏览
  • 根据Global Info Research项目团队最新调研,预计2030年全球封闭式电机产值达到1425百万美元,2024-2030年期间年复合增长率CAGR为3.4%。 封闭式电机是一种电动机,其外壳设计为密闭结构,通常用于要求较高的防护等级的应用场合。封闭式电机可以有效防止外部灰尘、水分和其他污染物进入内部,从而保护电机的内部组件,延长其使用寿命。 环洋市场咨询机构出版的调研分析报告【全球封闭式电机行业总体规模、主要厂商及IPO上市调研报告,2025-2031】研究全球封闭式电机总体规
    GIRtina 2025-01-06 11:10 80浏览
  • 自动化已成为现代制造业的基石,而驱动隔离器作为关键组件,在提升效率、精度和可靠性方面起到了不可或缺的作用。随着工业技术不断革新,驱动隔离器正助力自动化生产设备适应新兴趋势,并推动行业未来的发展。本文将探讨自动化的核心趋势及驱动隔离器在其中的重要角色。自动化领域的新兴趋势智能工厂的崛起智能工厂已成为自动化生产的新标杆。通过结合物联网(IoT)、人工智能(AI)和机器学习(ML),智能工厂实现了实时监控和动态决策。驱动隔离器在其中至关重要,它确保了传感器、执行器和控制单元之间的信号完整性,同时提供高
    腾恩科技-彭工 2025-01-03 16:28 166浏览
  • 在测试XTS时会遇到修改产品属性、SElinux权限、等一些内容,修改源码再编译很费时。今天为大家介绍一个便捷的方法,让OpenHarmony通过挂载镜像来修改镜像内容!触觉智能Purple Pi OH鸿蒙开发板演示。搭载了瑞芯微RK3566四核处理器,树莓派卡片电脑设计,支持开源鸿蒙OpenHarmony3.2-5.0系统,适合鸿蒙开发入门学习。挂载镜像首先,将要修改内容的镜像传入虚拟机当中,并创建一个要挂载镜像的文件夹,如下图:之后通过挂载命令将system.img镜像挂载到sys
    Industio_触觉智能 2025-01-03 11:39 115浏览
  • 本文介绍Linux系统更换开机logo方法教程,通用RK3566、RK3568、RK3588、RK3576等开发板,触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。制作图片开机logo图片制作注意事项(1)图片必须为bmp格式;(2)图片大小不能大于4MB;(3)BMP位深最大是32,建议设置为8;(4)图片名称为logo.bmp和logo_kernel.bmp;开机
    Industio_触觉智能 2025-01-06 10:43 72浏览
  • 随着市场需求不断的变化,各行各业对CPU的要求越来越高,特别是近几年流行的 AIOT,为了有更好的用户体验,CPU的算力就要求更高了。今天为大家推荐由米尔基于瑞芯微RK3576处理器推出的MYC-LR3576核心板及开发板。关于RK3576处理器国产CPU,是这些年的骄傲,华为手机全国产化,国人一片呼声,再也不用卡脖子了。RK3576处理器,就是一款由国产是厂商瑞芯微,今年第二季推出的全新通用型的高性能SOC芯片,这款CPU到底有多么的高性能,下面看看它的几个特性:8核心6 TOPS超强算力双千
    米尔电子嵌入式 2025-01-03 17:04 48浏览
  • 物联网(IoT)的快速发展彻底改变了从智能家居到工业自动化等各个行业。由于物联网系统需要高效、可靠且紧凑的组件来处理众多传感器、执行器和通信设备,国产固态继电器(SSR)已成为满足中国这些需求的关键解决方案。本文探讨了国产SSR如何满足物联网应用的需求,重点介绍了它们的优势、技术能力以及在现实场景中的应用。了解物联网中的固态继电器固态继电器是一种电子开关设备,它使用半导体而不是机械触点来控制负载。与传统的机械继电器不同,固态继电器具有以下优势:快速切换:确保精确快速的响应,这对于实时物联网系统至
    克里雅半导体科技 2025-01-03 16:11 176浏览
  • 彼得·德鲁克被誉为“现代管理学之父”,他的管理思想影响了无数企业和管理者。然而,关于他的书籍分类,一种流行的说法令人感到困惑:德鲁克一生写了39本书,其中15本是关于管理的,而其中“专门写工商企业或为企业管理者写的”只有两本——《为成果而管理》和《创新与企业家精神》。这样的表述广为流传,但深入探讨后却发现并不完全准确。让我们一起重新审视这一说法,解析其中的矛盾与根源,进而重新认识德鲁克的管理思想及其著作的真正价值。从《创新与企业家精神》看德鲁克的视角《创新与企业家精神》通常被认为是一本专为企业管
    优思学院 2025-01-06 12:03 76浏览
  • PLC组态方式主要有三种,每种都有其独特的特点和适用场景。下面来简单说说: 1. 硬件组态   定义:硬件组态指的是选择适合的PLC型号、I/O模块、通信模块等硬件组件,并按照实际需求进行连接和配置。    灵活性:这种方式允许用户根据项目需求自由搭配硬件组件,具有较高的灵活性。    成本:可能需要额外的硬件购买成本,适用于对系统性能和扩展性有较高要求的场合。 2. 软件组态   定义:软件组态主要是通过PLC
    丙丁先生 2025-01-06 09:23 71浏览
  •     为控制片内设备并且查询其工作状态,MCU内部总是有一组特殊功能寄存器(SFR,Special Function Register)。    使用Eclipse环境调试MCU程序时,可以利用 Peripheral Registers Viewer来查看SFR。这个小工具是怎样知道某个型号的MCU有怎样的寄存器定义呢?它使用一种描述性的文本文件——SVD文件。这个文件存储在下面红色字体的路径下。    例:南京沁恒  &n
    电子知识打边炉 2025-01-04 20:04 79浏览
  • 每日可见的315MHz和433MHz遥控模块,你能分清楚吗?众所周知,一套遥控设备主要由发射部分和接收部分组成,发射器可以将控制者的控制按键经过编码,调制到射频信号上面,然后经天线发射出无线信号。而接收器是将天线接收到的无线信号进行解码,从而得到与控制按键相对应的信号,然后再去控制相应的设备工作。当前,常见的遥控设备主要分为红外遥控与无线电遥控两大类,其主要区别为所采用的载波频率及其应用场景不一致。红外遥控设备所采用的射频信号频率一般为38kHz,通常应用在电视、投影仪等设备中;而无线电遥控设备
    华普微HOPERF 2025-01-06 15:29 81浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦