进行定时采样的方法大致有三种:
1、使用定时器中断每隔一定时间进行ADC转换,这样每次都必须读ADC的数据寄存器,如果采样率很低到时可以用。
2、把ADC设置成连续转换模式,同时对应的DMA通道开启循环模式,这样ADC就一直在进行数据采集然后通过DMA把数据搬运至内存(一个U16变量)。
然后再加一个定时中断,定时读取那个U16变量,存入你的采样数组。
3、使用定时器触发ADC转换的功能,然后使用DMA进行数据的搬运。这样只要设置好定时器的触发间隔,就能实现ADC定时采样转换的功能,
然后可以在程序的死循环中一直检测DMA转换完成标志,然后进行数据的读取,或者使能DMA转换完成中断,这样每次转换完成就会产生中断。
第三种方法较于第二种方法的好处在于它由定时器触发ADC采样,那样ADC的采样间隔会更加均匀,方便闭环控制、数据滤波等操作。
本文示意采用第三种方法的配置过程。
//一次采集多少数据
u16 ADC_BUFFER[BufferSize];
u8 ADC_DMA_FINISHED;
void TIM5_Init(void)
{
//设置触发ADC的定时器5 通道1
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);
TIM_TimeBaseStructure.TIM_Period=999;//设置1ms一次TIM5比较的周期 = 1 KHz
TIM_TimeBaseStructure.TIM_Prescaler=83;//系统主频84M,这里分频83,相当于1000K的定时器10时钟
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//下面详细说明
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//TIM_OutputState_Disable;
TIM_OCInitStructure.TIM_Pulse=499;
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;//如果是PWM1要为Low,PWM2则为High
TIM_OC1Init(TIM5,&TIM_OCInitStructure); // channel 1
TIM_SelectOutputTrigger(TIM5, TIM_TRGOSource_OC1Ref); //选择TIM5的OC1事件更新为触发源
}
//初始化ADC with DMA
void ADC_DMA_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM5_Init();
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);//使能GPIOC时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能ADC1时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能
//先初始化ADC1通道10 IO口
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//PC0 通道10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//不带上下拉
GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化
RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE); //ADC1复位
RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE); //复位结束
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;//两个采样阶段之间的延迟5个时钟 47.6 ns*5 = 238.1 ns
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //DMA失能
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//预分频4分频。ADCCLK=PCLK2/4=84/4=21Mhz,ADC时钟最好不要超过36Mhz
ADC_CommonInit(&ADC_CommonInitStructure);//初始化
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//12位模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//关闭连续转换 ;如果开启,后续的转换就会永不停歇(除非CONT清0)
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;//上升沿触发检测
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T5_CC1;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐
ADC_InitStructure.ADC_NbrOfConversion = 1;//1个转换在规则序列中 也就是只转换规则序列1
ADC_Init(ADC1, &ADC_InitStructure);//ADC初始化
ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1,ADC_SampleTime_480Cycles); // 不间断连续(最大)采样间隔大约23.5 us -->42KHz
DMA_DeInit(DMA2_Stream0);
while (DMA_GetCmdStatus(DMA2_Stream0) != DISABLE){}//等待DMA可配置
/* 配置 DMA Stream */
DMA_InitStructure.DMA_Channel = DMA_Channel_0; //通道选择
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR;//DMA外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = (u32)ADC_BUFFER;//DMA 存储器0地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//外设到存储器模式
DMA_InitStructure.DMA_BufferSize = BufferSize;//数据传输量
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_PeripheralDataSize_HalfWord;//存储器数据长度:16位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 不使用循环模式 ,普通模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输
DMA_Init(DMA2_Stream0, &DMA_InitStructure);//初始化DMA Stream
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);
DMA_ITConfig(DMA2_Stream0,DMA_IT_TC,ENABLE); //使能传输完成中断
}
void Start_Sample()
{
TIM_Cmd(TIM5,ENABLE);
ADC_Cmd(ADC1, ENABLE);//打开AD转换器 失能ADC_ADON=1
ADC_DMACmd(ADC1,ENABLE);
DMA_Cmd(DMA2_Stream0, ENABLE); //使能DMA
ADC_DMA_FINISHED = 0;
//ADC_SoftwareStartConv(ADC1);
}
void Stop_Sample()
{
TIM_Cmd(TIM5,DISABLE);
ADC_Cmd(ADC1, DISABLE);//关闭AD转换器 失能ADC_ADON=0
ADC_DMACmd(ADC1,DISABLE);
DMA_Cmd(DMA2_Stream0, DISABLE); //失能DMA
ADC_DMA_FINISHED = 1;
}
void DMA2_Stream0_IRQHandler(void)
{
if(DMA_GetITStatus(DMA2_Stream0,DMA_IT_TCIF0)!=RESET)
{
DMA_ClearITPendingBit(DMA2_Stream0,DMA_IT_TCIF0);
Stop_Sample();
}
}
void ADC2Voltage(u16* adc,float*vol)
{
u16 i;
for(i=0;i
0