最近在做一个采集卡的东西,需要采集电压电流,用STM32做主控芯片,考虑到还得驱动其他器件,所以就不能用中断的方式采集,于是有了下面的方法: TIM输出PWM触发ADC, 进行周期性采集,采集数据通过DMA传输至内存,保存64点后,产生一个中断表示采集完成,进行一次FFT变换,得到基波幅值。这样只在采集开始设置一下,然后采集结束后处理,处理过程中又可以进行下一次采集,效率很高。
- /******************** (C) COPYRIGHT 2012 WildFire Team **************************
- 2015.1.1
- 1.TIM2 PWM触发ADC1采集,3200hz,采集完成后数据DMA存到内存,一次64点,采集64点完成产生DMA中断
- 2.用ST公司自带库进行64点FFT运算,测试OK
- **********************************************************************************/
- #include "stm32f10x.h"
- #include "led.h"
- #include "sys.h"
- #include "SysTickDelay.h"
- #include
- #include
- #include "stm32_dsp.h"
- #include "table_fft.h"
- //#define MI_ERR (-2)
- #define PI2 6.28318530717959
- #define NPT 64 /* NPT = No of FFT point*/
- #define Fs 3200
- #define ADC1_DR_Address ((u32)0x40012400+0x4c)
- void led_init(void);
- void Adc_GPIO_Init(void);
- void Adc_single_Init(void);
- void ADC1_DMA_Init(void);
- void TIM2_NVIC_Config_1s(void);
- void TIM2_Config_1s(void);
- void TIM2_Configration(void);
- void dsp_asm_init(void);
- void dsp_test(void);
- void dsp_asm_powerMag(void);
- long lBUFIN[NPT]; /* Complex input vector */
- long lBUFOUT[NPT]; /* Complex output vector */
- long lBUFMAG[NPT + NPT/2];/* Magnitude vector */
- long lBUFMAG_base;
- float average = 0.0;
- float voltage = 0.0;
- extern uint16_t TableFFT[];
- __IO uint16_t ADCConvertedValue[64];
- uint8_t DMA_FLAG = 0;
- uint8_t led_flag = 0;
- int main(void)
- {
- led_init();//pc 3 4 5
- SysTick_Initaize();
- Adc_GPIO_Init();//pc2
- Adc_single_Init();
- ADC1_DMA_Init();
- TIM2_Configration();
- while(1)
- {
- led0 = 0;
- led0 = 1;
- while(1)
- {
- while(DMA_FLAG == 0);
- dsp_asm_init();
- dsp_test();
- }
- }
- }
- void led_init(void)
- {
- /*定义一个GPIO_InitTypeDef类型的结构体*/
- GPIO_InitTypeDef GPIO_InitStructure;
- /*开启GPIOC的外设时钟*/
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE);
- /*选择要控制的GPIOC引脚*/
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
- /*设置引脚模式为通用推挽输出*/
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- /*设置引脚速率为50MHz */
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- /*调用库函数,初始化GPIOC*/
- GPIO_Init(GPIOC, &GPIO_InitStructure);
- /* 关闭所有led灯 */
- GPIO_SetBits(GPIOC, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5);
- }
- void Adc_GPIO_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOC, &GPIO_InitStructure);
- }
- void Adc_single_Init(void)
- {
- ADC_InitTypeDef ADC_InitStructure;
- ADC_DeInit(ADC1);
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC1, ENABLE);
- RCC_ADCCLKConfig(RCC_PCLK2_Div6);//设置ADC时钟(ADCCLK) 72MHZ/6 = 12MHZ
- ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
- ADC_InitStructure.ADC_ScanConvMode = DISABLE;//单次模式(单通道)
- ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//连续模式
- ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;//转换由TIM2 CC2 trig
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//ADC数据右对齐
- ADC_InitStructure.ADC_NbrOfChannel = 1;//规则转换的ADC的通道数目,取值范围为1-16
- ADC_Init(ADC1,&ADC_InitStructure);//初始化配置
- ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 1, ADC_SampleTime_7Cycles5);
- ADC_DMACmd(ADC1, ENABLE);//enable DMA
- ADC_Cmd(ADC1,ENABLE);// enable adc
- ADC_ResetCalibration(ADC1);
- while( ADC_GetResetCalibrationStatus(ADC1));//获取ADC重置校准寄存器的状态 等待复位结束
- ADC_StartCalibration(ADC1);//开始指定ADC的校准状态
- while( ADC_GetCalibrationStatus(ADC1) );
- ADC_ExternalTrigConvCmd(ADC1,ENABLE);
- }
- void ADC1_DMA_Init(void)
- {
- DMA_InitTypeDef DMA_InitStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
- //ADC1 DMA channel 1
- DMA_DeInit(DMA1_Channel1);
- DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
- DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue;
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
- DMA_InitStructure.DMA_BufferSize = 64;
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;// 内存自增
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//16位
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//16位
- DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//DMA normal
- DMA_InitStructure.DMA_Priority = DMA_Priority_High;
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
- DMA_Init(DMA1_Channel1, &DMA_InitStructure);
- NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 主优先级为0
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 次优先级为0
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
- DMA_ITConfig(DMA1_Channel1,DMA_IT_TC, ENABLE);//使能或者失能指定的通道x中断(DMA1 通道1)
- /* Enable DMA1 channel1 */
- DMA_Cmd(DMA1_Channel1, ENABLE);
- }
- void TIM2_NVIC_Config_1s(void)
- {
- NVIC_InitTypeDef NVIC_InitStructure;
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
- NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
- }
- void TIM2_Config_1s(void)
- {
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
- TIM_DeInit(TIM2);
- TIM_TimeBaseStructure.TIM_Period=10000; /* 自动重装载寄存器周期的值(计数值) */
- /* 累计 TIM_Period个频率后产生一个更新或者中断 */
- TIM_TimeBaseStructure.TIM_Prescaler= (7200 - 1); /* 时钟预分频数 72M/72 */
- TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; /* 采样分频 */
- TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; /* 向上计数模式 */
- TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
- TIM_ClearFlag(TIM2, TIM_FLAG_Update); /* 清除溢出中断标志 */
- TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
- TIM_Cmd(TIM2, ENABLE); /* 开启时钟 */
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE); /*先关闭等待使用*/
- }
- void TIM2_Configration(void)
- {
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
- TIM_OCInitTypeDef TIM_OCInitStructure;
- //TIM_DeInit(TIM2);
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
- TIM_TimeBaseStructure.TIM_Period=100; /* 自动重装载寄存器周期的值(计数值) */
- /* 累计 TIM_Period个频率后产生一个更新或者中断 */
- TIM_TimeBaseStructure.TIM_Prescaler= (225 - 1); // 时钟预分频数 72000000/3200 = 22500 = 225 * 100
- TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; /* 采样分频 */
- TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; /* 向上计数模式 */
- TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
- TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
- TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//PWM模式1
- TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能
- TIM_OCInitStructure.TIM_Pulse = 50;//脉冲宽度,由这个设置占空比
- TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;//LOW电平有效
- TIM_OC2Init(TIM2,&TIM_OCInitStructure);//初始化
- TIM_Cmd(TIM2,ENABLE);
- TIM_InternalClockConfig(TIM2);
- TIM_OC2PreloadConfig(TIM2,TIM_OCPreload_Enable);
- TIM_UpdateDisableConfig(TIM2,DISABLE);
- }
- void dsp_asm_init(void)
- {
- uint16_t i = 0;
- //float fx;
- for( i = 0;i
- {
- //fx = 4000 * sin(PI2*i*50.0/Fs ) + 4000*sin(PI2*i*2500.0/Fs) + 4000*sin(PI2*i*2550.0/Fs);
- average = average + ADCConvertedValue[i];
- }
- average = average / NPT;
- for( i = 0;i
- {
- lBUFIN[i] = ((int16_t)(ADCConvertedValue[i] - average)) << 16;
- }
- }
- void dsp_test(void)
- {
- cr4_fft_64_stm32(lBUFOUT, lBUFIN, NPT);
- dsp_asm_powerMag();
- }
- // int main(void)
- // {
- // dsp_asm_init();
- // dsp_test();
- // dsp_test();
- // }
- void dsp_asm_powerMag(void)
- {
- int16_t lX,lY;
- uint32_t i;
- float X =0.0;
- float Y =0.0;
- float Mag = 0.0;
- for(i=0;i
- {
- lX = ( lBUFOUT[i] << 16 ) >> 16;
- lY = ( lBUFOUT[i] >> 16 );
- {
- X = NPT * ((float)lX) / 32768;
- Y = NPT * ((float)lY) / 32768;
- Mag = sqrt ( X*X + Y*Y)/NPT;
- lBUFMAG[i] = (uint32_t)(Mag*65536);
- }
- }
- voltage = (float)(lBUFMAG[1]) / 4096.0 * 3.3;
- // lX = ( lBUFOUT[1] << 16 ) >> 16;
- // lY = ( lBUFOUT[1] >> 16 );
- // X = NPT * ((float)lX) / 32768;
- // Y = NPT * ((float)lY) / 32768;
- // Mag = sqrt ( X*X + Y*Y)/NPT;
- // lBUFMAG_base = (uint32_t)(Mag*65536);
- }