打印
[STM32F4]

STM32F407的ADC+TIM+DMA采样

[复制链接]
1534|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
前线指挥官|  楼主 | 2017-8-24 20:18 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
不知道哪里出问题了,初衷是用TIM3每500ms触发一次ADC1的通道5采样外部电压,再通过DMA传数据到内存,但是我调试时发现   ADC1的数据寄存器只更新的一次,就卡在while(1)里面了。
  //adc.h

  #ifndef __ADC__
  #define __ADC__
  #include "sys.h"

  void gpioled_config(void);
  void gpio_config(void);
  void adc_config(void);
  void tim_config(void);
  void dma_config(void);

#endif
*********************************************************************************************************

  //adc.c

  #include "stm32f4xx_conf.h"
  #include "sys.h"
  #include "stm32f4xx_spi.h"
  #include "delay.h"
  #include "stm32f4xx_adc.h"
  #include "stm32f4xx_dma.h"
  #include "stm32f4xx_dma2d.h"
  #include "adc.h"


  void gpioled_config(void)
  {
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);

    GPIO_InitTypeDef  GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOF, &GPIO_InitStructure);
  }

    void gpio_config(void)
    {
      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

      GPIO_InitTypeDef  GPIO_InitStructure;
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
      GPIO_Init(GPIOA, &GPIO_InitStructure);
    }

  void adc_config(void)
  {
             RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);

ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //是否提高采样率
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; //ADC独立模式
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4; //配置成21M,保证ADC不超过36M
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; //采样通道之间的间隔
ADC_CommonInit(&ADC_CommonInitStructure);

ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  //ADC单次模式
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  //数据右对齐
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO;  //TIM3外部触发
ADC_InitStructure.ADC_ExternalTrigConvEdge =ADC_ExternalTrigConvEdge_Rising;  //上升沿触发
ADC_InitStructure.ADC_NbrOfConversion = 1; //一个转换序列
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;  //采样精度为12位
ADC_InitStructure.ADC_ScanConvMode = DISABLE;  //扫描模式禁止
ADC_Init(ADC1,&ADC_InitStructure);

ADC_RegularChannelConfig(ADC1,ADC_Channel_5,1,ADC_SampleTime_480Cycles); //配置ADC转换通道

ADC_Cmd(ADC1,ENABLE); //使能ADC
ADC_DMACmd(ADC1,ENABLE); //使能ADC的DMA
}

void tim_config(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV4;  //定时器时钟168M/4*2 = 84M
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInitStructure.TIM_Period = 4999;  // 重载数
TIM_TimeBaseInitStructure.TIM_Prescaler = 8399;   //分频系数
//        TIM_TimeBaseInitStructure.TIM_RepetitionCounter   高级定时器才用到,不管
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);

TIM_ARRPreloadConfig(TIM3,ENABLE);

TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_Update); //定时器触发输出

TIM_Cmd(TIM3,ENABLE); // 使能定时器
}

void dma_config(void)
{
u16 adcbuffer[24];
  u16 *a = adcbuffer;

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);

DMA_DeInit(DMA1_Stream4);

DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_BufferSize = 128;
DMA_InitStructure.DMA_Channel= DMA_Channel_5;//DMA通道5
DMA_InitStructure.DMA_DIR= DMA_DIR_PeripheralToMemory;//传输方向为外设到内存
DMA_InitStructure.DMA_FIFOMode= DMA_FIFOMode_Disable;//DMA的FIFO模式禁止
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_Memory0BaseAddr = ((uint16_t)&adcbuffer); //内存地址
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //半字传输
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址递增
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  //DMA循环模式开启
DMA_InitStructure.DMA_PeripheralBaseAddr = ((uint32_t)&(ADC1->DR)); //外设地址
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//半字传输
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址递增
DMA_InitStructure.DMA_Priority = DMA_Priority_High;//DMA优先级高
DMA_Init(DMA1_Stream4, &DMA_InitStructure);

DMA_Cmd(DMA1_Stream4,ENABLE);
}

*******************************************************************************************************************

//mian.c

#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"
#include "adc.h"


int main(void)
{
uart_init(115200);
delay_init(168);
gpioled_config();
PFout(9) = 0;
PFout(10) = 0;
  gpio_config();
  adc_config();
dma_config();
  tim_config();

while(1)
{
   PFout(9) = 1;
   PFout(10) = 1;
   delay_ms(100);
PFout(9) = 0;
PFout(10) = 0;
   delay_ms(100);
}
}

**************************************************************************************************
以上就是我的程序了,是哪里没配,还是哪里没配对,请大家多多指教!!!
沙发
feelhyq| | 2017-8-24 21:57 | 只看该作者
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  //ADC单次模式
这个改成连续模式 即ENABLE

使用特权

评论回复
板凳
队长shiwo| | 2017-8-25 09:26 | 只看该作者
按楼上所说

使用特权

评论回复
地板
前线指挥官|  楼主 | 2017-8-25 09:48 | 只看该作者
我是过了哦,还是不行。

ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  //ADC单次模式
这个改成连续模式 即ENABLE

还有,这样改后,那TIM定时触发还有意义吗?请各位解惑也,谢谢

使用特权

评论回复
5
feelhyq| | 2017-8-25 11:30 | 只看该作者
前线指挥官 发表于 2017-8-25 09:48
我是过了哦,还是不行。

ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  //ADC单次模式

DMA 还是应该跟ADC一起用  timer仅仅只是个触发ADC转换而已,timer +DMA这个用法有问题 ,应该是ADC+DMA

使用特权

评论回复
6
前线指挥官|  楼主 | 2017-8-25 13:55 | 只看该作者
      现在有2个想法在我脑子了,有点困惑哦。
     1.我这样写程序的初衷是为了靠TIM控制ADC采样,但不是用TIM的中断。例如我要一个周波内(20ms)采20个点,那配成每1.05ms,定时器计数溢出,触发一次单次ADC采样,从而达到目的。
    2. 如果ADC采样配成连续模式,TIM触发一次后ADC自己就一直在转换,采样的时间间隔 = ADC转换通道的转换时间+ADC通道之间的间隔,其实这个时间很快的,也达不到我要的目的。
   是不是要达到我这种目的不是这样配的。

使用特权

评论回复
7
feelhyq| | 2017-8-25 15:11 | 只看该作者
前线指挥官 发表于 2017-8-25 13:55
现在有2个想法在我脑子了,有点困惑哦。
     1.我这样写程序的初衷是为了靠TIM控制ADC采样,但不是 ...

针对第二个问题, “”如果ADC采样配成连续模式,TIM触发一次后ADC自己就一直在转换” 我个人不觉得ADC自己一直在转换,你是否验证过这个问题,我更倾向于,定时器每溢出一次,ADC就转换一次。与其在这里猜测还不如撸起袖子干,去试验一下

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

3

帖子

0

粉丝