- void TMR_Init(void) {
- TMR_BaseConfig_T timBaseConfig;
- RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR2);
- //系统工作主频为168M,由于APB1是4分频,所以tmr2时钟84M计算如下
- timBaseConfig.period = 83; //设置定时器时基为125us,(83+1)*(124+1)/(84m) = 125us
- timBaseConfig.division = 124;
- timBaseConfig.clockDivision = TMR_CLOCK_DIV_1;
- timBaseConfig.countMode = TMR_COUNTER_MODE_UP;
- TMR_ConfigTimeBase(TMR2,&timBaseConfig);
-
- //选择外部触发源
- TMR_SelectOutputTrigger(TMR2, TMR_TRGO_SOURCE_UPDATE);
-
- TMR_EnableInterrupt(TMR2,TMR_INT_UPDATE);
- NVIC_EnableIRQRequest(TMR2_IRQn,0,0);
-
- TMR_Enable(TMR2);
- }
系统工作主频为168M,由于APB1是4分频,所以tmr2时钟84M计算如下:(83+1)*(124+1)/(84m) = 125us
也就是在默认168M主频下TMR2触发ADC采样的周期是125us.
对应的,ADC的初始化中增加外部触发的配置:
- void ADC_Init(void)
- {
- GPIO_Config_T gpioConfig;
- ADC_Config_T adcConfig;
- ADC_CommonConfig_T adcCommonConfig;
- /* RCM Enable*/
- RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA|RCM_AHB1_PERIPH_GPIOB|RCM_AHB1_PERIPH_GPIOC);
- /* GPIO Configuration */
- GPIO_ConfigStructInit(&gpioConfig);
- gpioConfig.pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6;
- gpioConfig.mode = GPIO_MODE_AN;
- gpioConfig.pupd = GPIO_PUPD_NOPULL;
- GPIO_Config(GPIOA, &gpioConfig);
-
- GPIO_ConfigStructInit(&gpioConfig);
- gpioConfig.pin = GPIO_PIN_0|GPIO_PIN_1;
- gpioConfig.mode = GPIO_MODE_AN;
- gpioConfig.pupd = GPIO_PUPD_NOPULL;
- GPIO_Config(GPIOB, &gpioConfig);
-
- GPIO_ConfigStructInit(&gpioConfig);
- gpioConfig.pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
- gpioConfig.mode = GPIO_MODE_AN;
- gpioConfig.pupd = GPIO_PUPD_NOPULL;
- GPIO_Config(GPIOC, &gpioConfig);
- RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);
- RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC2);
- RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC3);
- ADC_Reset();
- /* ADC Common Configuration */
- adcCommonConfig.mode = ADC_MODE_TRIPLE_REGSIMULT;//3ADC规则同步模式
- adcCommonConfig.prescaler = ADC_PRESCALER_DIV4;
- adcCommonConfig.accessMode = ADC_ACCESS_MODE_1;
- adcCommonConfig.twoSampling = ADC_TWO_SAMPLING_10CYCLES;
- ADC_CommonConfig(&adcCommonConfig);
- /* ADC Configuration */
- ADC_ConfigStructInit(&adcConfig);
- /* Set resolution*/
- adcConfig.resolution = ADC_RESOLUTION_12BIT;
- /* Set dataAlign*/
- adcConfig.dataAlign = ADC_DATA_ALIGN_RIGHT;
- /* Set scanDir*/
- adcConfig.scanConvMode = ENABLE;
- /* Set convMode continous*/
- adcConfig.continuousConvMode = DISABLE;
- /* Set extTrigEdge*/
- adcConfig.extTrigEdge = ADC_EXT_TRIG_EDGE_RISING;
- adcConfig.extTrigConv = ADC_EXT_TRIG_CONV_TMR2_TRGO; //设置ADC使用TMR2触发
- /* Set nbrOfConversion*/
- adcConfig.nbrOfChannel = 4;
- ADC_Config(ADC1, &adcConfig);
- ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_0, 1, ADC_SAMPLETIME_3CYCLES);
- ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_1, 2, ADC_SAMPLETIME_3CYCLES);
- ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_2, 3, ADC_SAMPLETIME_3CYCLES);
- ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_4, 4, ADC_SAMPLETIME_3CYCLES);
- ADC_Config(ADC2, &adcConfig);
- ADC_ConfigRegularChannel(ADC2, ADC_CHANNEL_5, 1, ADC_SAMPLETIME_3CYCLES);
- ADC_ConfigRegularChannel(ADC2, ADC_CHANNEL_6, 2, ADC_SAMPLETIME_3CYCLES);
- ADC_ConfigRegularChannel(ADC2, ADC_CHANNEL_8, 3, ADC_SAMPLETIME_3CYCLES);
- ADC_ConfigRegularChannel(ADC2, ADC_CHANNEL_9, 4, ADC_SAMPLETIME_3CYCLES);
-
- ADC_Config(ADC3, &adcConfig);
- ADC_ConfigRegularChannel(ADC3, ADC_CHANNEL_10, 1, ADC_SAMPLETIME_3CYCLES);
- ADC_ConfigRegularChannel(ADC3, ADC_CHANNEL_11, 2, ADC_SAMPLETIME_3CYCLES);
- ADC_ConfigRegularChannel(ADC3, ADC_CHANNEL_12, 3, ADC_SAMPLETIME_3CYCLES);
- ADC_ConfigRegularChannel(ADC3, ADC_CHANNEL_13, 4, ADC_SAMPLETIME_3CYCLES);
-
-
- ADC_EnableMultiModeDMARequest();
- /* Enable ADC*/
- ADC_Enable(ADC1);
- ADC_Enable(ADC2);
- ADC_Enable(ADC3);
- ADC_SoftwareStartConv(ADC1);
- }
这样的话ADC就会由定时器TMR2触发采样,采样完成后有DMA搬运到数组中,触发DMA完成中断进行数据处理。
- void DMA2_STR0_IRQHandler(void)
- {
- if(DMA_ReadIntFlag(DMA2_Stream0,DMA_INT_TCI**0) != RESET)
- {
- APM_MINI_LEDToggle(LED2);
- APM_MINI_LEDOn(LED2);
- ADC1_CH0_ConvertedValue = (float)DMA_DualConvertedValue[0]/4095*3.3f;
- ADC2_CH5_ConvertedValue = (float)DMA_DualConvertedValue[1]/4095*3.3f;
- ADC3_CH10_ConvertedValue = (float)DMA_DualConvertedValue[2]/4095*3.3f;
-
- ADC1_CH1_ConvertedValue = (float)DMA_DualConvertedValue[3]/4095*3.3f;
- ADC2_CH6_ConvertedValue = (float)DMA_DualConvertedValue[4]/4095*3.3f;
- ADC3_CH11_ConvertedValue = (float)DMA_DualConvertedValue[5]/4095*3.3f;
-
- ADC1_CH2_ConvertedValue = (float)DMA_DualConvertedValue[6]/4095*3.3f;
- ADC2_CH8_ConvertedValue = (float)DMA_DualConvertedValue[7]/4095*3.3f;
- ADC3_CH12_ConvertedValue = (float)DMA_DualConvertedValue[8]/4095*3.3f;
-
- ADC1_CH4_ConvertedValue = (float)DMA_DualConvertedValue[9]/4095*3.3f;
- ADC2_CH9_ConvertedValue = (float)DMA_DualConvertedValue[10]/4095*3.3f;
- ADC3_CH13_ConvertedValue = (float)DMA_DualConvertedValue[11]/4095*3.3f;
- DMA_ClearIntFlag(DMA2_Stream0,DMA_INT_TCI**0);
- }
- }
- void TMR2_IRQHandler(void){
- if (TMR_ReadIntFlag(TMR2, TMR_INT_UPDATE) != RESET) {
- APM_MINI_LEDOff(LED2);
- TMR_ClearIntFlag(TMR2, TMR_INT_UPDATE);
- }
- }
同时,这样也可以使用一个IO在TMR2中断中置高,在DMA完成中断中置低,IO的高电平时间就相当于ADC采样转化的时间。
我们也可以先看看理论上的ADC采样时间改如何计算:
ADC时钟在APB2总线上,最大是主频的二分频也就是84Mhz。
ADC的时钟通过 adcCommonConfig.prescaler = ADC_PRESCALER_DIV4;再分频下来。
这里测试是4分频也就是21Mhz
ADC的转换时间公司在用户手册中可以看到:
TCONV=采样时间+12 个周期;采样时间由 SMPCYCCFGx[2:0]位控制,最小采样周期为 3 个
也就是我配置的: ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_0, 1, ADC_SAMPLETIME_3CYCLES);
所以我目前配置的采样频率是21M÷(3+12)=1.4M,对应的采样时间为0.714us。
我使用三ADC采12个通道需要采4次也就是我目前配置的理论采样时间就是4*0.713us=2.856us。
而实际的采样时间我们通过示波器输出来看:
实际采样时间是3.333us
将采样周期改成15后: ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_0, 1, ADC_SAMPLETIME_15CYCLES);
理论采样时间就是5.143us
实际采样时间是5.529us
可以看到实际值比理论值略大零点几us,这主要是DMA传输以及进出中断的指令占的时间.
所以APM32F407ADC的采样时间与理论是相符的。