ADC อ่านค่าไม่ตรงครับ STM32F107 รบกวนผู้รู้ช่วยทีครับ

Started by Jimmkung, March 02, 2013, 02:15:33 AM

Previous topic - Next topic

Jimmkung

ผมอยากทราบอาการที่ทำไม ADC ถึงอ่านค่าเพี้ยนครับ โดยที่ผมจับที่ 0v ก็อ่านได้ 0 และที่ 3.3v ก็อ่านได้ 4095 แต่แทนที่1.5v จะอ่านได้ ประมาณ 2095 แต่กลับอ่านออกมาได้ถึง 3805 ครับ ผมแปลกใจมาก setting ADC ใหม่ก็ไม่หาย ผมใช้ ride7 ครับ
ปล. ผมเอามิเตอร์จับที่ขา adcแล้ว ก็ประมานแค่ 0.2v ผมคิดว่าปัญหาน่าจะอยู่ที่การ init ADC มากกว่าครับ ถ้าผมเข้าใจผิดอย่างไรรบกวนผู้รู้ช่วยแนะนำด้วยน่ะครับ :'(

tha

น่าจะใช่ การ set sampling time ก็อาจจะมีผลด้วยบ้างเป็นบางกรณี สรุปแล้วยังไม่รู้สาเหตที่แน่นอน ข้อมูลน้อยไปหน่อย

deejun

มีโค๊ดตัวอย่างมั๊ยครับที่เขียน  เผือมีอะไรที่ไม่ถูกต้องได้มีหลายท่านช่วยดู
สิ่งที่สงสัยคือ
1 0V  อ่านค่าได้ถูก  ค่าคือ 0 และ  3.3V อ่านได้ถูก 4095     เคยลองเอามิเตอร์จับดูหรือไม่ว่าโวลต์ได้จริง
2 ที่ประมาณว่า  1.5V  จะต้องได้ค่า    1861 ครับ  และลองวัดโวลต์ว่าได้ 1.5vหรือไม่
3 VR มีแบบค่าเอ็กโปร และแบบลีเนีย  การหมุนรอบองศาเท่ากัน  แต่ค่าไม่เท่ากัน  ยกเว้นช่วงสูงสุด และต่ำสูด เท่ากัน


activefilter

ค่า 3.3 V ที่ ป้อน ให้มัน น่า จะเลย Full Scale ไปแล้ว ค่า ที่เลย  Full Scale จะอ่าน ได้ 4095 ตลอด

ที่ถูก ต้อง เรา จะต้อง  ค่อยๆปรับ แรงดัน ขึ้น พร้อมแสดงผลขณะปรับ พอได้ค่า 4094 ก็หยุดได้แล้ว ถ้าเพิ่มแรงดัน เราอาจ หมุนเกิน 4095 จะ ทำให้เราคำนวณผิด

แต่กรณีนี้ FULL SCALE น่าจะอยู่ ที่ แค่ 2.0 ไม่ใช่ 3.3 
 
   คำนวณจาก       1.5*(4096/3805)=  1.99


Jimmkung

อันนี้เป็น code ที่ผมเขียนแล้วแสดงค่าทาง UART ครับ
จนปัญญาแล้ว เสียเวลาเซตมาหลายวันแล้วครับ รบกวนผู้รู้ช่วยแนะนำทีน่ะครับ

#include "stm32f10x_lib.h"

VU16 ADC_ConvertedValue;
char str[14];

//------------------------------ Function RCC Configuration ------------------------------------------//
void RCC_setup()
{
   ErrorStatus HSEStartUpStatus; // Keep error status
   RCC_DeInit();      // RCC system reset(for debug purpose)
   RCC_HSEConfig(RCC_HSE_ON);  // Enable HSE
   HSEStartUpStatus = RCC_WaitForHSEStartUp();   // Wait till HSE is ready
   if(HSEStartUpStatus == SUCCESS)
   {
      RCC_HCLKConfig(RCC_SYSCLK_Div1); // HCLK = SYSCLK
      RCC_PCLK2Config(RCC_HCLK_Div1); // PCLK2 = HCLK
      RCC_PCLK1Config(RCC_HCLK_Div4); // PCLK1 = HCLK/2
      RCC_ADCCLKConfig(RCC_PCLK2_Div4);  // ADCCLK = PCLK2/4
      FLASH_SetLatency(FLASH_Latency_2); // Flash 2 wait state
      FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);  // Enable Prefetch Buffer
      RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);   // PLLCLK = 8MHz * 9 = 72 MHz
   
      RCC_PLLCmd(ENABLE);  // Enable PLL 
      while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);   // Wait until PLL is ready
     
      RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);  // Select PLL as system clock source
      while(RCC_GetSYSCLKSource() != 0x08); // Wait till PLL is used as system clock source
   }
   
}

//------------------------------ Function GPIO Configuration -----------------------------------------//
void GPIO_setup()
{
   GPIO_InitTypeDef GPIO_InitStructure;
   // Enable GPIOC clock and Enable GPIOA and AFIO clock
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE);
   
   // Configure PC4 as analog input(ADC Channel14)       //ADC_CH1(ADC10)
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
   GPIO_Init(GPIOC, &GPIO_InitStructure);

   // Configure USART1 Tx (PA9) as alternate function push-pull
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
   GPIO_Init(GPIOA, &GPIO_InitStructure);
   // Configure USART1 Rx (PA10) as input floating
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
   GPIO_Init(GPIOA, &GPIO_InitStructure);
}

//------------------------------ Function DMA Configuration ------------------------------------------//
void DMA_setup()
{
   DMA_InitTypeDef DMA_InitStructure;
   // Enable DMA clock
   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
   // DMA channel1 configuration
   DMA_DeInit(DMA1_Channel1);
   DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR;
   DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&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_Disable;
   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);   // Enable DMA channel1
}

//------------------------------ Function ADC Configuration ------------------------------------------//
void ADC_setup()
{
   ADC_InitTypeDef ADC_InitStructure;
   // Enable ADC1 clock
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
   // ADC1 configuration
   ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
   ADC_InitStructure.ADC_ScanConvMode = DISABLE;
   ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
   ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
   ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
   ADC_InitStructure.ADC_NbrOfChannel = 1;
   ADC_Init(ADC1, &ADC_InitStructure);
   // ADC1 regular channel14 configuration 
   ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_13Cycles5);
   ADC_DMACmd(ADC1, ENABLE);  // Enable ADC1 DMA
   ADC_Cmd(ADC1, ENABLE);  // Enable ADC1
 
   ADC_ResetCalibration(ADC1);   // Enable ADC1 reset calibaration register
   while(ADC_GetResetCalibrationStatus(ADC1));

   ADC_StartCalibration(ADC1);   // Start ADC1 calibration
   while(ADC_GetCalibrationStatus(ADC1)); // Check the end of ADC1 calibration
   ADC_SoftwareStartConvCmd(ADC1, ENABLE);    // Start ADC1 Software Conversion 
}

//------------------------------ Function USART1 Configuration -----------------------------------------//
void USART1_setup()
{
   USART_InitTypeDef USART_InitStructure;
   // Enable USART1 clock
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
   // USART1 configured
   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_None;
   USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
   
   USART_Init(USART1, &USART_InitStructure); // Configure the USART1
   USART_Cmd(USART1, ENABLE);  // Enable USART1
   
}

//------------------------------ Function USART1 send 1 character ------------------------------------//
void usart1_putc(unsigned char c)
{
   while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);   // Wait until transmition ready
   USART_SendData(USART1,(int)c);   // Send character
}

//------------------------------ Function USART1 send string -----------------------------------------//
void usart1_puts(unsigned char *s)
{
   while(*s)   // Check end of string
   {
      usart1_putc(*s++);   // Send charracter 1 time
   }
}

//------------------------------ Function USART1 wait character --------------------------------------//
int usart1_getc()
{
   while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);   // Wait until receive data
   return(USART_ReceiveData(USART1));  // Return  character
}

//---------------------------------------- Main Program ----------------------------------------------//
int main()
{   
   unsigned long percentage;
   
   RCC_setup();       // RCC Configuration   
   GPIO_setup();      // GPIO Configuration
   DMA_setup();       // DMA Configuration
   ADC_setup();       // ADC Configuration
 
   USART1_setup();    // USART1 Configuration
   
  while(1)       
   { 
         
      percentage = ADC_ConvertedValue;     
      sprintf(str,"%d%%   ",percentage);  // Convert percentage value to string
      usart1_puts(str);       // Send character from buffer
      usart1_puts("\r\n");    // New line
      delay_ms(100);     // Delay a few time 
     
   }
}

Jimmkung

ตอนนี้ผมกำลังสงสัยอยู่สองกรณีครับคือ
1. ผม set ADC config ผิด
2. STM32F107VBT6 ของผมมีปัญหา

เพราะผมลองเอาโค้ดตัวอย่างแบบที่ไม่ได้ใช้ DMA มาลองมันก็ยังอ่านไม่ตรงครับ ลองตามหนังสือเค้าทุกอย่าง เปลี่ยนไปใช้ ADC ช่องเดียวกับเค้าด้วยก็ไม่หาย

Case ADC ของผมในตอนนี้น่ะครับ
1. ที่ 0 V ADC อ่านได้ 0 จริง ลองเอามิเตอร์มาจับก็ 0 โวลต์จริงครับ
2. ที่ 3.3 V ADC อ่านได้ 4095 จริง ลองเอามิเตอร์มาจับก็ 3.3V จริงครับ
3. VR แบบที่ผมเลือกใช้เป็นแบบ Linear ครับ เอามิเตอร์วัดตลอดช่วงครับ
4. ผมลองเอา R 2 ตัวมาต่อแบบ Voltage Divider โดยใช้ R 2 ตัว ค่าเท่ากัน จ่ายไฟเลี้ยง ที่ 3.3V ดังนั้นเมื่อผ่านวงจร Voltage Divider จะเหลือ 1.65 ลองเอามิเตอร์มาวัด
ก็ได้ค่าตามที่คำนวณจริงครับ
5. ผมเอาสัญญาณที่ผ่านวงจร Voltage divider แล้ว เข้า ADC1 channel 14 ซึ่งก็น่าจะอ่านได้ 2048 แต่ปรากฏว่า ณ ปัจจุบันตามโค้ตที่ผมโพสไว้ ผมอ่าน ADC ได้ 2904
ซึ่งแตกต่างจากค่าความเป็นจริงอยู่ถึงประมาณ 900

Case Setting ADC ที่ผมเคยลองน่ะครับ
1.ผมลองเปลี่ยน sampling time จาก 13.5 เป็น 7.5, 5.5 , 28.5 ก็ไม่มีความแตกต่างจากเดิมครับ
2.ผมลองเปลี่ยน ADC_InitStructure.ADC_Mode จาก Independent เป็น ADC_Mode_FastInterl, ADC_Mode_RegSimlt ก็ไม่มีความแตกต่างเช่นกันครับ

ปล.รบกวนผู้รู้ทุกท่านที่เมตตา ที่ให้คำปรึกษาได้ฝากเบอร์โทรไว้ใน Terawat.k@gmail.com ให้ผมโทรไปถามท่านจะขอบคุณมากๆครับ

crywolf

ลองดู Code ของผมนะครับ http://www.electoday.com/index.php?topic=447.msg1388#msg1388
ผม Test บน STM32-Discovery แสดงผลได้ถูต้อง ลอง Print มาโชว์ดูครับ ADC_RAW_Value นะครับ

Jimmkung

@ คุณ crywolf ผมลองตามวิธีของคุณแล้วปรากฏว่ามันก็ยังอ่านได้ 2905 เท่าเดิมเลยครับ ผมว่าสงสัย STM32F107VBT6 ของผมจะกลับบ้านเก่าไปแล้วแน่ๆเลยครับ