代码:
volatile uint8_t TimerTrgAdcOkFlag=0;
//------------------------------------ DMA 初始化 ----------------------------------------------------------------
void DmaInit(void)
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE); //使能DMA时钟
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_Address; //DMA外设ADC基地址
DMA_InitStructure.DMA_MemoryBaseAddr =(uint32_t)&AdResults; //DMA内存基地址*/
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //方向:外设为源地址 即外设-》内存
DMA_InitStructure.DMA_BufferSize = ADC_SAMP_CNT; //搬运数量
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //DMA外设地址不自加
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
//DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //循环搬运
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //搬运完DMA_BufferSize 后不再搬运
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; // 配置DMA中断源
NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_ClearITPendingBit(DMA_IT_TC); //清除一次DMA中断标志
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE); //使能DMA传输完成中断
DMA_ClearITPendingBit(DMA_IT_TC); //清除一次DMA中断标志
DMA_Cmd(DMA1_Channel1, ENABLE); //使能DMA1
}
//配置ADC触发 = 定时器TIM15,用更新事件触发
void TimTrgInit(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
//(1)选择TIM15 Update事件作为触发源(计数器溢出)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM15, ENABLE);
TIM_DeInit(TIM15); //配置基础
TIM_TimeBaseStructure.TIM_ClockDivision=0; //48M
TIM_TimeBaseStructure.TIM_Prescaler=48-1;//48000; //48k 1Tick=1ms
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period=20-1;//1000*1; //50K
TIM_TimeBaseStructure.TIM_Period=25-1;//1000*1; //40K
TIM_TimeBaseStructure.TIM_Period=50-1;//1000*1; //20K
TIM_TimeBaseStructure.TIM_Period=FS_PRE-1;
TIM_TimeBaseStructure.TIM_RepetitionCounter=0; //发生RepetitionCounter+1次溢出事件后中断
TIM_TimeBaseInit(TIM15,&TIM_TimeBaseStructure);
TIM_SelectOutputTrigger(TIM15,TIM_TRGOSource_Update); //TIM15的Update事件作为外部TRGO
TIM_ClearFlag(TIM15,TIM_FLAG_Update); //防止一上电进入中断 貌似可以不用??
TIM_Cmd(TIM15,ENABLE); //使能TIM15
ADC_StartOfConversion(ADC1); //如果是软件触发将立即开始转换,
//如果是定时器触发则等待定时触发信号来到启动。
NVIC_InitStructure.NVIC_IRQChannel = TIM15_IRQn; // 配置DMA中断源
NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIM15,TIM_IT_Update,ENABLE); //使能中断用来调试,
}
//-----------配置ADC为TIM15触发--------------
void AdcConfig(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
//DMA_InitTypeDef DMA_InitStructure;
//TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
//NVIC_InitTypeDef NVIC_InitStructure;
//----gpio----
RCC_APB2PeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_5; //Configure PA.0 PA.1 as analog input
//GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //Configure PA.0 PA.1 as analog input
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//-----adc-----
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_ADCCLK_PCLK_Div4); //ADC时钟不能大于14M
ADC_DeInit(ADC1);
ADC_StructInit(&ADC_InitStructure);
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right; //右对齐
ADC_InitStructure.ADC_ExternalTrigConvEdge=ADC_ExternalTrigConvEdge_Rising; //上升沿触发
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_T15_TRGO; //TIM15触发
// ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC4;//选择TIM1 Compare&Capture4 作为触发源
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; //12位精度
ADC_InitStructure.ADC_ContinuousConvMode=DISABLE; //连续模式禁止 要由定时器触发
ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward; //CH0-18
ADC_Init(ADC1, &ADC_InitStructure);
ADC_OverrunModeCmd(ADC1,ENABLE); //数据覆盖方式,只保留最新的转换数据
//ADC_ChannelConfig(ADC1,ADC_Channel_0|ADC_Channel_1,ADC_SampleTime_1_5Cycles);
ADC_ChannelConfig(ADC1,ADC_Channel_1,ADC_SampleTime_1_5Cycles);
ADC_GetCalibrationFactor(ADC1); // 开始ADC校准
ADC_Cmd(ADC1,ENABLE);
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN)==RESET); //等待ADC准备好
ADC_DMACmd(ADC1,ENABLE); //使能ADC
ADC_DMARequestModeConfig(ADC1,ADC_DMAMode_Circular); //ADC模式
//ADC_DMARequestModeConfig(ADC1,ADC_DMAMode_OneShot); //DMA循环模式
//------dma-----------
DmaInit();
//-------trg timer------
TimTrgInit();
}
//传输完512个数据后,进入中断。在中断中我关闭触发定时器 并TimerTrgAdcOkFlag=1 声明采集传送完毕。
void DMA1_Channel1_IRQHandler()
{
//DMA_InitTypeDef DMA_InitStructure;
if(DMA_GetITStatus(DMA1_IT_TC1) != RESET) //判断DMA传输完成中断
{
TimerTrgAdcOkFlag = 1;
//toggle(GPIOC,GPIO_Pin_13);
TIM_Cmd(TIM15,DISABLE); //关闭触发用的定时器
DMA_ClearITPendingBit(DMA1_IT_TC1); //清除DMA中断标志位
}
}
//-----------------------至此某个通道的一组数据就已经成功搬运存储完毕, 然后我有个timer3 是不停的在跑的并开启了溢出中断。在中断检测 当 TimerTrgAdcOkFlag 为0时就会再次初始化DMA和触发定时器。 这样就会继续采集搬运了
void TIM3_IRQHandler()
{
//static uint8_t cnt=0;
if(TIM_GetITStatus(TIM3, TIM_IT_Update)!= RESET) //判断发生update事件中断
{
tick++;
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除update事件中断标志
//toggle(GPIOC,GPIO_Pin_13);
if(TimerTrgAdcOkFlag==0) //上次数据处理完毕
{
if(!(TIM15->CR1 & TIM_CR1_CEN)) //且TIM15定时器 在关闭状态
{
DmaInit();
TimTrgInit(); //开启下一笔数据采集
}
}
}
}
//----------------------- 当我要切换通道时调用下面这个函数-----------------------------
void SetAdcChannel(uint32_t ADC_Channel)
{
while(0==TimerTrgAdcOkFlag); //等待上一次数据采集完成
ADC1->CR &= (uint32_t)(~ADC_CR_ADSTART); //设置START=0 才可以修改通道
ADC_ChannelConfig(ADC1,ADC_Channel,ADC_SampleTime_1_5Cycles);
ADC1->CHSELR = (uint32_t)ADC_Channel; //修改通道
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY)){};
DelayMs(5);
TimerTrgAdcOkFlag=0; //申明上一次数据处理完毕 , timer3中断里如果判断为0 就开始下次采集
//ADC1->CR |= (uint32_t)ADC_CR_ADSTART; //使能触发转换
//while(0==TimerTrgAdcOkFlag); //等待上一次数据采集完成
//TimerTrgAdcOkFlag=0;
}
SetAdcChannel(ADC_Channel_2); 等待TimerTrgAdcOkFlag=1 ----》查看结果 ---》SetAdcChannel(ADC_Channel_2); 等待TimerTrgAdcOkFlag=1 ----》查看结果 。。。 这样ADC_Channel_2数据是对的
SetAdcChannel(ADC_Channel_2); 等待TimerTrgAdcOkFlag=1 ----》查看结果 ---》SetAdcChannel(ADC_Channel_1); 等待TimerTrgAdcOkFlag=1 ----》查看结果 .。。 这样ADC_Channel_2数据是错的 |