Goal

  1. 配置USART1为异步通讯模式,波特率为115200,配置PA1为ADC单通道(中断或者DMA均可)采集模式
  2. 使用AD8232心电采集模块,配置相应的其余IO口
  3. 功能:(1)将测到的心电数据转换成电压,并通过串口输出;  (2) 通过算法计算心率,每一分钟通过串口打印

Background

模数转换器(ADC)【以光敏电阻传感器模块为例】

图 1 5V容忍I/O端口位的基本结构

把GPIO口设置为读取模式,信号从GPIO口经过TTL施密特触发器输入数据到寄存器,TTL施密特触发器可以把连续信号通过一个分界线,将模拟信号在界限上的部分转换为高电平脉冲并将界限下的部分转换为低电平脉冲。通过一个“模拟”功能,将GPIO进入的信号输入模拟口也即AD口,把连续信号模拟量转化为数字量接到外设。

输入GPIO口的模拟量在此以光敏电阻传感器的模拟值变化为例。

图 2 光敏电阻传感器原理图

光敏二极管依照光强改变阻值Rgm,VAD = Rgm/(Rgm+10k)*3.3V,单片机这个AD口就是把接收到的VAD电压转换为程序中读取的值。

心电模块(AD8232)

表 1 Pins of AD8232

GND 接地

3.3V 给模块供电电源

OUT 运放输出端,接到ADC的输入端

LOD-,LOD+接到身上的三个电极,导联脱落,这两个口某一个口会变为高电平,所以将这两个口接到输入口上

SDN 开启和关闭模块功能,接到GPIO输出口,给它高电平则模块工作,给低电平则不工作。

图 3 电极连接方式

Experiment Steps

CubeIDE UART的中断配置

根据题意配置USART1为异步通讯模式Asynchronous,波特率为115200 Bits/s,字长为8 Bits。

勾选ADC1为IN1模式。对其进行参数设定。

PCLK2 divided by 4 (板子电压3.3V,对应最高频率为36MHz,在时钟设置时PCLK2为84MHz,分频要小于最高频率,所以选择divided 4)

表 2 ADC 特性

Resolution分辨率:VAD的值转换进单片机有多大是取决于Resolution, 12 bits 表示212,0-4096,把3.3V划分到4096份中,决定采样数据多精细。3.3/4096 = 0.000805V,就是最小能采集到0.000805V的电压。

Alignment:一个字节8位需要两个字节存储,则有4位的空闲,左对齐和右对齐,低八位和高八位,先填充低八位还是高八位的问题。选择Left alignment和Right alignment都行。

Scan Conversion Mode: 扫描模式,不用一个个开启AD口,但是现在只需要一个AD口所以Disabled。

Continuous Conversion Mode:每次采集完一个数据会自动开启下一个采集循环,所以Enabled。

Discontinuous Conversion Mode:和上面相反,选择Disabled。

DMA Continuous Requests:用的是中断所以不使能DMA。

End Of Conversion Selection: 采集单通道进入一次中断,还是把所有通道转化完再进入中断,正常一般选择采集全部通道再进入中断EOC flag at the end of all conversions。

Number Of Conversion: 采集通道数量。

External Trigger Conversion Source:用软件触发还是用定时器触发,选择软件触发。

Rank: 排序,谁先采集谁后采集的排序问题,该例子中只采集一个信号通道故为1。

PCLK2最高为84MHz,分为4份,即21MHz,一个机器周期时间为1/21000000=4.7619e-8 一个机器周期的时间,每一次需要(Sampling Time)三个机器周期采样,需要12个机器周期将数据放到12位,每采集一个数据的转换时间为一个机器周期的时间乘(12+3) = 7.14286e-7s,因为每采集完一个数据就会进入一次中断,程序执行中进入中断次数太多,把采样时间设置大些,到480Cycles。

NVIC Settings:使能中断。

在NVIC中勾选ADC1,ADC2 and ADC3 global... 把中断从main函数分离出来,Code Generator中勾选Generate peripheral Initialization as a pair of ...把函数从main中分离出来。

生成代码。

在main函数中MX_ADC1_Init();进入adc.c,在adc.c中在void MX_ADC1_Init(void)中调用HAL_ADC_Start_IT(&hadc1); 开启中断。因为要HAL_ADC_Star_IT要传入指针,所以加个&给hadc1代表地址。

在it.c中找到ADC_IRQHandler点进去找到HAL_ADC_IRQHandler,在它里面找到HAL_ADC_ConvCpltCallback点进去,然后复制代码到main.c。

变量值没有正负之分则用unsigned,定义全局变量unsigned int ADC_Value = 0, 在函数中写if(hadc == &hadc1){ADC_Value = HAL_ADC_GetValue(hadc)};

(Get一般用在内部模块,Read一般用在GPIO)

在while中写入

sprintf(buff, “V = %.3f V\r\n”, ADC_Value * 3.3 / 4096.0);

HAL_UART_Transmit(&huart1, buff, strlen(buff), 5000);

HAL_Delay(500);

在int main中定义uint8_t buff[1024] = {0}; 通过buff将数据输出到串口。

【如果输入sprintf报错,则在project中的properties中的C/C++ Build中的Settings中的MCU Settings中打开use float with printf from newlib-nano就可以使用C语言中可以使用的包如scanf,sprintf,sprintf为字符串拼接函数,%.3f 保留三位小数的float类型,把”V = %.3f V\r\n”变成字符串传给buff, .3f的值为ADC_Value采集到的值,因为分辨率为4096,再乘3.3V,也即光敏电阻分到的电压到底有几伏。】

单通道DMA配置

系统内部划分了缓冲区,在ADC转换完后把数据丢进缓冲区,当需要时调用,就不用进入中断操作,需要在配置中把ADC1中IN1中Parameter Settings中DMA Continuous Requests改为Enabled,但是不能直接选,要先去DMA中的DMA2中Add一个ADC1,Mode为Circular循环模式,数据放进后循环一直拿进缓冲区,没取掉则不停覆盖。然后在NVIC Settings中勾选DMA2 stream0 global interrupt,取消勾选ADC1,ADC2 and ADC3 global interrupts。

生成代码

在adc.c中不需要加入开启中断,直接在main.c定义全局变量uint32_t ADC_Value = 0;

在int main中while外写HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&ADC_Value, 1);

采集到的数据存入ADC_Value中,需要指针形式,length为一次性取多少次uint32的数据,因为DMA中有很多数据,自己定义数组可以读取你想要的数据量,但是因为单通道所以length直接为1。有了这个函数后,每次采样的数据都会自动存入ADC_Value中。

AD8232心电模块配置

初始配置,与以上ADC中断相同,再找PB0,PB1两个口为GPIO_INPUT,接在LOD-和LOD+,把PA2作为GPIO_OUTPUT。

GPIO PA2配置:GPIO output level为High即直接工作

PB0,PB1作为GPIO input默认拉低,分别设置为LO0和LO1

在Connectivity中串口选USART1,选择Asynchronous,其他默认

NVIC勾选ADC1,ADC2...

Code Generator中勾选Generate peripheral initialization...

生成工程

在adc.c加入开启中断的一句话:HAL_ADC_Start_IT(&hadc1);

Q2的思路分析:设定心电中间幅值,当采集到的值大于这个值是计数加一,只有当出现小于这个幅值后再采集到大于这个幅值计数才再加一。

Q1代码如下:

uint16_t ADC_Value = 0;
int main(void)
{uint8_t buff[1024] = {0};//作为模拟信号转换为数字信号的存储int time = 0;int count = 0;bool flag = FALSE;HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_ADC1_Init();MX_USART1_UART_Init();while (1){if(HAL_GPIO_ReadPin(LO0_GPIO_Port, LO0_Pin) == GPIO_PIN_SET || HAL_GPIO_ReadPin(LO1_GPIO_Port, LO1_Pin) == GPIO_PIN_SET){sprintf(buff, "Something Error!\r\n");}else{sprintf(buff, "V = %.3f V\r\n", ADC_Value / 4096.0 * 3.3);}HAL_UART_Transmit(&huart1, buff, strlen(buff), 5000);HAL_Delay(500);}
}void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{if(hadc == &hadc1){ADC_Value = HAL_ADC_GetValue(hadc);}
}

Q2代码如下:

#include "main.h"
#include "adc.h"
#include "usart.h"
#include "gpio.h"
uint16_t ADC_Value = 0;
#define CRIT (1.8/3.3*4096) //作为计算心跳的电压临界值
void SystemClock_Config(void);
int main(void)
{uint8_t buff[1024] = {0};//作为数字信号的存储int time = 0;int count = 0;bool flag = FALSE;HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_ADC1_Init();MX_USART1_UART_Init();while (1){if(time == 6000){sprintf(buff, "V = %d /minute\r\n", count);time = 0;count = 0;HAL_UART_Transmit(&huart1, buff, strlen(buff), 5000);}else{HAL_Delay(10);time++;if(ADC_Value > CRIT){if(!flag){flag = TRUE;count++;}}else{if(flag){ //1.8V作为计算心电电压阈值flag = FALSE;}}}}
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{if(hadc == &hadc1){ADC_Value = HAL_ADC_GetValue(hadc);}
}

Result

测得心电信号峰值约为2.3V,且心率约为90/min。

STM32 CubeIDE ADC及AD8232模块心电采集实验相关推荐

  1. STM32物联网项目-ADC采集实验板板温度(NTC热敏电阻)

    STM32 ADC采集板载温度 STM32 ADC简介 ​ STM32 拥有 1~3 个 ADC(STM32F101/102 系列只有 1 个 ADC),这些 ADC 可以独立使用, 也可以使用双重模 ...

  2. STM32使用ADC+DMA进行多通道模拟量采集 (踩坑及傻瓜式解析)

    STM32使用ADC+DMA进行多通道模拟量采集 (踩坑及通俗解析) ​ 利用STM32的片上外设可采集多个模拟量(如传感器数值),并在嵌入式程序中使用.如果只使用了一个通道,用时令ADC转换而后读取 ...

  3. 基于STM32的ADC电压采集(DMA传输)

    我最近在写stm32的adc电压采集过程中遇到了一些问题,这些问题或许对stm32初学者入手adc有所帮助. 对adc采集到的数据进行均值滤波处理,新建一个数组ADC_ConvertedValue_1 ...

  4. STM32——多通道ADC的DMA方式采集方法

    前言: 最近在调试STM32F205芯片ADC多通道DMA方式采集数据,总结下STM32多通道ADC的DMA方式采集的使用方法. 硬件平台:STM32F205 软件平台:keil v5 函数库:标准库 ...

  5. STM32实现ADC采集(待优化)

    1.ADC简介 STM32F103 系列最少都拥有 2 个 ADC ,我们选择的 STM32F103RCT 包含有 3 个 ADC,STM32的最大转换速率为1Mhz,也就是转换时间为1us,除此之外 ...

  6. 基于STM32HAL库ADC+DMA模式,高精度采集电池电量与芯片内部温度方法 (48脚 使用内部参考电压方案)

    目录 概述 1.原理图 2.在这先普及一下概念 3.通过查看STM32L0中文数据手册中301页,第14.10 小节 ,DataSheet 4.ADC通道转换模式的理解 5.STM32CubeMx工具 ...

  7. 我的第一篇文章——stm32的ADC+DMA+滤波算法

    stm32的ADC+DMA+滤波算法 一 工程目的 (1)外设配置 (2)源码 头文件 主文件 二 调试过程遇到的问题 1 如果打开中断 2 无法打开ADC 3 变量无法赋值 三 参考资料 四 写在最 ...

  8. STM32理论 —— ADC、存储、定时器、时钟、中断

    文章目录 1. ADC 1.1 ADC相关寄存器 1.1.1 ADC 控制寄存器1(ADC_CR1) 1.1.2 ADC 控制寄存器2(ADC_CR2) 1.1.3 ADC 采样时间寄存器(ADC_S ...

  9. STM32之ADC模数转换器单通道。

    ADC模数转换器 ADC(Analog-Digital Converter)模拟-数字转换器 ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁. 12位逐次 ...

最新文章

  1. 【编程5】斐波那契数列 + 递归+LeetCode50
  2. 第二十四期:揭秘:为什么电脑越用越卡 大型破案现场
  3. 安卓异常总结---GestureBuilder] Re-installation failed due to different application signatures
  4. python路径中有中文_python3 网址路径中带中文的处理办法
  5. 21最难调剂年:150万人参加调剂,预扩招18万人!
  6. 全局配置_再次强调:必须站在全局的角度去考虑客厅的内机配置
  7. java 微信文章评论点赞_微信文章评论点赞刷赞工具及微信文章评论点赞软件使用教程...
  8. 阿里银泰集团物业预付费系统项目的设计与应用
  9. 数据结构——图的应用
  10. 软件著作权申请表怎么填
  11. 阿里云企业邮箱域名注册流程
  12. Vue.js的简单趋势图
  13. Codewar刷题总结
  14. netflix app for android 使用记录
  15. java poi 追加_使用POI 向Excel中追加数据
  16. C语言beep中有什么作用,C++中发声函数Beep用法
  17. CPU架构与指令集的关系
  18. Serial Programming HOWTO
  19. 分布式数据库使用逻辑卷管理存储之扩容
  20. 关于MySQL表添加某一列和删除某一列

热门文章

  1. springboot 健康饮食管理系统
  2. CentOS7 NGROK服务器搭建 无需域名
  3. “三通两平台”与的数字化校园的建设
  4. 中值滤波,均值滤波,高斯滤波,双边滤波,联合双边滤波介绍
  5. html div居中属性,css布局设置div水平居中
  6. 标准化软件应用程序设计
  7. 利用Try-with-resources(TWR)读取Excel文件
  8. Python相关软件下载教程
  9. Mac下paragon插件卸载不完整的解决办法
  10. Android触摸事件派发(一) ViewGroup的dispatchTouchEvent()