32mo tim adc dma

闲来无事,玩玩去年申请过来的STM32f0Discovery,决定试试 ADC+TIM+DMA方式。具体方法是每隔10s钟TIM触发一次AD转换,之后从DMA读走数据。讲讲ADC中最重要编程的部分,看看下面这张ADC结构图:


      ADC可选择外部触发,有5个信号,TIM1_TRGO,TIM1_CC4,...TIM15_TRGO,TIM1_CC4容易理解,就是TIM1输出捕获4通道触发(PWM模式下)。那TRGO是什么呢?Trigger Output,触发输出,定时器均有Trigger Output信号(自己看看定时器的结构图),以下事情可以触发TRGO信号:(摘自stm32f0xx.tim.c   TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource)函数)
  *   - For all TIMx
  *            @arg TIM_TRGOSource_Reset:  The UG bit in the TIM_EGR register is used as the trigger output (TRGO).
  *            @arg TIM_TRGOSource_Enable: The Counter Enable CEN is used as the trigger output (TRGO).
  *            @arg TIM_TRGOSource_Update: The update event is selected as the trigger output (TRGO).
  *
  *   - For all TIMx except TIM6 
  *            @arg TIM_TRGOSource_OC1: The trigger output sends a positive pulse when the CC1IF flag
  *                                     is to be set, as soon as a capture or compare match occurs (TRGO).
  *            @arg TIM_TRGOSource_OC1Ref: OC1REF signal is used as the trigger output (TRGO).
  *            @arg TIM_TRGOSource_OC2Ref: OC2REF signal is used as the trigger output (TRGO).
  *            @arg TIM_TRGOSource_OC3Ref: OC3REF signal is used as the trigger output (TRGO).
  *            @arg TIM_TRGOSource_OC4Ref: OC4REF signal is used as the trigger output (TRGO).
即复位、使能、输出捕获均能引起TRGO事件。所以若想利用TIM的TRGO引发ADC转换,记得必须加上:
TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource) 函数选择定时器的TRGO。当如果你想利用TIM1_CC4触发,就不必使用该函数,因为CC4不在TRGO行列内!
       上面有TIM_TRGOSource_OC1和TIM_TRGOSource_OC1Ref,OCxRef和OCx有啥区别,这里,有许多PWM模式知识要将。看看下面这张结构图:

      OCxRef参看信号由PWM模式决定,OCxRef再经过极性选择得到OCx,OCx必须被使能输出才得到PWM。PWM有模式1和模式2。PWM mode1为:当计数值cnt<预定值ccr时,输出有效电平(可简单视为高电平),cnt=ccr时,触发PWM,输出无效电平(低电平);mode2相反,cnt<ccr,输出高,cnt>ccr,输出低;必须说说有两种计数模式,向上计数和向下计数;向上计数,从0向上递增;向下计数,从0xfff向下递减。 所以若选择PWM模式1且向上计数,输出极性的变化必定是从高到低,即OCxRef是从有效电平到无效电平跳变。 其他组合方式自己算算。极性选择,若选择TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High,表明输出OCx与OCxRef同相,若为Low表明反向。 总输出极性=PWM模式选择 && PWM计数方式 && 极性选择。
      讲程序,TIM15 10s触发一次ADC有3种方法。1法:10s进入TIM中断,在中断中软件触发ADC。技术含量低,不采用,效率也低。2法:定时器配置为10s计时,ADC配置为ADC_ExternalTrigConv_T15_TRGO,TIM15的TRGO选择为 TIM_TRGOSource_Update(即计数溢出事件);3法:TIM15配置为PWM,周期10s,向上计数,PWM pulse值设定为1,ADC配置为ADC_ExternalTrigConv_T15_TRGO,TIM15的TRGO选择为TIM_TRGOSource_OC1。
     2法如下:
(1)GPIO设置
void GPIOConfig()
{   
  GPIO_InitTypeDef        GPIO_InitStructure;
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);//使能外设GPIO时钟
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_0 |GPIO_Pin_1;//ADC_CH1 ADC_CH2 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速率
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模式为模拟输入输出
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//上拉设置
  GPIO_Init(GPIOA,&GPIO_InitStructure);
}
(2)ADC配置
void ADCConfig()
{
  ADC_InitTypeDef        ADC_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
  
  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_239_5Cycles);
  ADC_GetCalibrationFactor(ADC1);        // 开始ADC校准 
  ADC_Cmd(ADC1,ENABLE);
  while(ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN)==RESET);   /* 等待ADC准备好 */
  
  ADC_DMACmd(ADC1,ENABLE);//使能DMA
  ADC_DMARequestModeConfig(ADC1,ADC_DMAMode_Circular);//DMA循环模式
}
(3)TIM15配置
void TIM15Config()
{  
  //(1)选择TIM15 Update事件作为触发源(计数器溢出)
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM15, ENABLE);
//配置基础
  TIM_DeInit(TIM15);
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  TIM_TimeBaseStructure.TIM_ClockDivision=0;//48M
  TIM_TimeBaseStructure.TIM_Prescaler=48000;//48k 1Tick=1ms
  TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
  TIM_TimeBaseStructure.TIM_Period=1000*10;//10s周期
  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);//使能TIM3
}
(4)DMA配置
void DMAConfig()
{
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE);//使能DMA时钟
  DMA_InitTypeDef        DMA_InitStructure;
  DMA_DeInit(DMA1_Channel1);
  DMA_InitStructure.DMA_PeripheralBaseAddr = (INT32U)&(ADC1->DR);//外设基地址 ADC1数据寄存器地址
  DMA_InitStructure.DMA_MemoryBaseAddr =(INT32U)ADCResult;//内存基地址:数组ADCResult地址
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//方向:外设为源地址 即外设-》内存
  DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE;//BUFFER_SIZE是宏定义,为2
  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_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  DMA_Init(DMA1_Channel1, &DMA_InitStructure);
  /* DMA1 Channel1 enable */
  DMA_Cmd(DMA1_Channel1, ENABLE);
}
(5)main函数
#define BUFFER_SIZE 2
INT16U ADCResult[BUFFER_SIZE];
INT16U ADC1ConvertedValue[BUFFER_SIZE];
void main()

  int i;
  GPIOConfig();
  ADCConfig();
  DMAConfig();
  TIM15Config();
  ADC_StartOfConversion(ADC1);
  //A conversion either starts immediately (software trigger configuration)or once a hardware trigger event 
  //  occurs (hardware trigger configuration).
  
  while (1)
  {
    while((DMA_GetFlagStatus(DMA1_FLAG_TC1)) == RESET ); 
    DMA_ClearFlag(DMA1_FLAG_TC1);
    for(i=0;i<BUFFER_SIZE;i++)
    {
      ADC1ConvertedValue=ADCResult*3000/0x0fff;
    }
    asm("nop");  
  } 
}
ADC_StartOfConversion(ADC1)必须加入,看看注释就知道以及本帖图一ADC结构图就知道。
#################################################################
3法程序如下:
只有TIM15配置不同,多了PWM配置。
void TIM15Config()
{  
   //(2)选择T15 TIM_TRGOSource_OC1 作为触发
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM15, ENABLE);
  
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  TIM_OCInitTypeDef       TIM_OCInitStructure;
    
  TIM_DeInit(TIM15);
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_OCStructInit(&TIM_OCInitStructure);  
  // Time base configuration /
  TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;  //48M
  TIM_TimeBaseStructure.TIM_Prescaler = 48000; //48k 1Tick=1ms 
  TIM_TimeBaseStructure.TIM_Period = 1000*10;//周期10s
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数 
  TIM_TimeBaseInit(TIM15, &TIM_TimeBaseStructure);
  TIM_SelectOutputTrigger(TIM15,TIM_TRGOSource_OC1);//TIM15的OC1事件作为外部TRGO
  TIM_ClearFlag(TIM15,TIM_FLAG_CC1);
  // Output Compare PWM Mode configuration 
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 
  //PWM模式1- 在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平,否则为无效电平;
  //PWM模式2- 在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道2为无效电平,否则为有效电平;
  
  TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//OC与OCRef同相
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;           
  TIM_OCInitStructure.TIM_Pulse = 0x01;
  TIM_OC1Init(TIM15, &TIM_OCInitStructure);
  //TIM1 enable counter //
  TIM_Cmd(TIM15, ENABLE);
  //Main Output Enable //
  TIM_CtrlPWMOutputs(TIM15, ENABLE);
}
#########################################################
     如果选择TIM1_CC4触发ADC,TIM配置中
TIM_SelectOutputTrigger函数不必有(也不应该有,第二个参数没合适的)。。。官网例程中TIM就有CC4触发的例子
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值