STM32笔记_ADC的采样(软件/TIM+DMA)

ADC 采样速率如何最大

介绍 ADC 主频

ADC-0

  • STM32F407 的 ADC 连接在 APB2 总线上的 PCLK 线上,支持的最大时钟为 36 MHz,而 PCLK 时钟是由 HCLK 固定的二分频得到,所以如果总线频率拉到 168 M,APB2 则只能得到 84 M,这就导致 ADC 内部再分频的时候,刚好分不到 36 M,所以我们需要设置 HCLK 为 144 M,这样就可以得到 72 M,进而 ADC 二分频得到 36 M

ADC-1.png

  • 此时如果我们设置 ADC 的转换周期是 15 clk,就可以得到理论最大采样率为 36 15 \frac{36}{15} 1536 = 2.4 M =2.4M =2.4M

2.4 M 2.4M 2.4M 极限采样率

  • ADC 的极限采样率只能用定时器+DMA 方式实现
    • 定时器是为了使采样间隔一致可控
    • DMA 是为了让数据搬运不需要 CPU 的参与

参数

  • ADC
    • 36 M H z 36MHz 36MHz
    • Resolution : 8 8 8 bits(11 ADC Clock Cycles)
    • Sampling time: 3 3 3 Cycles
    • 所以采一个点最快 11 个 clk,理论最大为 36 11 ≈ 3.27 M H z \frac{36}{11}\approx 3.27MHz 11363.27MHz
  • TIM: 72 M H z 72MHz 72MHz(APB1)
    • Prescaler: 3 3 3
    • Counter Period: 8 8 8
    • 所以速率为 72 4 × 9 = 2 M H z \frac{72}{4 \times 9} =2MHz 4×972=2MHz

实际测试

  • 实际测试发现,测得的数据确实为 2 M H z 2MHz 2MHz,输入 100 k H z 100kHz 100kHz 的信号,一个周期可以测得 20 20 20 个点

软件触发转换

ADC 设置

ADC-2.png

  • 选择了 ADC 2 的 Chanel 7,这个可以随意选择
  • External Trigger Conversion Source设置为 by software(软件触发)

代码部分

  • MX_ADC2_Init
    • CubeMX 会自动帮我们生成 ADC 的 Init 函数
  • HAL_ADC_Start(&hadc2)
    • 手动启动 ADC 的转换,启动的时候会有校准的时间,所以第一次启动的时候所需要的时间会长一些,如果只测一次,则使用完后用HAL_ADC_Stop(&hadc 2) 来关闭,否则不用关闭,他会一直转换
  • HAL_ADC_PollForConversion(&hadc2, 200)
    • 这个函数用来检测 ADC 转换是否完成,如果完成就返回 HAL_OK,之后就可以用HAL_ADC_GetValue(&hadc2) 读出 ADC 内部寄存器 dr 的值了。其中第二个参数是允许等待 ADC 转换完成的时间,即超时时间

用软件触发读取多数据的一个代码编写思路


for (i = 0; i < FFT_LENGTH; i++) /* 生成信号序列 */

{

dac_value = dac_vol * 4095 / 3.3;

HAL_ADC_Start(&hadc2);

while (HAL_ADC_PollForConversion(&hadc2, 200) != HAL_OK)

{

}

uint32_t adc_value = HAL_ADC_GetValue(&hadc2);

uint32_t Volt = 3300 * adc_value >> 12;

printf("%d\r\n",Volt);

fft_inputbuf[2 * i] =Volt; /* 生成输入信号实部 */

fft_inputbuf[2 * i + 1] = 0; /* 虚部全部0 */

}

arm_cfft_radix4_f32(&scfft, fft_inputbuf); /* FFT计算(基4) */

arm_cmplx_mag_f32(fft_inputbuf, fft_outputbuf, FFT_LENGTH); /* 把运算结果复数求模得幅 */

for (i = 0; i < FFT_LENGTH; i++)

{

printf("fft_outputbuf[%d]:%f\r\n", i, fft_outputbuf[i]);

}

  • 重点是这一句
while (HAL_ADC_PollForConversion(&hadc2, 200) != HAL_OK)

{

}
  • 即如果没转换完成,就一直卡在 while 里

软件触发的问题
似乎用软件触发会使得采样率提不上来
如果想要较高采样率,可以用 TIM 触发,如果想要极限采样率,则用 DMA 搬运数据

定时器TRGO信号触发转换

定时器设置

Pasted image 20240404095302.png
Pasted image 20240404100258

  • Clock Source设置为internal Clock
  • Prescaler和Counter Period根据时钟频率和定时器期望周期计算得到
  • auto-reload preload关闭,否则更新不能及时生效
  • TriggerOutput(TRGO) Parameters设置
    • 主从模式关闭(我也不知道这是干嘛的)
    • Trigger Event Selection
      • 这个是设置什么东西会产生TRGO信号
      • 设置为UEV事件的产生会产生TRGO信号,这样就使得计数器记满一个周期后,就有一个TRGO信号传给ADC进行转换
      • TRGO是一个短的脉冲信号
  • TIM3的全局中断不打开

ADC设置

Pasted image 20240404101226.png

Pasted image 20240404101525.png

  • 打开任意一个ADC的任意一个通道,我这里打开ADC2-IN7
  • Mode模式设置为独立模式
  • Continuous Conversion Mode
    • 开启了之后,ADC 无需 Start,ADC 会自动连续转换
    • 问题:此时 ADC 转换的速率是不是可以拉到最快?也就是 2.4 M 极限不用 tim 触发,用这个模式配合 dma
    • HAL ADC连续转换模式
  • End Of Conversion Selection
    • 有两个选项
      • 一个通道转换完成就发出转换完成信号(HAL_OK)
      • 所有通道转换完成才发出转换完成信号
    • 这里设置为一个通道就发出,因为我只开了一个通道
  • External Trigger Conversion Source
    • 这个是用来设置触发ADC转换的方式的
      • 常用的有软件触发
      • 我们这里使用Timer3的TRGO信号触发
  • External Trigger Conversion Edge
    • TRGO信号是一个短时的正脉冲
    • 我们这里设置脉冲的上升沿触发转换
  • 打开ADC的全局中断
    • 注意:ADC1-2-3共用一个全局中断,即一个中断号ISR

NVIC设置

Pasted image 20240404101718.png

  • 最后来到NVIC,设置ADC和滴答定时器的中断优先级

代码流程

  • HAL_ADC_GetValue(&hadc 2)
    这个函数是在 adc 转换完成之后,将 adc 的值读出来

  • HAL_ADC_Start_IT(&hadc2)
    将 ADC 以中断方式启动,即 ADC 开始测量

  • HAL_TIM_Base_Start(&htim3)
    开启定时器的函数,执行后定时器就开始计时了

  • HAL_ADC_IRQHandler
    ADC 的中断函数,即 ADC 采集转换完成后,执行这个中断函数

  • __weak void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef * hadc)
    这个函数在HAL_ADC_IRQHandler里,是 ADC 转换完成的回调函数,用户在需要编写在 ADC 转换完成后需要执行什么操作
    由于多个 ADC 共用一个中断号,所以他们的中断回调函数也是相同的,我们在编写这个函数的时候需要首先判断传入的 hadc 是哪个,再在 if 里执行对应的操作
    这个函数有时候编写的时候在 main 函数里会识别不出来,然后编译就报错,点击报错会跳转到一个 error handler 的函数,这个时候没有别的办法,只能把整个工程删除重开,就会好了(这个 bug浪费了我一整天事件,不过似乎也有可能是因为我确实漏看了某个括号)

ADC 的 DMA 模式

CubeMX 配置

Timer

ADC-DMATIM

  • Timer 部分很熟悉了,就不再详细说了

ADC

ADC-DMAADC

  • 这里着重介绍一下DMA Continuous RequestsContinuous Conversion Mode
    • DMA Continuous Requests (这个理解好像不对)
      • 例如,HAL_ADC_START_DMA (&hadc 1, (uint 32_t *) buf, 200) 这个语句,使用 ADC 1 和 DMA,数据放入 buf 数组内,放 200 个数据。如果 DMA 连续请求去能的话,这个语句传完 200 个数据后自动关闭 ADC 1 和 DMA。反之,使能后,语句执行完后会又会连续从头开始传输数据,实际为 buf 数组中的值一直在更新
    • Continuous Conversion Mode
      • 开了这个会连续触发采样,一般在软件触发里常用;但是开了定时器就不需要了
      • 如果开了软件,开了这个,那么 start 一次后 ADC 还会一直采样;如果开了软件,没开这个,那么 start 一次以后 ADC 不会采样,需要手动 start(换句话说,采样一次完成后 ADC 会自动 stop)

ADC-DMANVIC

ADC-DMADMA

  • ADC 还需要
    • 开启 NVIC,从而在 DMA 的 buffer 满了以后,触发 ADC 的中断回调函数
    • 开启 DMA,设置 ADC 传输数据的 DMA 通道

NVIC 与 DMA

ADC-system

ADC-NVICDMA

  • 开启 ADC 的 NVIC
  • 创建一个 DMA 通道
    1. 添加一个通道
    2. 添加完成
    3. 模式
      • 分为 normal 和 circular
      • normal 指 buffer 满了以后,就停止 DMA 传输了,即只传一次;circular 指循环传输,即满了以后从头开始再传输,覆盖以前的内容
    4. 地址自增
      • 第一个是外设地址自增,本次 ADC 的数据寄存器只有 dr 一个,即采集到的电压,所以不需要自增,始终读取该值即可
      • 第二个是内存地址自增,即 DMA 传输到的地址是否自增,我们进行 fft,这里需要传入 1024 个数据,即 buffer 的大小是 1024,所以肯定要地址自增,才能让数据一个一个的按顺序传入 buffer
    5. 传输的数据宽度
      • 数据宽度和传入的内存地址的类型有关,我们这里是 uint 32_t,所以就选 word(一个字);如果是 uint 16_t 或者 uint 8_t 之类的,就选 half word 或者 byte 就行

具体流程的理解(ADC 的 DMA 模式流程图)

  • 我先 hal_adc_start_dma,然后 hal_time_base_start,然后定时器产生 trgo 信号后就会自动 adc 采集,adc 采集完成就会自动把数据搬运到缓冲区,缓冲区满了以后 adc 就自动停止了,进到 adc 的中断处理函数void HAL_ADC_ConvCpltCallback (ADC_HandleTypeDef* hadc) 了,这个也是我们需要重写的回调函数
  • 如果我不想让 DMAcircular 采集,而是DMA 模式手动控制采集了一轮以后继续采集的话,调整成 normal 之后再把hal_adc_start_dma 重新开启,不过可能需要先手动 stop 一下?(HAL_ADC_Stop_DMA)(待定)
  • 31
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32F103是一款具有多通道ADC、TIMDMA和FFT功能的微控制器。 首先,多通道ADC允许我们同时采集多个不同通道的模拟信号。这对于需要同时监测多个传感器或信号源的应用非常有用。通过配置ADC的多个通道,并设置相应的采样速率和分辨率,可以轻松实现高效的数据采集。 其次,TIM(定时器)模块允许我们生成精确的时间基准。在实时系统和定时器应用中,我们可以配置TIM来实现各种定时和计时功能。通过设置预分频器、计数器和比较器,我们可以准确地生成周期性的、定时的或脉冲宽度可变的信号。这对于控制和调度其他外设非常有用。 接下来,DMA(直接内存访问)控制器允许我们实现高速数据传输,而不需要CPU的干预。通过配置DMA通道并定义源和目标的地址、传输长度和传输方向,我们可以实现高效的数据传输操作。这对于处理大量数据、高速数据流或实时响应的应用非常有用。 最后,FFT(快速傅里叶变换)是一种用于信号处理和频谱分析的重要算法。通过使用STM32F103的FFT库,我们可以对采集到的模拟信号进行频谱分析,以提取信号的频率和幅度特征。这对于音频处理、通信系统、传感器数据分析等应用非常有用。 总之,STM32F103的多通道ADC、TIMDMA和FFT功能为我们提供了丰富的数据采集、定时、数据传输和信号处理能力,使得我们可以设计出高度灵活、高效的嵌入式系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值