你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

ADC的連續轉換雜訊問題

[复制链接]
小豚豚 提问时间:2017-10-3 17:24 /
使用的晶片為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[ARRAYSIZE];
volatile uint8_t bufferIndex;
int32_t a=0;

__IO extern int16_t adcInt_O[800][2];
__IO extern int16_t adcInt_S[800][2];
__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[a]=adcInt_O[a][(bufferIndex-1) & 0x1];
                                        adcInt_Buffer_S[a]=adcInt_S[a][(bufferIndex-1) & 0x1];
                                }

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

/* 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[ARRAYSIZE];
__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[storetime][bufferIndex] = ADC_values[myindex];
                                        adcInt_S[storetime][bufferIndex] = ADC_values[myindex+1];
                                        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筆資料)


第二輪資料轉換


N輪轉換


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



2017-10-03_171747.jpg
2017-10-03_172033.jpg
2017-10-03_172207.jpg
收藏 评论8 发布时间:2017-10-3 17:24

举报

8个回答
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通道尽量采样多次后一次性处理数据呢?

评分

参与人数 1ST金币 +2 收起 理由
zero99 + 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

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

点评

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

评分

参与人数 1ST金币 +2 收起 理由
zero99 + 2

查看全部评分

小豚豚 回答时间: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陣列>輸出資料(因此輸出的資料也跟著不正確)

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版