OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 9995|回复: 9

STM32F103 定时器触发ADC采样,DMA方式?

[复制链接]

1

主题

4

帖子

0

精华

新手入门

积分
12
金钱
12
注册时间
2017-10-11
在线时间
3 小时
发表于 2017-10-11 12:53:05 | 显示全部楼层 |阅读模式
10金钱
本帖最后由 kimirak 于 2017-10-13 11:42 编辑

      我用定时器PWM触发ADC采样,用DMA中断方式读取内存数据,读取到一定数据后(也就是DMA多次中断后),然后在DMA中断中停止定时器,处理完数据后,再初始化定时器。重新开始新一轮的采样。不知道这样能不能实现?
还有以下几个疑问:
1.停止计数器的时候要不要停止ADC和DMA,如何停止?
2.重新启动的时候要不要重新初始化或者启动ADC和DMA?
麻烦各位大神看看,已经困扰好久了,第一次用STM32好多地方还不了解,再次感谢!

//定时器初始化
void TIM2_Int_Init() //4999 7199   72MHZ/(7199+1)/(4999+1)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_OCInitTypeDef TIM_OCInitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能
        
        //定时器TIM2初始化
        TIM_TimeBaseStructure.TIM_Period = 5-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值        
        TIM_TimeBaseStructure.TIM_Prescaler =3600-1; //设置用来作为TIMx时钟频率除数的预分频值
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位

         TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
        TIM_OCInitStructure.TIM_Pulse = 5000;
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
        TIM_OC1Init(TIM2,&TIM_OCInitStructure);
  //      TIM_Cmd(TIM2,ENABLE);

        TIM_InternalClockConfig(TIM2);
        TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
        TIM_UpdateDisableConfig(TIM2, DISABLE);                        
}


                  
//初始化ADC                                                                                                                                          
void  ADC_Configuration(void)
{         
        ADC_InitTypeDef ADC_InitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC|RCC_APB2Periph_ADC1        , ENABLE );          //使能ADC1通道时钟


        RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M

        //PA1 作为模拟通道输入引脚                        
        GPIO_InitStructure.GPIO_Pin = PIN_ULA|PIN_ULB|PIN_ULC|PIN_IA|PIN_IB|PIN_IC;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
        GPIO_Init(GPIOA, &GPIO_InitStructure);        

        //PA1 作为模拟通道输入引脚                        
        GPIO_InitStructure.GPIO_Pin = PIN_UA|PIN_UB|PIN_UC;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
        GPIO_Init(GPIOC, &GPIO_InitStructure);        

        ADC_DeInit(ADC1);  //复位ADC1

        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式
        ADC_InitStructure.ADC_ScanConvMode = ENABLE;        //模数转换工作在单通道模式
        ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式
        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;        //转换由软件而不是外部触发启动
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐
        ADC_InitStructure.ADC_NbrOfChannel = 6;        //顺序进行规则转换的ADC通道的数目

        
        ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   

        //设置指定ADC的规则组通道,设置它们的转化顺序和采样时间
        //ADC1,ADC通道x,规则采样顺序值为y,采样时间为239.5周期
        ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_239Cycles5 );  //TCONV = 采样时间+ 12.5 个周期 = 239.5+12.5 = 252  //21us
        ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_239Cycles5 );
        ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 3, ADC_SampleTime_239Cycles5 );
        ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 4, ADC_SampleTime_239Cycles5 );
        ADC_RegularChannelConfig(ADC1, ADC_Channel_4,  5, ADC_SampleTime_239Cycles5 );
        ADC_RegularChannelConfig(ADC1, ADC_Channel_5,  6, ADC_SampleTime_239Cycles5 );


          ADC_DMACmd(ADC1, ENABLE);  
        
        ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1
        
        ADC_ResetCalibration(ADC1);        //使能复位校准  
         
        while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束
        
        ADC_StartCalibration(ADC1);         //开启AD校准

        while(ADC_GetCalibrationStatus(ADC1));         //等待校准结束

        ADC_ExternalTrigConvCmd(ADC1,ENABLE);

        TIM_Cmd(TIM2, ENABLE);//最后面打开定时器使能  
          DMA_Cmd(DMA1_Channel1, ENABLE);//使能DMA

}                        


void DMA_Configuration(void)
{

        DMA_InitTypeDef DMA_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;   
        
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//
        DMA_DeInit(DMA1_Channel1);                                 //将DMA的通道1寄存器重设为缺省值
        DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR; //DMA外设ADC基地址
//        DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_Value;     //DMA内存基地址
        DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&wAdcValue;     //DMA内存基地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;         //内存作为数据传输的目的地
        DMA_InitStructure.DMA_BufferSize = 6;//10*M;                   //DMA通道的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通道 x拥有高优先级
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
        DMA_Init(DMA1_Channel1, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道
        DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);

        
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);  
    NVIC_InitStructure.NVIC_IRQChannel =DMA1_Channel1_IRQn;   
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;   
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
    NVIC_Init(&NVIC_InitStructure);
}

void  DMA1_Channel1_IRQHandler(void)  
{  
   if(DMA_GetITStatus(DMA1_IT_TC1)!=RESET)
   {  
                DMA_ClearITPendingBit(DMA1_IT_TC1);  

                memcpy(&g_sWaveCode.sWaveCodeItem[s_wTotalDots++],wAdcValue,6);

                if (s_wTotalDots >= (200))
                {
                        ADCONVTOVER;
                        s_wTotalDots = 0;

                        TIM_Cmd(TIM3, DISABLE);  //         
                }

   }

}


//再次启动转化,数据处理完后,程序其他地方调用
void StartNewADC(void)
{
           s_wTotalDots = 0;
        TIM2_Int_Init();
        TIM_Cmd(TIM2, ENABLE);//最后面打开定时器使能  

}



最佳答案

查看完整内容[请看2#楼]

最近我也在研究定时器触发ADC 参考下这个帖子http://www.openedv.com/forum.php?mod=viewthread&tid=277863&highlight=%B6%A8%CA%B1%C6%F7%B4%A5%B7%A2
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

57

主题

1680

帖子

3

精华

资深版主

Rank: 8Rank: 8

积分
4307
金钱
4307
注册时间
2018-6-30
在线时间
808 小时
发表于 2017-10-11 12:53:06 | 显示全部楼层
本帖最后由 1208 于 2018-8-27 13:01 编辑

最近我也在研究定时器触发ADC
参考下这个帖子http://www.openedv.com/forum.php ... 1%C6%F7%B4%A5%B7%A2


stm32定时器è§&.pdf

668.69 KB, 下载次数: 221

业精于勤荒于嬉;行成于思毁于随!
回复

使用道具 举报

1

主题

4

帖子

0

精华

新手入门

积分
12
金钱
12
注册时间
2017-10-11
在线时间
3 小时
 楼主| 发表于 2017-10-11 16:38:47 | 显示全部楼层
怎么只看不回复呢?
回复

使用道具 举报

6

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
190
金钱
190
注册时间
2016-8-25
在线时间
50 小时
发表于 2017-10-11 17:29:21 | 显示全部楼层
kimirak 发表于 2017-10-11 16:38
怎么只看不回复呢?

楼主,知道了分享下,我也想用这种方法,要不采PWM的AD值不知道怎么采
回复

使用道具 举报

1

主题

4

帖子

0

精华

新手入门

积分
12
金钱
12
注册时间
2017-10-11
在线时间
3 小时
 楼主| 发表于 2017-10-12 10:20:18 | 显示全部楼层
panxing 发表于 2017-10-11 17:29
楼主,知道了分享下,我也想用这种方法,要不采PWM的AD值不知道怎么采

可是没有大神过来呀!
回复

使用道具 举报

21

主题

84

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
374
金钱
374
注册时间
2016-6-8
在线时间
79 小时
发表于 2017-10-12 11:57:47 | 显示全部楼层
你问的另个问题就是一个问题。
你ADC工作在单次转换模式,转换成功一次后就停止了,DMA关不关无所谓,因为DMA始终都是把ADC的数据送到你的目的内存地址。
也就是说ADC成功转换一次,ADC停止,DMA继续运行着,他传输的值应该是0吧。

还有点建议:
你可以把数据放在一个缓存里,这样你处理数据管处理数据,定时器产生PWM你就让它产生着就好了。
还有个疑问:
你的PWM输出结果正确吗?
回复

使用道具 举报

1

主题

4

帖子

0

精华

新手入门

积分
12
金钱
12
注册时间
2017-10-11
在线时间
3 小时
 楼主| 发表于 2017-10-13 11:43:33 | 显示全部楼层
我叫做大熙熙 发表于 2017-10-12 11:57
你问的另个问题就是一个问题。
你ADC工作在单次转换模式,转换成功一次后就停止了,DMA关不关无所谓,因为 ...

之前的配置错了,现在改了一下,可是没有PWM输出,求问哪里有问题?
回复

使用道具 举报

5

主题

103

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
453
金钱
453
注册时间
2016-8-8
在线时间
101 小时
发表于 2017-10-13 15:05:59 | 显示全部楼层
1.停止计数器的时候要不要停止ADC和DMA,如何停止?
为什么要停止ADC和计数器。
2.重新启动的时候要不要重新初始化或者启动ADC和DMA?
为什么要重新初始化。

你在想想。
如何拿下蒙住眼的树叶。
回复

使用道具 举报

21

主题

84

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
374
金钱
374
注册时间
2016-6-8
在线时间
79 小时
发表于 2017-10-16 11:14:58 | 显示全部楼层
kimirak 发表于 2017-10-13 11:43
之前的配置错了,现在改了一下,可是没有PWM输出,求问哪里有问题?

不好意思啊,最近都只是偶尔上一下论坛,是这样的,
PWM输出跟桑三个值有关,
1.重载寄存器的值-这个值就是变化的区间,你配置的时候设置的是4
“TIM_TimeBaseStructure.TIM_Period = 5-1;”

2. 当前计数值-就是一直在计数的那个值在TIMx_CNT里
3. 比较值-用于比较的值,你设置的是5000
“TIM_OCInitStructure.TIM_Pulse = 5000;”


所以,计数器的值只能一直在[0,4]变化,所以你没有PWM输出
回复

使用道具 举报

0

主题

5

帖子

0

精华

初级会员

Rank: 2

积分
53
金钱
53
注册时间
2017-3-6
在线时间
10 小时
发表于 2017-10-17 10:57:14 来自手机 | 显示全部楼层
个人推荐   adc  得到数据直接传给dma数组   当dma数组满了以后进入dma中断   然后处理数据平均值  储存到外部缓冲区
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-7-12 15:07

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表