小豚豚 发表于 2017-10-3 17:24:47

ADC的連續轉換雜訊問題

使用的晶片為STM32L152
編寫程式內容大略為:


ADC轉換→ADC_DR暫存→藉由DMA搬運到自訂的陣列中 →經由USART在PC端印出
(其中ADC藉由TIM3外部觸發,每儲存N筆轉換後進入DMA中斷並匯入資料)


附上程式碼
main.c

/* Includes ------------------------------------------------------------------*/
#include "stm32l1xx.h"
#include <stdio.h>

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define ADC1_DR_ADDRESS    ((uint32_t)0x40012458)

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
volatile uint16_t ADC_values;
volatile uint8_t bufferIndex;
int32_t a=0;

__IO extern int16_t adcInt_O;
__IO extern int16_t adcInt_S;
__IO extern int16_t storetime;
__IO extern int8_t Flag;

int16_t adcInt_Buffer_O[800];
int16_t adcInt_Buffer_S[;

/* Private function prototypes -----------------------------------------------*/
void ADC_Configuration(void);
void DMA_Configuration(void);
void USART_Configuration(void);
void RCC_Configuration(void);
void NVIC_Configuration(void);
void TIM3_Configuration(void);

int main(void)
{
        Flag =0;

      RCC_Configuration();
        TIM3_Configuration();
        ADC_Configuration();
        DMA_Configuration();
        USART_Configuration();
       

       
        while(1)
        {

                        if(Flag ==1) /*匯入資料*/
                        {               
                                Flag = 0;
                                for(a=0; a<800; a++ ) /*怕資料被覆蓋*/
                                {
                                        adcInt_Buffer_O=adcInt_O[(bufferIndex-1) & 0x1];
                                        adcInt_Buffer_S=adcInt_S[(bufferIndex-1) & 0x1];
                                }

                                for(a=0 ; a<800 ; a++)
                                {                                                       
                                                printf("%d\r\n", adcInt_Buffer_O);
                                }
                        }                       
        }
       
}

/* ADC1 channel18 configuration using DMA1 channel1 */
void ADC_Configuration(void)
{
   /*----------------- ADC1 configuration with DMA enabled --------------------*/
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
/* Enable ADC1 clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);

/* Configure PB.12 (ADC Channel18) in analog mode */
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
       
/* Configure PB.13 (ADC Channel19) in analog mode */
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
       
/* ADC1 configuration */
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;                                                                                        
ADC_InitStructure.ADC_ScanConvMode = ENABLE;                                                                                                                        
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                                                
ADC_InitStructure.ADC_ExternalTrigConvEdge=ADC_ExternalTrigConvEdge_Rising;
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_T3_CC1;                                
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                                                                                        
ADC_InitStructure.ADC_NbrOfConversion = 2;        /*雙通道採集*/                                                                                                                               
ADC_Init(ADC1, &ADC_InitStructure);
       
/* ADC1 regular channel18 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_18, 1, ADC_SampleTime_384Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_19, 2, ADC_SampleTime_384Cycles);

/* Enable the request after last transfer for DMA Circular mode */
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
       
/* Enable ADC1 DMA */
ADC_DMACmd(ADC1, ENABLE);
}

void DMA_Configuration(void)
{
          /*------------------------ DMA1 configuration ------------------------------*/
        DMA_InitTypeDef DMA_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
        /* Enable DMA1 clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

        /* DMA1 channel1 configuration */
      DMA_DeInit(DMA1_Channel1);
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
      DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
        DMA_InitStructure.DMA_BufferSize = ARRAYSIZE;
      DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_ADDRESS;
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_values;
      DMA_Init(DMA1_Channel1, &DMA_InitStructure);
      DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
      /* Enable DMA1 channel1 */
      DMA_Cmd(DMA1_Channel1, ENABLE);
       
        /*Enable DMA1 channel IRQ Channel */
        NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
}

void USART_Configuration(void)
{
    USART_InitTypeDef USART_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate = 115200;                        
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;        
    USART_InitStructure.USART_StopBits = USART_StopBits_1;                
    USART_InitStructure.USART_Parity = USART_Parity_No;                        
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_RTS;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                
    USART_Init(USART2, &USART_InitStructure);                                                                                                                                        
    USART_Cmd(USART2, ENABLE);               
}

void RCC_Configuration(void)
{   
/* Enable HSI Clock */
RCC_HSICmd(ENABLE);
/*!< Wait till HSI is ready */
while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);
/* Set HSI as sys clock*/
RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);
/* Set MSI clock range to ~4.194MHz*/
RCC_MSIRangeConfig(RCC_MSIRange_6);
/* Enable the GPIOs clocks */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOC| RCC_AHBPeriph_GPIOD| RCC_AHBPeriph_GPIOE| RCC_AHBPeriph_GPIOH, ENABLE);   
/* Enable comparator, LCD and PWR mngt clocks */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_COMP | RCC_APB1Periph_LCD | RCC_APB1Periph_PWR,ENABLE);
/* Enable ADC & SYSCFG clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_SYSCFG , ENABLE);
/* Allow access to the RTC */
PWR_RTCAccessCmd(ENABLE);
/* Reset RTC Backup Domain */
RCC_RTCResetCmd(ENABLE);
RCC_RTCResetCmd(DISABLE);
/* LSE Enable */
RCC_LSEConfig(RCC_LSE_ON);
/* Wait until LSE is ready */
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
/* RTC Clock Source Selection */
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
/* Enable the RTC */
RCC_RTCCLKCmd(ENABLE);   
/*Disable HSE*/
RCC_HSEConfig(RCC_HSE_OFF);
if(RCC_GetFlagStatus(RCC_FLAG_HSERDY) != RESET )
{
    /* Stay in infinite loop if HSE is not disabled*/
    while(1);
        }

}

void TIM3_Configuration(void)
{   
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;   
        TIM_OCInitTypeDef TIM_OCInitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;
       
        /*PWM Output pin (PC6) for Timer 3, Channel 1 */
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;   
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;       
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
        GPIO_Init(GPIOC, &GPIO_InitStructure);
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_TIM3);
       
        //#define SAMPLESPERSEC        4096
        //#define PRESCALER                        SystemCoreClock / 1600000                                               
        //#define PERIOD                                1600000 / SAMPLESPERSEC               
               
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 , ENABLE);

/* Time base configuration */
       
/*((1 + TIM Prescaler)/16M)*(1 + TIM Period)*/
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 2000000) - 1;
TIM_TimeBaseStructure.TIM_Period = 1000 - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
       
/* TIM PWM1 Mode configuration */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 5;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM3, &TIM_OCInitStructure);


        TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);       
        TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_OC1);
        TIM_ARRPreloadConfig(TIM3, ENABLE);
        TIM_Cmd(TIM3, ENABLE);
}

   int fputc(int ch, FILE *f)
   {
      USART_SendData(USART2, (unsigned char) ch);
      while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET)
                        {
                        }
      return ch;
   }


stm32l1xx_it.c

extern volatile uint8_t bufferIndex;

int Flag;
extern int16_t a;

extern volatile uint16_t ADC_values;
__IO int16_t adcInt_O[1000][2];
__IO int16_t adcInt_S[1000][2];
__IO int16_t storetime;
__IO int16_t myindex=0;


void DMA1_Channel1_IRQHandler(void)                                          
{
                if(DMA_GetITStatus(DMA1_IT_TC1)==SET)
                {
                                DMA_ClearITPendingBit(DMA1_IT_TC1);
                                for(myindex=0 ; myindex<1600; myindex+=2)
                                {
                                        adcInt_O = ADC_values;
                                        adcInt_S = ADC_values;
                                        storetime++;
                               
                                        if (storetime == 800)
                                        {
                                        storetime=0;
                                        bufferIndex = (bufferIndex+1) & 0x1;
                                        Flag = 1;
                                        }
                                }
                }

}





已以上程式為例
每1ms進行一次ADC轉換,每次轉換輪尋2個通道並經由DMA存入陣列,故800ms後陣列存入1600筆資料並進入DMA中斷
DMA中斷程式中將資料存入緩衝陣列(怕被覆蓋),全部存完後設置旗標(Flag=1)
Main函示判斷(Flag)旗標為貞開始進行Printf動作

實驗結果
第一輪資料轉換(只抓一個通道來觀察,故為800筆資料)
https://www.stmcu.org.cn/module/forum/forum.php?mod=image&aid=400827&size=300x300&key=7a16112e5e6286f2&nocache=yes&type=fixnone

第二輪資料轉換
https://www.stmcu.org.cn/module/forum/forum.php?mod=image&aid=400828&size=300x300&key=ff722c8be62524b8&nocache=yes&type=fixnone

N輪轉換
https://www.stmcu.org.cn/module/forum/forum.php?mod=image&aid=400829&size=300x300&key=0cf126db0f60f2c5&nocache=yes&type=fixnone

看起來是前段的資料被覆蓋了,但實際運算個城市的執行時間後卻又是足夠的
目前僅發現更改包率可以減少出問題的資料數



MrJiu 发表于 2017-10-5 10:15:59

台湾人?还有现在ST这种外设配置,请使用Cube。。。妥妥的。。。

MrJiu 发表于 2017-10-5 10:16:04

台湾人?还有现在ST这种外设配置,请使用Cube。。。妥妥的。。。

wenyangzeng 发表于 2017-10-5 13:26:21

本帖最后由 wenyangzeng 于 2017-10-5 17:45 编辑

STM32L152主频只有30MHZ,楼主的ADC采样周期又设置达384Cycles之长。加之需要进行串口通信,可能超时了。降低ADC采样个数试看看吧!还有DMA只收集2次ADC数据很不划算,为何不对2通道尽量采样多次后一次性处理数据呢?

小豚豚 发表于 2017-10-17 15:59:03

wenyangzeng 发表于 2017-10-5 13:26
STM32L152主频只有30MHZ,楼主的ADC采样周期又设置达384Cycles之长。加之需要进行串口通信,可能超时了。降 ...

你好!
我的程式

DMA_InitStructure.DMA_BufferSize = ARRAYSIZE;//ARRAYSIZE = 1600

此程式在雙通道採集到1600筆資料後才進DMA中斷處理資料

樓主的对2通道尽量采样多次是這個意思嗎?

wenyangzeng 发表于 2017-10-17 21:49:19

小豚豚 发表于 2017-10-17 15:59
你好!
我的程式



是的,如果RAM足够,DMA应该一次足够多数据后才传送到串口。

kylongmu 发表于 2017-10-18 00:10:16

HSI Clock这就决定了你的ADC有很高的相位噪声。
至于数据堆在一起,明显是你的绘图软件的问题,把前后数据画了堆在一起。

小豚豚 发表于 2017-10-18 09:39:44

kylongmu 发表于 2017-10-18 00:10
HSI Clock这就决定了你的ADC有很高的相位噪声。
至于数据堆在一起,明显是你的绘图软件的问题,把前后数据 ...

數據的產生方式為使用Putty將資料輸出到excel程式中並繪圖

數據異常的點發生在:
第一次ADC採集1600筆資料>經DMA>儲存至自己的Buffer陣列>輸出資料 (第一資料皆正常)
第二次ADC採集1600筆資料(感覺第二次的ADC轉換資料前幾筆會有附蓋問題)>經DMA>儲存至自己的Buffer陣列>輸出資料(因此輸出的資料也跟著不正確)
页: [1]
查看完整版本: ADC的連續轉換雜訊問題