打印

APM32F103 Timer触发ADC DMA采集

[复制链接]
70|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
david-lau|  楼主 | 2024-10-8 12:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一、概述
在APM32项目开发中,我们经常需要进行高速、精确的模拟信号采样。通过使用定时器触发ADC采样,我们可以实现稳定的采样频率,这在各种数据采集应用中非常重要。本文将详细介绍如何使用APM32的定时器来触发ADC进行采样。
二、硬件要求
  • APM32F103系列高性能系列(如APM32F103RC、APM32F103VC等)
  • ADC输入信号连接到PC0引脚
三、基本原理
TIM8是APM32F103系列中的高级定时器,具有多种触发功能。我们可以配置TIM8生成TRGO(触发输出)信号,用于触发ADC1开始转换。每当定时器计数到设定值时,就会产生一个触发信号,从而启动一次ADC转换。
四、详细配置步骤1. 时钟配置
首先需要使能相关外设的时钟:
    /* Enable peripheral clock */
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR8);
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA);
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);
    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_DMA1);
2. GPIO配置
配置ADC输入引脚为模拟输入模式:
    /* Configure PC0 (ADC Channel0) as analog input */
    GPIO_ConfigStructInit(&gpioConfig);
    gpioConfig.mode    = GPIO_MODE_ANALOG;
    gpioConfig.pin     = GPIO_PIN_0;
    GPIO_Config(GPIOA, &gpioConfig);
3. TIM8配置
配置TIM8为主模式,产生触发信号:
void TMR8_Init(void)
{
    TMR_BaseConfig_T TMR_TimeBaseStruct;

    /* Enable peripheral clock */
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR8);

    /* configure TMR3 */
    TMR_ConfigTimeBaseStructInit(&TMR_TimeBaseStruct);

    TMR_TimeBaseStruct.clockDivision = TMR_CLOCK_DIV_1;
    TMR_TimeBaseStruct.countMode = TMR_COUNTER_MODE_UP;
    TMR_TimeBaseStruct.division = 71;
    TMR_TimeBaseStruct.period = 2400;
    TMR_TimeBaseStruct.repetitionCounter = 0;
    TMR_ConfigTimeBase(TMR8, &TMR_TimeBaseStruct);

    TMR_ConfigInternalClock(TMR8);

    /* Disable TMR8 the Master Slave Mode */
    TMR_DisableMasterSlaveMode(TMR8);
    TMR_SelectOutputTrigger(TMR8, TMR_TRGO_SOURCE_UPDATE);


    /* Enable TMR3 Interrupt */
    NVIC_EnableIRQRequest(TMR8_UP_IRQn, 0, 0);
    TMR_EnableInterrupt(TMR8, TMR_INT_UPDATE);

    /* Enable the specified TMR peripheral */
    TMR_Enable(TMR8);
}
4. ADC配置
配置ADC1使用TIM8触发:
void ADC_Init(void)
{
    GPIO_Config_T           gpioConfig;
    ADC_Config_T            adcConfig;

    /* Enable GPIOA clock */
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA);

    /* Configure PC0 (ADC Channel0) as analog input */
    GPIO_ConfigStructInit(&gpioConfig);
    gpioConfig.mode    = GPIO_MODE_ANALOG;
    gpioConfig.pin     = GPIO_PIN_0;
    GPIO_Config(GPIOA, &gpioConfig);

    /* ADCCLK = PCLK2/4 */
    RCM_ConfigADCCLK(RCM_PCLK2_DIV_4);

    /* Enable ADC clock */
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);

    /* ADC configuration */
    ADC_Reset(ADC1);

    ADC_ConfigStructInit(&adcConfig);
    adcConfig.mode                  = ADC_MODE_INDEPENDENT;
    adcConfig.scanConvMode          = DISABLE;
    adcConfig.continuosConvMode     = DISABLE;
    adcConfig.externalTrigConv      = ADC_EXT_TRIG_CONV_EINT11_T8_TRGO;
    adcConfig.dataAlign             = ADC_DATA_ALIGN_RIGHT;
    /* channel number */
    adcConfig.nbrOfChannel          = 1;
    ADC_Config(ADC1, &adcConfig);

    /* ADC channel Convert configuration */
    ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_0, 1, ADC_SAMPLETIME_55CYCLES5);

    /* Enable ADC DMA */
    ADC_EnableDMA(ADC1);

    /* Enable ADC */
    ADC_Enable(ADC1);

    /* Enable ADC1 reset calibration register */
    ADC_ResetCalibration(ADC1);
    /* Check the end of ADC1 reset calibration register */
    while (ADC_ReadResetCalibrationStatus(ADC1));

    /* Start ADC1 calibration */
    ADC_StartCalibration(ADC1);
    /* Check the end of ADC1 calibration */
    while (ADC_ReadCalibrationStartFlag(ADC1));

    /* Enable AFIO clock */
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_AFIO);

    GPIO_ConfigPinRemap(GPIO_REMAP_ADC1_ETRGREG);

    ADC_EnableExternalTrigConv(ADC1);

    ADC_EnableInterrupt(ADC1, ADC_INT_EOC);
    NVIC_EnableIRQRequest(ADC1_2_IRQn, 0, 0);
}
4. DMA配置void DMA_Init(void)
{
    DMA_Config_T dmaConfig;

    /* Enable DMA Clock */
    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_DMA1);

    /* DMA config */
    dmaConfig.peripheralBaseAddr = ADC_DR_ADDR;
    dmaConfig.memoryBaseAddr = (uint32_t)&DMA_ADCConvertedValue;
    dmaConfig.dir = DMA_DIR_PERIPHERAL_SRC;
    dmaConfig.bufferSize = 1;
    dmaConfig.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
    dmaConfig.memoryInc = DMA_MEMORY_INC_DISABLE;
    dmaConfig.peripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_HALFWORD;
    dmaConfig.memoryDataSize = DMA_MEMORY_DATA_SIZE_HALFWORD;
    dmaConfig.loopMode = DMA_MODE_CIRCULAR;
    dmaConfig.priority = DMA_PRIORITY_HIGH;
    dmaConfig.M2M = DMA_M2MEN_DISABLE;

    /* Enable DMA channel */
    DMA_Config(DMA1_Channel1, &dmaConfig);

    DMA_EnableInterrupt(DMA1_Channel1, DMA_INT_TC);
    NVIC_EnableIRQRequest(DMA1_Channel1_IRQn, 0, 0);

    /* Enable DMA */
    DMA_Enable(DMA1_Channel1);
}

六、注意事项
  • TIM8只在APM32F103的大容量产品中可用
  • 采样频率可用过修改TMR8更改
  • 使用中断方式处理转换结果,避免CPU轮询等待
  • ADC校准对于提高采样精度很重要,不要省略
七、常见问题解答
  • Q:如何修改采样频率?A:可以通过调整TIM8的预分频值和周期值来改变触发频率。
  • Q:为什么选择55.5个采样周期?A:较长的采样时间可以提高采样精度,但会降低最大采样频率,需要权衡。
  • Q:如果需要采样多个通道怎么办?A:可以将ADC设置为扫描模式,并配置多个通道。
八、总结
使用TIM8触发ADC1是实现精确定时采样的有效方法。通过合理配置定时器和ADC参数,我们可以实现稳定可靠的数据采集。本文提供的代码和配置可以作为基础,根据具体需求进行修改和扩展。

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

42

帖子

1

粉丝