STM32F4 HAL库使用DMA进行ADC采样实时发送波形到串口显示(包含傅里叶变换)

这篇具有很好参考价值的文章主要介绍了STM32F4 HAL库使用DMA进行ADC采样实时发送波形到串口显示(包含傅里叶变换)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.总体逻辑

按下 STM32F4 的 KEY0 按键,通过外部中断的方式对按键进行检测,然后进行一次固定点数的 DMA ADC 采集,采集完成后在 DMA 的中断发送采集到的数据,然后清空数据区准备下一次的按键中断。电脑接受到串口数据后对数据进行简单处理和傅里叶变化,然后实时显示在电脑上。
开发板:正点原子探索者STM32F407ZG

2. STM32

源工程文件
可以拿着正点原子的官方例程的单通道ADC采集(DMA读取)实验进行修改
这里只展示
部分重要代码

2.1 外部中断处理函数

打开 exti.c 文件,修改为以下的代码。删掉了冗余的代码,在 KEY0 按下后的逻辑中加入了 adc_dma_enable(ADC_DMA_BUF_SIZE) 来启动一次ADC采集

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/KEY/key.h"
#include "./BSP/EXTI/exti.h"
#include "./BSP/ADC/adc.h"

/**
 * @brief       KEY0 外部中断服务程序
 * @param       无
 * @retval      无
 */
void KEY0_INT_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(KEY0_INT_GPIO_PIN);         /* 调用中断处理公用函数 清除KEY0所在中断线 的中断标志位 */
    __HAL_GPIO_EXTI_CLEAR_IT(KEY0_INT_GPIO_PIN);         /* HAL库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发 */
}

/**
 * @brief       中断服务程序中需要做的事情
 *              在HAL库中所有的外部中断服务函数都会调用此函数
 * @param       GPIO_Pin:中断引脚号
 * @retval      无
 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    delay_ms(20);      /* 消抖 */
    switch(GPIO_Pin)
    {
        case KEY0_INT_GPIO_PIN:
            if (KEY0 == 0)
            {
                LED0_TOGGLE();
                adc_dma_enable(ADC_DMA_BUF_SIZE);                   /* 启动一次ADC DMA采集 */
            }
            break;
        default : break;
    }
}

/**
 * @brief       外部中断初始化程序
 * @param       无
 * @retval      无
 */
void extix_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;
    
    key_init();
    gpio_init_struct.Pin = KEY0_INT_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_IT_FALLING;            /* 下降沿触发 */
    gpio_init_struct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(KEY0_INT_GPIO_PORT, &gpio_init_struct);    /* KEY0配置为下降沿触发中断 */

    HAL_NVIC_SetPriority(KEY0_INT_IRQn, 0, 2);               /* 抢占0,子优先级2 */
    HAL_NVIC_EnableIRQ(KEY0_INT_IRQn);                       /* 使能中断线4 */

}

2.2 DMA传输完成中断函数

adc.c 中,找到 ADC DMA 采集中断服务函数,也就是 ADC_ADCX_DMASx_IRQHandler ,然后修改为如下的代码。在 DMA 采集完成后触发的中断中,通过串口将采集到的数据发送出来

/**
 * @brief       ADC DMA采集中断服务函数
 * @param       无
 * @retval      无
 */
void ADC_ADCX_DMASx_IRQHandler(void)
{
    if (ADC_ADCX_DMASx_IS_TC())     /* 判断DMA数据传输完成 */
    {
        g_adc_dma_sta = 1;          /* 标记DMA传输完成 */
        for (int i = 0; i < ADC_DMA_BUF_SIZE; i++)  /* 累加 */
        {
            printf("%d\r\n",g_adc_dma_buf[i]);
        }
        ADC_ADCX_DMASx_CLR_TC();    /* 清除DMA2 数据流4 传输完成中断 */
    }
}

2.3 DMA缓存区大小设置

adc.h 中,修改 ADC_DMA_BUF_SIZE 为自己想要的大小,如下图所示
stm32波形显示,stm32,stm32,单片机,嵌入式硬件

2.4主函数

main.c 修改为如下代码

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/ADC/adc.h"
#include "./BSP/EXTI/exti.h"
#include "string.h"

uint16_t g_adc_dma_buf[ADC_DMA_BUF_SIZE];   /* ADC DMA BUF */
extern uint8_t g_adc_dma_sta;               /* DMA传输状态标志, 0,未完成; 1, 已完成 */

int main(void)
{
    HAL_Init();                             /* 初始化HAL库 */
    sys_stm32_clock_init(336, 8, 2, 7);     /* 设置时钟,168Mhz */
    delay_init(168);                        /* 延时初始化 */
    usart_init(115200);                     /* 串口初始化为115200 */
    led_init();                             /* 初始化LED */
    lcd_init();                             /* 初始化LCD */
    extix_init();                           /* 初始化外部中断输入 */
    adc_dma_init((uint32_t)&g_adc_dma_buf); /* 初始化ADC DMA采集 */
    
    lcd_show_string(30,  50, 200, 16, 16, "STM32", RED);
    lcd_show_string(30,  70, 200, 16, 16, "ADC DMA TEST", RED);
    lcd_show_string(30,  90, 200, 16, 16, "ATOM@ALIENTEK", RED);
    lcd_show_string(30, 110, 200, 16, 16, "ADC1_CH5_VAL:", BLUE);
    lcd_show_string(30, 130, 200, 16, 16, "ADC1_CH5_VOL:0.000V", BLUE); /* 先在固定位置显示小数点 */
    
    while (1)
    {

    }
}

2.5采样率的计算

目前采用的是 21M 时钟,一个时钟周期是 0.047us,采集 3 个周期,转化要 12 个周期(STM32F4 参考手册有写),采样一次就是 15 个周期
采样时间:0.047x15=0.705us
采样率为:1/0.705=1.418M(这里由于计算的时候采用了近似值,若不使用近似值计算下来就是1.4M)
理论最高采集 0.700M 的信号,即 700K 的信号

3. Python实时显示

这里的傅里叶变化只会显示最后的 POINT 个点的傅里叶变化情况

#%%
import serial
import matplotlib.pyplot as plt
import numpy as np
import time
#%%
LINE = 1 # 是否用线的方式连接
OFFSET = 0 # 是否减去偏置值
POINT = 140 # 这里设置的大小和STM32中DMA缓存区的大小要一致
SAMPLE = 1.418e6
count = 0
# 设置画布大小
fig, (ax1, ax2) = plt.subplots(1, 2)
line1, = ax1.plot([], [])
line2, = ax2.plot([], [])
ax1.set_xlim(0, 100)
ax2.set_xlim(0,SAMPLE)
ax1.set_ylim(0, 5)
ax2.set_ylim(0, 100)
ax1.set_title('Time Domain')
ax2.set_title('Frequency Domain')

# 初始化数据
x = []
y = []
yfft = []
xfft = np.linspace(0,POINT-1,POINT)
xfft = xfft*(SAMPLE/POINT)

# 创建曲线对象
if LINE:
    line1, = ax1.plot([], [])
    line2, = ax2.plot([], [])
else:
    line1, = ax1.plot([], [],'.')
    line2, = ax2.plot([], [],'.')   

# 开始绘图
start_time = time.time()
ser = serial.Serial(port ='COM3', baudrate =115200,bytesize = serial.EIGHTBITS,parity = serial.PARITY_NONE,
                    stopbits = serial.STOPBITS_ONE,xonxoff = False,rtscts =False,dsrdtr =False) 
#%%
# 循环读取串口数据并绘图
while True:
    count+=1
    # print(ser.inWaiting())
    # 读取串口数据
    if(ser.inWaiting()):
        line = ser.readline()
        ser.flush()
        # print(line)
        if len(line) : 
            real_vol = int(line) * (3.3 / 4096)
            print(real_vol)
    else:
        real_vol = 0

    # 实时更新x轴
    t = time.time() - start_time

    # 更新数据
    x.append(t)
    y.append(real_vol)
    if count>POINT:
        #FFT
        temp = []
        # xfft = np.linspace(0,POINT,1)
        # xfft = xfft*(SAMPLE/POINT)
        if OFFSET:
            yfft = np.fft.fft(y[-POINT:]-np.mean(y[-POINT:]))
        else:
            yfft = np.fft.fft(y[-POINT:])
        line2.set_data(xfft, abs(yfft))
    
    # 更新曲线数据
    line1.set_data(x, y)
    ax1.set_xlim(max(0, t - 5), t)

    # 重新绘制图形
    fig.canvas.draw()
    fig.canvas.flush_events()
    plt.pause(0.01)  # 控制循环速率 

4. 结果展示

输入信号:700KHz 正弦波,幅度1V,偏置1V
显示的结果如下图所示,观察频域图发现与输入信号的频率一致

stm32波形显示,stm32,stm32,单片机,嵌入式硬件文章来源地址https://www.toymoban.com/news/detail-629237.html

到了这里,关于STM32F4 HAL库使用DMA进行ADC采样实时发送波形到串口显示(包含傅里叶变换)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 【STM32F4系列】【HAL库】【自制库】WS2812(软件部分)(PWM+DMA)

    【STM32F4系列】【HAL库】【自制库】WS2812(软件部分)(PWM+DMA)

    硬件介绍(PCB设计方案) 模拟时序发送 WS2812是一种异步串行通信,它每一位数据时间是ns级别的 默认是高电平状态 0码:220-380ns高电平+580-1600ns低电平 1码:580-1600ns高电平+220-380ns低电平 复位码:280us低电平 24Bit数据来代表GRB的亮度值 从高位到低位发送,分别按照G-R-B的顺序发送

    2024年02月15日
    浏览(12)
  • STM32基于hal库的adc以DMA的多通道采样以及所遇问题解决

    STM32基于hal库的adc以DMA的多通道采样以及所遇问题解决

    目录 准备 配置 步骤  总结   正点原子的STM32F103ZET6开发板(精英版) CUBEMX配置软件 KEIL5  右对齐就是正常的数据格式。左对齐除以16后得正常数据。(当输出非常大时考虑是否改了对齐方式,默认都是右对齐)  扫描模式,连续转换模式使能。(多通道下扫描模式自动使能

    2024年02月04日
    浏览(11)
  • STM32 HAL库 PWM+DMA 驱动WS2812B彩灯(STM32F030F4P6)

    STM32 HAL库 PWM+DMA 驱动WS2812B彩灯(STM32F030F4P6)

    博主使用STM32驱动WS2812B主要参考了这位佬的文章,因为需求问题,采用了Cortex-M0的stm32f030f4p6(16k的flash,4k的sram)来驱动,原文中写的是stm32f103c8t6,个人认为其实区别并不是很大,需要修改部分参数即可移植(cv战士申请出战)。 上图是我的一圈灯,一共8个,第一个LED的数

    2024年02月06日
    浏览(24)
  • 【STM32F407 ADC+DMA采集压力变送器数据(HAL库)】

    【STM32F407 ADC+DMA采集压力变送器数据(HAL库)】

    之前项目中需要对麦克传感器的mpm480隔爆压力变送器(4-20ma输出)的数据进行实时采集,使用STM32F407作为控制器,使用信号转换模块将压力变送器4-20ma的输出转换为0-3.3v的信号量,输入到STM32F407板子的ADC1的通道10,并使用DMA2通道0数据流0将采集的多个值从外设直接存入存储器

    2024年02月16日
    浏览(8)
  • STM32 hal库使用笔记(五)ADC—单通道/双通道DMA传输

    STM32 hal库使用笔记(五)ADC—单通道/双通道DMA传输

    实现目的:利用ADC采集光敏传感器/烟雾传感器的值,并利用串口打印 实验平台:正点原子精英版 一、简介 1.DMA的介绍 参考:STM32 hal库使用笔记(四)DMA—内存到内存/内存到外设_乱码小伙的博客-CSDN博客 2.ADC简介      ADC(Analog-Digital Converter)模拟-数字转换器 ADC可以将引脚

    2024年02月03日
    浏览(10)
  • 【STM32F4系列】【HAL库】【模块介绍】MPU6050设置与DMP库使用

    【STM32F4系列】【HAL库】【模块介绍】MPU6050设置与DMP库使用

    MPU6050是一个3轴陀螺仪(测角加速度)和3轴加速度计(测量线加速度)的测量芯片 内部自带运算单元(DMP),可以输出经姿态融合计算后的 四元数 (一种表示旋转的方法) 而且MPU6050的价格较低(10r以下),常被用于精度不高的场合作为姿态感知的芯片 如经典项目平衡车,某年电赛题目风力摆

    2024年02月05日
    浏览(28)
  • STM32 ADC单/多通道采样+DMA搬运

    STM32 ADC单/多通道采样+DMA搬运

    通过介绍我们可以了解到,ADC是12位的转换器,所以采样值范围是0~4095。18个通道可同时进行转换,也可以单独转换某个通道。 使用ADC的流程应为: 初始化IO口。 我这里使用的是PA1进行采样,也就是ADC1的通道1 初始化ADC。 转换、获取采样值。 多通道的时候我们一般用DMA来搬

    2024年02月14日
    浏览(11)
  • STM32CubeMX配置ADC采样(轮询、中断、DMA)

    STM32CubeMX配置ADC采样(轮询、中断、DMA)

    STM32CubeMX能够极大减小STM32外设配置的工作量,因此作者也借助空闲时间对STM32CubeMX相关配置进行了学习,本文介绍如何利用STM32CubeMX配置ADC采样,记录了作者学习过程中遇到的问题及解决办法,使大家少走弯路,并方便以后复习 先选择所使用的MCU,这里我使用的是STM32F407ZGT系

    2024年02月03日
    浏览(16)
  • STM32 HAL库 ADC+DMA

    STM32 HAL库 ADC+DMA

       软件触发:STM32 HAL库 软件触发ADC 多通道连续转换_随风飘零翼的博客-CSDN博客 配置如图      注意采样周期不要过小,不然频繁中断会导致在RTOS中卡死 写了部分关键代码,在两个任务中OLED和串口打印分别显示的通道值。 后来发现使用的杜邦线接触不良,固定好之后,接

    2024年02月14日
    浏览(6)
  • 【stm32开发笔记】基于HAL库的STM32F4添加DSP库

    【stm32开发笔记】基于HAL库的STM32F4添加DSP库

    本文分两种方法添加DSP库:1.CubeMX直接配置ioc添加; 2.KEIL内添加; 简述:补齐全部lib库-添加DSP包-使能DSP勾选-添加头文件及魔术棒配置-测试 1.补齐lib库。( 如果使用直接默认添加的库,是不支持FPU的,所以需要补齐后找到所需的lib文件进行替换,在MX的工程管理栏,选择复制所

    2024年02月16日
    浏览(101)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包