Thông báo

Collapse
No announcement yet.

Lập trình ARM STM32F103x8 để thu tín hiệu ADC 25kHz

Collapse
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • Lập trình ARM STM32F103x8 để thu tín hiệu ADC 25kHz

    Chào cả nhà,
    Em đang lập trình con ARM STM32F103x8 dùng ADC để đọc tín hiệu khoảng 25kHz. Em có đính kèm hình tín hiệu đo bằng oscilloscope. Em lập trình và check thử giá trị đọc được gửi lên máy tính thì kết quả không như mong muốn. Các anh chị xem thử chỉ cho em với. Em cám ơn nhiều ạ!

    https://www.dropbox.com/s/brj55cr4rv...61854.jpg?dl=0
    Code:
    #include "application.h"
    #define ADC1_DR_Address ((uint32_t) 0x4001244c)
    uint16_t ADC_ConvertedValue;
    int myArray[1024];
    int lastTime = 0;
    void setup()
    {
        //Spark.disconnect();
        //WiFi.off();
        
        GPIO_InitTypeDef GPIO_InitStructure;
        DMA_InitTypeDef DMA_InitStructure;
        ADC_InitTypeDef ADC_InitStructure;
        Serial.begin(9600);
        
        //enable ADC1 clock
        RCC_ADCCLKConfig(RCC_PCLK2_Div6);
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        
        DMA_DeInit(DMA1_Channel1);
        DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) &ADC_ConvertedValue;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
        DMA_InitStructure.DMA_BufferSize = 1;
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        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);
        DMA_Cmd(DMA1_Channel1, ENABLE);
        
        //ADC1 configuration
        //select independent conversion mode (single)
        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
        //We will convert single channel only
        ADC_InitStructure.ADC_ScanConvMode = DISABLE;
        //We will convert one time
        ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
        //Select no external triggering
        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
        //Right 12-bit data alignment in ADC data register
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
        //Single channel conversion
        ADC_InitStructure.ADC_NbrOfChannel = 1;
        //Load structure values to control and status registers
        ADC_Init(ADC1, &ADC_InitStructure);
        
        ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_1Cycles5);
        ADC_DMACmd(ADC1, ENABLE);
        //Enable ADC1
        ADC_Cmd(ADC1, ENABLE);
        //Enable ADC1 reset calibration register
        ADC_ResetCalibration(ADC1);
        //Check the end of ADC1 reset calibration register
        while (ADC_GetResetCalibrationStatus(ADC1));
        //Start ADC1 calibration
        ADC_StartCalibration(ADC1);
        //Check the end of ADC1 calibration
        while (ADC_GetCalibrationStatus(ADC1));
        ADC_SoftwareStartConvCmd(ADC1, ENABLE);
        while (!Serial.available());
    }
    void loop()
    {
        for (int i=0; i<1024; i++)
        {
           ADC_SoftwareStartConvCmd(ADC1, ENABLE);
           while (!DMA_GetFlagStatus(DMA1_FLAG_TC1));
           DMA_ClearFlag(DMA1_FLAG_TC1); 
           myArray[i]=ADC_ConvertedValue;
        }
       // long start = micros();
        if(millis() - lastTime > 1024)
        {
            for (int i=0; i<1024; i++)
            {
                Serial.println(myArray[i]);
            }
            lastTime = millis();
        }
        
       // long end = micros();
        //Serial.println(ADC_ConvertedValue);
        //Serial.print(" micros ");
        //Serial.println(end - start);
        //delay(1000);
    }

  • #2
    Nguyên văn bởi smith2679 Xem bài viết
    Chào cả nhà,
    Em đang lập trình con ARM STM32F103x8 dùng ADC để đọc tín hiệu khoảng 25kHz. Em có đính kèm hình tín hiệu đo bằng oscilloscope. Em lập trình và check thử giá trị đọc được gửi lên máy tính thì kết quả không như mong muốn. Các anh chị xem thử chỉ cho em với. Em cám ơn nhiều ạ!

    https://www.dropbox.com/s/brj55cr4rv...61854.jpg?dl=0
    Code:
    #include "application.h"
    #define ADC1_DR_Address ((uint32_t) 0x4001244c)
    uint16_t ADC_ConvertedValue;
    int myArray[1024];
    int lastTime = 0;
    void setup()
    {
        //Spark.disconnect();
        //WiFi.off();
        
        GPIO_InitTypeDef GPIO_InitStructure;
        DMA_InitTypeDef DMA_InitStructure;
        ADC_InitTypeDef ADC_InitStructure;
        Serial.begin(9600);
        
        //enable ADC1 clock
        RCC_ADCCLKConfig(RCC_PCLK2_Div6);
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        
        DMA_DeInit(DMA1_Channel1);
        DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) &ADC_ConvertedValue;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
        DMA_InitStructure.DMA_BufferSize = 1;
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        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);
        DMA_Cmd(DMA1_Channel1, ENABLE);
        
        //ADC1 configuration
        //select independent conversion mode (single)
        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
        //We will convert single channel only
        ADC_InitStructure.ADC_ScanConvMode = DISABLE;
        //We will convert one time
        ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
        //Select no external triggering
        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
        //Right 12-bit data alignment in ADC data register
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
        //Single channel conversion
        ADC_InitStructure.ADC_NbrOfChannel = 1;
        //Load structure values to control and status registers
        ADC_Init(ADC1, &ADC_InitStructure);
        
        ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_1Cycles5);
        ADC_DMACmd(ADC1, ENABLE);
        //Enable ADC1
        ADC_Cmd(ADC1, ENABLE);
        //Enable ADC1 reset calibration register
        ADC_ResetCalibration(ADC1);
        //Check the end of ADC1 reset calibration register
        while (ADC_GetResetCalibrationStatus(ADC1));
        //Start ADC1 calibration
        ADC_StartCalibration(ADC1);
        //Check the end of ADC1 calibration
        while (ADC_GetCalibrationStatus(ADC1));
        ADC_SoftwareStartConvCmd(ADC1, ENABLE);
        while (!Serial.available());
    }
    void loop()
    {
        for (int i=0; i<1024; i++)
        {
           ADC_SoftwareStartConvCmd(ADC1, ENABLE);
           while (!DMA_GetFlagStatus(DMA1_FLAG_TC1));
           DMA_ClearFlag(DMA1_FLAG_TC1); 
           myArray[i]=ADC_ConvertedValue;
        }
       // long start = micros();
        if(millis() - lastTime > 1024)
        {
            for (int i=0; i<1024; i++)
            {
                Serial.println(myArray[i]);
            }
            lastTime = millis();
        }
        
       // long end = micros();
        //Serial.println(ADC_ConvertedValue);
        //Serial.print(" micros ");
        //Serial.println(end - start);
        //delay(1000);
    }
    Mình thấy tín hiệu adc ở đầu vào của bạn có vẻ hơi lớn , chân adc của stm32 chỉ đọc đc Vmax <= Vcc(3.3v), nếu lớn hơn sẽ dẫn đến bão hòa (trong hình mình thấy tín hiệu adc phải lớn hơn đến 3 lần chân stm32), khi phục hồi lại thì ra giống xung vuông chứ ko thấy đc biên độ. Mình nghĩ bạn lên giảm tín hiệu adc đầu vào trong giải <= 3V là đẹp nhất.
    (^_^) hoangnv.3i@gmail.com

    Comment


    • #3
      Thanks bạn! Thật ra nếu bạn check góc phải phía dưới của oscilloscope là mình đang dùng thang đo 500mV unit để zoom to ra cho dễ nhìn maximum tín hiệu là ~3V, trung bình là ~2.0V. Mình collect số liệu rồi vẽ thử bằng excel cho ra đồ thị không giống với tín hiệu giống như là ADC setup không đủ nhanh hoặc một lý do nào đó ~~

      Comment


      • #4
        Tốc độ lấy mẫu của ADC thấp .Bạn tăng tốc độ lấy mẫu lên giá trị Max xem.

        Comment


        • #5
          Bạn Post kết quả đo được + chỉnh OSC của bạn về 25uS chú ý phần đầu nhọn
          Các bạn trên diển đàn có hướng giúp cho.
          mình gởi bạn kết quả đo xung vuông ,do tần số lấy mẫu thấp nên các xung hẹp có dạng tam giác.
          Attached Files

          Comment

          Về tác giả

          Collapse

          smith2679 Tìm hiểu thêm về smith2679

          Bài viết mới nhất

          Collapse

          Đang tải...
          X