STM32F407双ADC同步规则转换+双ADC交替采样+DMA搬运+DAC输出ADC采样+定时器或者软件触发+HAL库+cubemx

学习目标:

  • 双ADC同步规则转换
  • 双ADC交替采样
  • AC输出ADC采样
  • DMA搬运

学习内容:

 我们为什么要使用双ADC呢?
相较于单ADC模式他有什么好处呢?下面就让我来浅浅解答一下:

        首先ADC独立模式是指单个ADC模块独立地进行模数转换,即每个ADC模块都有自己的采样和转换控制器,可以独立地进行模数转换。这种模式适用于需要单独处理每个模拟信号的应用场景。

        而双ADC同步模式是指两个ADC模块同时进行模数转换,即两个ADC模块共享同一个采样和转换控制器,可以同时对两个模拟信号进行采样和转换。这种模式适用于需要同时处理两个模拟信号的应用场景,例如音频信号的采集和处理。

        现在假设我们要采集两路马达的电流值,对电流值的稳定性有一定要求。最初使用DMA+一个ADC的两个通道,采集的数据老是错位且数据变化波动大。而当我转换成双ADC+DMA模式时,使用两个ADC采集,就基本解决了以上问题。

        当然双重 ADC 模式 较独立模式一个最大的优势就是提高了采样率,弥补了单个 ADC 采样不够快的缺点。
原文链接:https://blog.csdn.net/m0_63325230/article/details/134703693

ADC介绍:

独立模式

  1. 单通道、单次转换模式
  2. 多通道(扫描)、单次转换模式
  3. 单通道连续转换模式
  4. 多通道(扫描)连续转换模式
  5. 注入转换模式

双ADC模式

  1. 双ADC常规同步模式
  2. 双ADC快速交替模式
  3. 双ADC慢速交替模式
  4. 双ADC交替触发模式
  5. 双ADC组合常规/同步注入模式
  6. 双ADC组合同步注入/交替模式

原理
        AD转换包括采样阶段和转换阶段,在采样阶段才对通道数据进行采集;而在转换阶段只是将采集到的数据进行转换为数字量输出,此刻通道数据变化不会改变转换结果。独立模式的 ADC 采集需要在一个通道采集并且转换完成后才会进行下一个通道的采集。双重或者三重 ADC的机制使用两个或以上 ADC 同时采样两个或以上不同通道的数据或者使用两个或以上 ADC 交叉采集同一通道的数据。双重或者三重 ADC 模式较独立模式一个最大的优势就是转换速度快。

        在有 2 个或以上 ADC 模块的产品中,可以使用双 ADC 模式和三 ADC 模式。在多 ADC 模式里,根据 ADC_CCR 寄存器中 MULTI[4:0]位所选的模式,转换的启动可以是 ADC1 主,ADC2 和 ADC3 从的交替触发或同步触发。

        在多 ADC 模式里,当转换配置成由外部事件触发时,用户必须将其设置成仅触发主 ADC,从ADC 设置成软件触发,这样可以防止意外的触发从转换。

        ADC共有4种可能的模式:

同步注入模式
同步规则模式
交叉模式
交替触发模式
还有可以用下列方式组合使用上面的模式:

同步注入模式+ 同步规则模式
同步规则模式+ 交替触发模式
在双 ADC 模式,ADC 公共的数据寄存器(ADC_CDR)包含 ADC1,ADC2 和 ADC3 的规则转换数据,32 位寄存器的所有位都将被使用。

在多DMA模式下,DMA支持3种模式:

DMA 模式 1:每次 DMA 请求(只有一个数据项是有效的),一个半字代表 ADC 转换数据项被传输。
        在双 ADC 模式,第一个请求下,ADC1 数据先被传输,第二个请求下,ADC2 数据被传输,以此类推。

        在三 ADC 模式,第一个请求下,ADC1 数据被传输,第二个请求下,ADC2 数据被传输,第三个请求下,ADC3 被传输,依次类推。

        DMA 模式 1 用于规则通道的三 ADC 模式。

        举一个例子:

        规则通道的三 ADC 模式:产生 3 个联系的 DMA 请求(一个请求对应一次转换数据项)。

        1st request: ADC_CDR[31:0] = ADC1_DR[15:0]

        2nd request: ADC_CDR[31:0] = ADC2_DR[15:0]

        3rd request: ADC_CDR[31:0] = ADC3_DR[15:0]

        4th request: ADC_CDR[31:0] = ADC1_DR[15:0]

DMA 模式 2:每次 DMA 请求(两个数据项有效)代表 2 个 ADC 转换数据项被传输,也就是一个字。
        在双 ADC 模式,第一个请求下,ADC2 和 ADC1 数据同时被传输(ADC2 占高 16 位,ADC1 占低16 位),后面以此类推。

        在三 ADC 模式,第一个请求下 ADC2 和 ADC1 数据被传输,第二个请求下 ADC1和 ADC3 被传输,第三个请求下 ADC3 和 ADC2 数据被传输。

        DMA 模式 2 用于交叉模式和规则同步模式(仅双 ADC 模式)。

        举一个例子:

        双 ADC 交叉模式:每次两个数据项有效是将产生 DMA 请求。

        1st request: ADC_CDR[31:0] = ADC2_DR[15:0] | ADC1_DR[15:0]

        2nd request: ADC_CDR[31:0] = ADC2_DR[15:0] | ADC1_DR[15:0]

        三 ADC 交叉模式:每次两个数据项有效是将产生 DMA 请求。

        1st request: ADC_CDR[31:0] = ADC2_DR[15:0] | ADC1_DR[15:0]

        2nd request: ADC_CDR[31:0] = ADC1_DR[15:0] | ADC3_DR[15:0]

        3rd request: ADC_CDR[31:0] = ADC3_DR[15:0] | ADC2_DR[15:0]

        4th request: ADC_CDR[31:0] = ADC2_DR[15:0] | ADC1_DR[15:0]

DMA 模式 3:这个模式和模式 2 类似,仅有的不同是每次 DMA 请求(两个数据项有效)两个字节代表两个 ADC 转换的数据项,也就是一个半字,数据传输顺序和 DMA 模式 2 类似。
        双 ADC 交叉模式:每次两个数据项有效是将产生 DMA 请求。

        1st request: ADC_CDR[31:0] = ADC2_DR[7:0] | ADC1_DR[7:0]

        2nd request: ADC_CDR[31:0] = ADC2_DR[7:0] | ADC1_DR[7:0]

        三 ADC 交叉模式:每次两个数据项有效是将产生 DMA 请求

        1st request: ADC_CDR[31:0] = ADC2_DR[7:0] | ADC1_DR[7:0]

        2nd request: ADC_CDR[31:0] = ADC1_DR[7:0] | ADC3_DR[7:0]

        3rd request: ADC_CDR[31:0] = ADC3_DR[7:0] | ADC2_DR[7:0]

        4th request: ADC_CDR[31:0] = ADC2_DR[7:0] | ADC1_DR[7:0]
————————————————
原文链接:https://blog.csdn.net/xhj1021/article/details/123089586

cubemx配置

配置DAC输出三角波。

将单片机PA4引脚与PA5引脚相连,以便后续ADC采集数据。

配置双ADC同步规则转换

我们这里采集内部的温度传感器ADC数据。

配置定时器3event更新事件为触发源。

配置DMA。

配置ADC2

定时器触发ADC采样配置,触发时间f=84000000/840/10000=10,t=0.1s

开启定时器3的中断。

配置定时器6为DAC触发源。

最后一步打开串口,双ADC同步规则触发到此配置完成。

生成代码:

添加代码

下载到单片机,此处省略串口外设代码。

双ADC同步转换实验成功。

此处有一个坑:

我买的这本书说需要在代码里面开启ADC2的DMA流,我试了开启和不开启都行,因为DMA已经在ADC1中配置,传输时同时传输了ADC1,ADC2的数据。

还有一点就是不要这样设置:

在这里设置成这样并不会导致出错,但是取消定时器触发改为软件触发DMA就不会正在工作。

我查了一下函数解释:

这个函数必须在主ADC开启,ADC1为主ADC,ADC2为从ADC,如果像这个书里这样开启,在软件触发时会导致不正常。

这个问题我也不知道咋解释,底层东西,如果有大佬知道给我评论一下。

配置双ADC交替采集

配置ADC1

配置ADC2

PA2接3.3V电压,PA3接DAC输出

理论速率=3+5+12/(84000000/4)/2=0.47us

生成代码:

添加以上代码。下载进单片机,串口波特率我设置的3M b/s

到此实验结束。

欢迎大家指正!!!


以下是基于HAL库stm32f407定时器触发adc dma多通道采样代码: 首先,需要初始化定时器ADC: ``` TIM_HandleTypeDef htim; ADC_HandleTypeDef hadc; void MX_TIM_Init(void) { TIM_MasterConfigTypeDef sMasterConfig = {0}; htim.Instance = TIMx; htim.Init.Prescaler = TIMx_PRESCALER; htim.Init.CounterMode = TIM_COUNTERMODE_UP; htim.Init.Period = TIMx_PERIOD; htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim.Init.RepetitionCounter = 0; HAL_TIM_Base_Init(&htim); sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; HAL_TIMEx_MasterConfigSynchronization(&htim, &sMasterConfig); } void MX_ADC_Init(void) { ADC_ChannelConfTypeDef sConfig = {0}; hadc.Instance = ADCx; hadc.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2; hadc.Init.Resolution = ADC_RESOLUTION_12B; hadc.Init.ScanConvMode = ENABLE; hadc.Init.ContinuousConvMode = DISABLE; hadc.Init.DiscontinuousConvMode = DISABLE; hadc.Init.NbrOfDiscConversion = 0; hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING; hadc.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_Tx_TRGO; hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc.Init.NbrOfConversion = ADC_CHANNEL_NUM; hadc.Init.DMAContinuousRequests = ENABLE; hadc.Init.EOCSelection = ADC_EOC_SEQ_CONV; HAL_ADC_Init(&hadc); for (int i = 0; i < ADC_CHANNEL_NUM; ++i) { sConfig.Channel = ADC_CHANNEL_x[i]; sConfig.Rank = i + 1; sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; HAL_ADC_ConfigChannel(&hadc, &sConfig); } } ``` 然后,需要初始化DMA和中断: ``` DMA_HandleTypeDef hdma_adc; void MX_DMA_Init(void) { hdma_adc.Instance = DMAx_STREAMx; hdma_adc.Init.Channel = DMA_CHANNELx; hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE; hdma_adc.Init.MemInc = DMA_MINC_ENABLE; hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; hdma_adc.Init.Mode = DMA_CIRCULAR; hdma_adc.Init.Priority = DMA_PRIORITY_HIGH; hdma_adc.Init.FIFOMode = DMA_FIFOMODE_DISABLE; HAL_DMA_Init(&hdma_adc); __HAL_LINKDMA(&hadc, DMA_Handle, hdma_adc); } void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { if (hadc->Instance == ADCx) { HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); } } ``` 最后,在main函数中启动定时器DMA: ``` int main(void) { HAL_Init(); MX_TIM_Init(); MX_ADC_Init(); MX_DMA_Init(); HAL_TIM_Base_Start(&htim); HAL_ADC_Start_DMA(&hadc, (uint32_t*)adc_buf, ADC_CHANNEL_NUM); while (1) { HAL_Delay(1000); } } ```
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一月千帆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值