F103RC 单通道ADC DMA数据采集时序错乱。

2019-08-17 06:57发布

用的原子哥F103RC。
外部信号下降沿触发单通道ADC 1MHz(系统主频54MHz)连续采样,目前设置为采样4500个点,大约是5ms完成,中间的等待时间由定时器来决定。采样的同时将数据通过DMA传输到指定内存,等采样完后进行计算。
目前信号由信号发生器给定。如下图的信号发生器波形,触发的方波和正弦波频率都是42.55Hz。每个下降沿到上升沿间的正选波信号为固定采样信号。


功能都能实现,现在问题Debug中看到的数据每次都采样的都是正弦波不同的位置,而不是我下降沿触发的指定采集位置,而且每次都是不同位置,也就是采集到的相位在变化。实在想不明白问题在哪?求各路大神指教。


部分重要代码如下:
extern TIM_HandleTypeDef TIM2InitStructure;                                        //定时器初始化结构体,在Timer.c文件中定义
extern ADC_HandleTypeDef PB1_ADCStructure;                                        //ADC初始化结构体,在ADC.c文件中定义
extern DMA_HandleTypeDef ADCxDMAChannel;                                        //DMA初始化结构体,在DMA.c文件中定义


//外部中断设置为PB0端口
void EXTI_Init(void)
{
        GPIO_InitTypeDef EXTI_GPIOStructure;
       
        __HAL_RCC_GPIOB_CLK_ENABLE();                                       //开启GPIOB时钟
        EXTI_GPIOStructure.Mode = GPIO_MODE_IT_FALLING;                //下降沿触发
        EXTI_GPIOStructure.Pin = GPIO_PIN_0;
        EXTI_GPIOStructure.Pull = GPIO_PULLUP;                                //内部上拉
       
        HAL_GPIO_Init(GPIOB,&EXTI_GPIOStructure);
       
       
        //中断线0-PB0
        HAL_NVIC_SetPriority(EXTI0_IRQn,2,3);                                        //抢占优先级为2,响应优先级为3
        HAL_NVIC_EnableIRQ(EXTI0_IRQn);                                        //使能中断线0
}


//中断服务函数
void EXTI0_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);                                        //调用中断处理公用函数,由此函数调用中断回调函数
}


//中断服务程序中需要做的事情
//在HAL库中所有的外部中断服务函数都会调用此函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)                                //GPIO_Pin:中断引脚号
{
    switch(GPIO_Pin)
    {
        case GPIO_PIN_0:
                        ADCFunction(279);
                break;


    }
}



void ADCFunction(u16 TimerValue)
{
       
        StateBit = true;
        HAL_ADC_Start(&PB1_ADCStructure);                                                        //开启ADC
        Delay_us(10);
        __HAL_DMA_ENABLE(&ADCxDMAChannel);
//        __HAL_DMA_ENABLE_IT(&ADCxDMAChannel, DMA_IT_TC);
        //(u32)DMAPartA为存储地址,由我们自行定义,4500为读取位数
        HAL_ADC_Start_DMA(&PB1_ADCStructure,(u32*)&DMACache,4500);
       
        __HAL_TIM_ENABLE_IT(&TIM2InitStructure,TIM_IT_UPDATE);
        __HAL_TIM_ENABLE(&TIM2InitStructure);

        do
        {
                Delay_us(1);
        }
        while(StateBit == true);
        HAL_ADC_Stop(&PB1_ADCStructure);                                                        //关闭ADC
        __HAL_TIM_DISABLE(&TIM2InitStructure);                                                //关闭定时器2,到需要时开启
        __HAL_TIM_DISABLE_IT(&TIM2InitStructure,TIM_IT_UPDATE);                        //关闭更新中断,到需要时再开启
        TIM2->CNT = TimerValue;                                                                        //重装载计数寄存器
        __HAL_DMA_DISABLE(&ADCxDMAChannel);
}

定时器我设置为7000ms
定时器部分代码:
//定时器时钟来源是APB1的时钟,我设置的APB1时钟为SYSCLK的4分频,为14MHz,当APB1分频系数不为1时,TIMxCLK的频率为APB1的2倍,即28MHz
//定时器定时时间计算time = (Prescaler + 1) * (Period + 1) / TIMxCLK,例如1s = (13999+1)*(1999+1)/28MHz
//目前需求定时时间为7000us,即28MHz*0.007s = 196000计时周期------》TimerValue = 979; SelfDefCLKDivision = 199
void TIM2Init(u16 TimerValue, u16 SelfDefCLKDivision)
{
        TIM2InitStructure.Instance = TIM2;
        TIM2InitStructure.Init.Prescaler = SelfDefCLKDivision;                                //可自行设置的分频系数,此数值在0到255之间
        TIM2InitStructure.Init.CounterMode = TIM_COUNTERMODE_UP;                //向上计数器
        TIM2InitStructure.Init.Period = TimerValue;                                        //自动重装载值
        TIM2InitStructure.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;        //时钟分频系数,系数为1
       
        HAL_TIM_Base_Init(&TIM2InitStructure);                                                //定时器初始化
        __HAL_TIM_CLEAR_IT(&TIM2InitStructure,TIM_IT_UPDATE);                //清除定时器标志位,屏蔽因系统复位而导致的意外进入中断
        HAL_TIM_Base_Start_IT(&TIM2InitStructure);                                         //使能定时器2和定时器2更新中断:TIM_IT_UPDATE
       
        __HAL_TIM_DISABLE(&TIM2InitStructure);                                        //关闭定时器2,到需要时开启
        __HAL_TIM_DISABLE_IT(&TIM2InitStructure,TIM_IT_UPDATE);                //关闭更新中断,到需要时再开启
        TIM2->CNT = TimerValue;                                                                //重装载计数寄存器
}

//定时器底层驱动,开启时钟,设置中断优先级
//此函数会被HAL_TIM_Base_Init()函数调用,用来控制所有的定时器初始化
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM2)
        {
                __HAL_RCC_TIM2_CLK_ENABLE();                                                        //使能TIM2时钟
                HAL_NVIC_SetPriority(TIM2_IRQn,1,1);                                                //设置中断优先级,抢占优先级1,响应优先级1
                HAL_NVIC_EnableIRQ(TIM2_IRQn);                                                //开启ITM2中断   
        }  
}




友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。