最近在做一个采集卡的东西,需要采集电压电流,用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 <math.h>
-
#include <stdio.h>
-
#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<NPT;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<NPT;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<NPT/2;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);
-
-
}