新手上路
- 积分
- 33
- 金钱
- 33
- 注册时间
- 2020-7-22
- 在线时间
- 9 小时
|
10金钱
【目的】:我想用 STM32F407内部ADC单路+定时器+DMA 采集100kHz的信号,读取一定数量的点并进行FFT分析。
【目前想的步骤】:1. 定时器3(定时器作用是控制采样频率)的TRGO触发ADC转换;2. ADC数据转换发出DMA请求;3. DMA搬移数据到存储区,搬移设定的数据量后开启DMA中断;4. DMA中断内部置标记位,读取数据,并关闭DMA(只采集一次)5. main中判断标记位并串口输出。
【异或】:
下面是我的代码
////////////////////////////////////////////////////////////////////////////////////////////////////////////////【adc.c】////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "adc.h"
#include "extern.h"
u16 ADC1_ConvertedValue[ ADC1_DMA_Size ];//目标寄存器,u16就是unsigned short int,u16这个数据大小与DMA_SxCR寄存器的MSIZE[1:0]位有关。
//ADC引脚配置
void ADC_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA , ENABLE ); //使能AHB时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//PA5引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//输入模式
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//无上拉
GPIO_Init(GPIOA, &GPIO_InitStructure );//初始化结构体
}
//TIM3初始化,作为ADC的采样触发源
void TIM3_Config( void )
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
//TIM3时间基准配置
RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3 , ENABLE ); //使能时钟
TIM_TimeBaseStructure.TIM_Period = 5-1 ;//自动重装载计数次数
TIM_TimeBaseStructure.TIM_Prescaler = 84-1-1;//分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//时钟分频因子
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInit( TIM3 , &TIM_TimeBaseStructure );
TIM_SelectOutputTrigger( TIM3 , TIM_TRGOSource_Update );//选择TIM3的UPDATA事件更新为触发源
TIM_ARRPreloadConfig( TIM3 , ENABLE );//允许TIM3定时重载
TIM_Cmd( TIM3 , ENABLE );//使能TIM3
}
//ADC-DMA触发使能
//Size:单次传输的数据量
void ADC_DMA_Trig( u16 Size )
{
DMA2_Stream0->CR &= ~((uint32_t)DMA_SxCR_EN); //DMA流失能
while (DMA_GetCmdStatus(DMA2_Stream0) != DISABLE){}//等待DMA可配置
DMA2_Stream0->NDTR = Size;//设置数量
DMA_ClearITPendingBit( DMA2_Stream0 ,DMA_IT_TCIF0| DMA_IT_FEIF0|DMA_IT_DMEIF0|DMA_IT_TEIF0|DMA_IT_HTIF0);//清除DMA2的中断标记位
ADC1->SR &= (uint32_t)(0x1F); //ADC所有状态清零
DMA2_Stream0->CR |= (uint32_t)DMA_SxCR_EN; //DMA流使能
}
//ADC与DMA关联性配置
//注:2000K采样频率,采集6000个数据,需要花费3ms
void ADC_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC1 , ENABLE );//使能ADC1时钟
ADC_DeInit( );//ADC复位
/* Enable the DMA Stream IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* DMA2 Stream0 channel0 configuration*/
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_DMA2 , ENABLE );//使能DMA2时钟
DMA_DeInit( DMA2_Stream0 );//DMA复位,默认外设是流控制器
while (DMA_GetCmdStatus(DMA2_Stream0) != DISABLE){}//等待DMA可配置
DMA_InitStructure.DMA_Channel = DMA_Channel_0;//通道0
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_ADDRESS;//外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ADC1_ConvertedValue;//寄存器地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//模式配置:外设->寄存器
DMA_InitStructure.DMA_BufferSize = ADC1_DMA_Size;//DMA 传输数量
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_Circular;//普通模式,不选择循环采集
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;//FIFO关闭
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//寄存器单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设单次传输
DMA_Init( DMA2_Stream0 , &DMA_InitStructure );//选择DMA2 流0
DMA_ClearITPendingBit( DMA2_Stream0 ,DMA_IT_TCIF0| DMA_IT_FEIF0|DMA_IT_DMEIF0|DMA_IT_TEIF0|DMA_IT_HTIF0);//清除DMA2的中断标记位
DMA_ITConfig( DMA2_Stream0 , DMA_IT_TC , ENABLE );//使能DMA2传输完成中断
/* ADC Common Init */
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;//4分频,84M(APB2)/4=21M,ADC 时钟最好不要超过36Mhz
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;//DMA模式禁止(对多ADC模式),【ADC_CCR_DMA=0】
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;//两个采样周期间间隔5个周期
ADC_CommonInit( &ADC_CommonInitStructure );
/* ADC1 Init */
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//12位
ADC_InitStructure.ADC_ScanConvMode = DISABLE;//关闭扫描模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//关闭连续转换
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;//外部上升沿
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO;//TIM3作为ADC的触发源
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐
ADC_InitStructure.ADC_NbrOfConversion = 1;//规则通道序列长度,这里只有一个通道
ADC_Init( ADC1, &ADC_InitStructure );
ADC_RegularChannelConfig( ADC1 , ADC_Channel_5 , 1 , ADC_SampleTime_3Cycles);//采样周期3
ADC_DMARequestAfterLastTransferCmd( ADC1 , ENABLE );//1:只要发生数据转换且DMA = 1,便会发出DAM请求【ADC_CR2_DDS=1】
ADC_DMACmd(ADC1, ENABLE);//ADC开启DMA功能,【CR2_DMA=1】
ADC_Cmd(ADC1, ENABLE);//开启ADC,【ADC_CR2_ADON=1】
ADC_SoftwareStartConv(ADC1);//ADC开始转换,我们每次单次转换模式下转换时都需要向该位写1,【ADC_CR2_SWSTART=1】
}
//DMA中断服务程序
void DMA2_Stream0_IRQHandler( void )
{
u16 i=0;
if(DMA_GetITStatus(DMA2_Stream0,DMA_IT_TCIF0))
{
DMA_ClearITPendingBit(DMA2_Stream0,DMA_IT_TCIF0);//清除中断标记位
DMA_Cmd( DMA2_Stream0 , DISABLE );//关闭DMA2,,
end=1;
for(i=0;i<ADC1_DMA_Size;i++)
Samp_Data=ADC1_ConvertedValue;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////【main.c】///////////////////////////
int main(void)
{
u16 i;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口波特率为115200
AD9834_Init(); //初始化AD9834
AD9834_Select_Wave(Sine_Wave);
AD9834_Set_Freq(FREQ_1,1000); //20kHz
ADC_GPIO_Init(); // ADC引脚初始化。
TIM3_Config( SAM_FRE ); // 触发ADC采样频率,采样频率
ADC_Config(); // ADC
ADC_DMA_Trig( ADC1_DMA_Size ); // 开始AD采集,设置采样点数
while(1)
{
if(end==1)
{
printf("\r\n------------converned-------------\r\nInter_Count=%d\r\n",Inter_Count);
for(i=0;i<ADC1_DMA_Size;i++)
{
printf("%f\r\n",Samp_Data*(3.3/4096));
}
end=0;
}
}
}
【下面这个是我采集的数据】

|
|