STM32通过TIM,ADC,DMA的配合使用实现双通道数据采样

本文介绍了如何在STM32F205VCT6芯片上,通过57.6kHz定时器触发ADC采样,并使用DMA将采样数据存入缓冲区,以实现双通道数据的高速采集。配置过程包括设置定时器、ADC以及采用乒乓缓冲的DMA。
摘要由CSDN通过智能技术生成

第一次写博客,奉献给STM32了,一直以来都是潜水看博客,希望能够自己也能写一点东西,对自己学习和工作的一个总结,希望能够坚持下去。

项目背景:以57.6kbps的速率采集两个通道的数据
芯片:STM32F205VCT6
总体的思路通过57.6kHz的定时器去触发ADC采样,采样后的数据在通过DMA存放于缓冲区定时产生中断。
由于需要产生57.6KHz的频率,晶振选择9.6MKHz,CPU主频为115.2MHz。
STEP1:配置定时器
通过TIM2去触发两路ADC,详见配置如下

void TIM2_Configuration(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;

    RCC_APB1PeriphClockCmd ( RCC_APB1Periph_TIM2 , ENABLE );

    TIM_DeInit ( TIM2 );

    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_Period        = (57600000/(ADC_SAMPLING_MUL*AIS_MODUL_RATE) - 1 );    //28.8M*2/100/10 = 57.6kHz
    TIM_TimeBaseStructure.TIM_Prescaler     = ( 1 - 1 );//28.8M*2 = 57.6MHz
    TIM_TimeBaseStructure.TIM_CounterMode   = TIM_CounterMode_Up;
    TIM_TimeBaseInit ( TIM2, &TIM_TimeBaseStructure );

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 1;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    TIM_OC2Init(TIM2, &TIM_OCInitStructure);
    //TIM_ITConfig(TIM2,TIM_IT_CC2,ENABLE); //开定时器中断测试使用

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 1;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    TIM_OC3Init(TIM2, &TIM_OCInitStructure);
   // TIM_ITConfig(TIM2,TIM_IT_CC3,ENABLE); //开定时器中断测试使用

    TIM_Cmd ( TIM2, ENABLE );
    TIM_InternalClockConfig(TIM2);
    TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);
    TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);
    TIM_UpdateDisableConfig(TIM2, DISABLE);
}

STEP2:配置ADC
首先需要配置GPIO复用

//GPIO -PB0 PB1 -ADC1 ADC2
    GPIO_InitStructure.GPIO_Pin     = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd    = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;
    GPIO_Init ( GPIOB, &GPIO_InitStructure );

然后配置ADC

void ADC_Configuration(void)
{                                       
    ADC_InitTypeDef       ADC_InitStructure;
    ADC_CommonInitTypeDef ADC_CommonInitSt
以下是一个示例代码,用于配置 STM32F4 的定时器触发双 ADC 同步采样DMA 转运的库函数配置: ```c #include "stm32f4xx.h" #define ADC1_DR_ADDRESS ((uint32_t)0x4001204C) #define ADC2_DR_ADDRESS ((uint32_t)0x4001214C) #define ADC_BUFFER_SIZE 1024 uint16_t adc_buffer1[ADC_BUFFER_SIZE]; uint16_t adc_buffer2[ADC_BUFFER_SIZE]; void ADC_DMA_Config(void) { ADC_InitTypeDef ADC_InitStructure; DMA_InitTypeDef DMA_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; // 使能 ADC1 和 ADC2 的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2, ENABLE); // 配置 ADC1 和 ADC2 的通用设置 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 1; ADC_Init(ADC1, &ADC_InitStructure); ADC_Init(ADC2, &ADC_InitStructure); // 配置 ADC1 和 ADC2 的规则通道 ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles); ADC_RegularChannelConfig(ADC2, ADC_Channel_0, 1, ADC_SampleTime_3Cycles); // 配置 DMA1 的时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); // 配置 DMA1_Stream0,用于 ADC1 的数据转移 DMA_InitStructure.DMA_Channel = DMA_Channel_0; DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_ADDRESS; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&adc_buffer1; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = ADC_BUFFER_SIZE; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA1_Stream0, &DMA_InitStructure); // 配置 DMA2_Stream0,用于 ADC2 的数据转移 DMA_InitStructure.DMA_Channel = DMA_Channel_1; DMA_InitStructure.DMA_PeripheralBaseAddr = ADC2_DR_ADDRESS; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&adc_buffer2; DMA_Init(DMA1_Stream0, &DMA_InitStructure); // 配置定时器触发 ADC1 和 ADC2 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_DeInit(TIM2); TIM_TimeBaseStructure.TIM_Period = 1000 - 1; // 定时器溢出时间 TIM_TimeBaseStructure.TIM_Prescaler = (84 - 1); // 定时器预分频系数 TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); // 配置 ADC1 和 ADC2 的外部触发源为定时器触发 ADC_ExternalTrigConvCmd(ADC1, ENABLE); ADC_ExternalTrigConvCmd(ADC2, ENABLE); ADC_ExternalTrigConvEdgeConfig(ADC1, ADC_ExternalTrigConvEdge_Rising); ADC_ExternalTrigConvEdgeConfig(ADC2, ADC_ExternalTrigConvEdge_Rising); // 配置 DMA1_Stream0 和 DMA2_Stream0 的传输完成中断 NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); // 使能 DMA1_Stream0 和 DMA2_Stream0 的传输完成中断 DMA_ITConfig(DMA1_Stream0, DMA_IT_TC, ENABLE); DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE); // 启动 DMA1_Stream0 和 DMA2_Stream0 DMA_Cmd(DMA1_Stream0, ENABLE); DMA_Cmd(DMA2_Stream0, ENABLE); // 启动定时器 TIM_Cmd(TIM2, ENABLE); // 启动 ADC1 和 ADC2 的转换 ADC_Cmd(ADC1, ENABLE); ADC_Cmd(ADC2, ENABLE); // 启动 ADC1 和 ADC2 的 DMA 传输 ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); ADC_DMARequestAfterLastTransferCmd(ADC2, ENABLE); ADC_DMACmd(ADC1, ENABLE); ADC_DMACmd(ADC2, ENABLE); } void DMA1_Stream0_IRQHandler(void) { if (DMA_GetITStatus(DMA1_Stream0, DMA_IT_TCIF0)) { // 处理 DMA1_Stream0 的传输完成中断 DMA_ClearITPendingBit(DMA1_Stream0, DMA_IT_TCIF0); } } void DMA2_Stream0_IRQHandler(void) { if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0)) { // 处理 DMA2_Stream0 的传输完成中断 DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0); } } int main(void) { ADC_DMA_Config(); while (1) { // 等待 ADC 转换完成 while (DMA_GetFlagStatus(DMA1_Stream0, DMA_FLAG_TCIF0) == RESET) { } // 处理 ADC 数据 for (int i = 0; i < ADC_BUFFER_SIZE; i++) { printf("ADC1: %d, ADC2: %d\n", adc_buffer1[i], adc_buffer2[i]); } // 清除标志位 DMA_ClearFlag(DMA1_Stream0, DMA_FLAG_TCIF0); } } ``` 这段代码配置了 ADC1 和 ADC2 以及相关的 DMA 和定时器,当 DMA 的转换完成中断触发时,可以处理 ADC 数据。你可以根据自己的需要进行修改和扩展。注意,这只是一个示例代码,可能需要根据你的具体硬件和需求进行调整。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值