發新話題
打印

C8051F340 ADC問題

C8051F340 ADC問題

各位先進,不好意思,小弟這邊有個問題想要提問,小弟現在是在實做一個光感測器經C8051F340 ADC轉換後再經USB傳給PC的裝置,程式皆是以Silicon Labs的Sample code改的,現在小弟的問題是,ADC0輸出的結果都會突然下降,例如:輸出值為160,會突然下降到10以下,下降後會在回來160然後又再下降,不知是什麼問題,已經困惑我多時了,希望各位先進可以給小弟一些建議,十分感謝!!
// Includes

#include "compiler_defs.h"
#include "C8051f340_defs.h"
#include <stddef.h>
#include "USB_API.h"

#define INTERRUPT_USBXpress 17


// Global CONSTANTS

#define Sw1 0x01                        
#define Sw2 0x02                        

#define SYSCLK       24500000         

U8 Switch1State = 0;                     
U8 Switch2State = 0;                    

U8 Toggle1 = 0;                          
U8 Toggle2 = 0;                        

U8 flicker = 0x00;

U8 Out_Packet[8] = {0,0,0,0,0,0,0,0};        //從HOST接收(讀)
U8 In_Packet[8]  = {0,0,0,0,0,0,0,0};     //傳送給HOST(寫)

/*** [BEGIN] USB Descriptor Information [BEGIN] ***/
SEGMENT_VARIABLE(USB_VID, U16, SEG_CODE) = 0x10C4;
SEGMENT_VARIABLE(USB_PID, U16, SEG_CODE) = 0xEA61;
SEGMENT_VARIABLE(USB_MfrStr[], U8, SEG_CODE) =
{
   0x1A,
   0x03,
   'S',0,
   'i',0,
   'l',0,
   'i',0,
   'c',0,
   'o',0,
   'n',0,
   ' ',0,
   'L',0,
   'a',0,
   'b',0,
   's',0
};
SEGMENT_VARIABLE(USB_ProductStr[], U8, SEG_CODE) =
{
   0x10,
   0x03,
   'U',0,
   'S',0,
   'B',0,
   ' ',0,
   'A',0,
   'P',0,
   'I',0
};

SEGMENT_VARIABLE(USB_SerialStr[], U8, SEG_CODE) =
{
   0x0A,
   0x03,
   '1',0,
   '2',0,
   '3',0,
   '4',0
};

SEGMENT_VARIABLE(USB_MaxPower, U8, SEG_CODE) = 15;   
                                                     
SEGMENT_VARIABLE(USB_PwAttributes, U8, SEG_CODE) = 0x80;   
                                                           
                                                            
SEGMENT_VARIABLE(USB_bcdDevice, U16, SEG_CODE) = 0x0100;   
                                                            


//-----------------------------------------------------------------------------
// Function Prototypes
//-----------------------------------------------------------------------------

void Timer_Init(void);                       
void Adc_Init(void);
void Port_Init(void);
void Suspend_Device(void);
void Initialize(void);
void Delay(unsigned int x);
//-----------------------------------------------------------------------------
// Main Routine
//-----------------------------------------------------------------------------
void main(void)
{

   PCA0MD &= ~0x40;                     

   USB_Clock_Start();                     
   USB_Init(USB_VID,USB_PID,USB_MfrStr,USB_ProductStr,USB_SerialStr,USB_MaxPower,USB_PwAttributes,USB_bcdDevice);

   Initialize();
   USB_Int_Enable();
   EA=1;
   while (1)
   {

      In_Packet[0] = Switch1State;        
      In_Packet[1] = Switch2State;        
      In_Packet[2] = 0x00;      
      In_Packet[3] = 0x00;      
      In_Packet[4] = flicker;   
  
   }
}

//-----------------------------------------------------------------------------
// Initialization Subroutines
//-----------------------------------------------------------------------------

//-------------------------
// Port_Init
//-------------------------
// Port Initialization
// - Configure the Crossbar and GPIO ports.
//
void Port_Init(void)
{
   P2MDIN   = 0xFB;                        
   P0MDOUT |= 0x0F;                       
   P1MDOUT |= 0x0F;                        

   P2MDOUT |= 0x0C;                       
   P2SKIP   = 0x04;  //0x20                        

   XBR0     = 0x00;
   XBR1     = 0x40;                        
}

//-------------------------
// Timer_Init
//-------------------------
// Timer initialization
// - 1 mhz timer 2 reload, used to check if switch pressed on overflow and
// used for ADC continuous conversion
//
void Timer_Init(void)
{
   TMR2CN  = 0x00;                        

   CKCON  &= ~0xF0;                       
   TMR2RL  = -(24500000 / 12);            
   TMR2    = 0xffff;                     

   ET2     = 1;                           
   TR2     = 1;                           
}

//-------------------------
// Adc_Init
//-------------------------
// ADC initialization
// - Configures ADC for single ended continuous conversion or Timer2
//

void Adc_Init (void)
{
   ADC0CN = 0x02;                     
                                       

   REF0CN = 0x00;                     

   AMX0P = 0x02;                       
   AMX0N = 0x1E;                       
                                      

   ADC0CF = ((SYSCLK/3000000)-1)<<3;   

   ADC0CF |= 0x00;                     

   EIE1 |= 0x08;                     

   AD0EN = 1;                          


}

//-------------------------
// Suspend_Device
//-------------------------
// Called when a DEV_SUSPEND interrupt is received.
// - Disables all unnecessary peripherals
// - Calls USB_Suspend()
// - Enables peripherals once device leaves suspend state
//
void Suspend_Device(void)
{
   // Disable peripherals before calling USB_Suspend()
   P0MDIN = 0x00;                       
   P1MDIN = 0x00;                       
   P2MDIN = 0x00;                       
   P3MDIN = 0x00;                       
   REF0CN  &= ~0x0E;                  
   ADC0CN &= ~0x80;                    
   ET2 = 0;                             


   USB_Suspend();                       

   // Once execution returns from USB_Suspend(), device leaves suspend state.
   // Reenable peripherals
   REF0CN  = 0x0E;                     
   ADC0CN |= 0x80;                     
   P0MDIN = 0xFF;
   P1MDIN = 0x7F;                     
   P2MDIN = 0xFF;
   P3MDIN = 0x01;
   ET2 = 1;                           
}

//-------------------------
// Initialize
//-------------------------
// Called when a DEV_CONFIGURED interrupt is received.
// - Enables all peripherals needed for the application
//
void Initialize(void)
{
   Port_Init();                           
   Timer_Init();                          
   Adc_Init();                           

}


//-------------------------
// Timer2_ISR
//-------------------------
// Called when timer 2 overflows, check to see if switch is pressed,
// then watch for release.
//
INTERRUPT(Timer2_ISR, INTERRUPT_TIMER2)
{
   if (!(P2 & Sw1))                       // Check for switch #1 pressed
   {
      if (Toggle1 == 0)                   // Toggle is used to debounce switch
      {                                   // so that one press and release will
         Switch1State = ~Switch1State;    // toggle the state of the switch sent
         Toggle1 = 1;                     // to the host
      }
   }
   else Toggle1 = 0;                      // Reset toggle variable

   if (!(P2 & Sw2))                       // This is the same as above, but for Switch2
   {
      if (Toggle2 == 0)
      {
         Switch2State = ~Switch2State;
         Toggle2 = 1;
      }
   }
   else Toggle2 = 0;

   TF2H = 0;                              // Clear Timer2 interrupt flag
}
//-------------------------
// Adc_ConvComplete_ISR
//-------------------------
// Called after a conversion of the ADC has finished
// - Updates the appropriate variable for either potentiometer or temperature sensor
// - Switches the Adc multiplexor value to switch between the potentiometer and temp sensor
//
INTERRUPT(Adc_ConvComplete_ISR, INTERRUPT_ADC0_EOC)
{
   //U32 flicker;
    U8 ADC0_A;
        U8 ADC0_N;
        U8 flicker_a;

   AD0INT = 0;                               // Clear ADC0 conv. complete flag

   if (AMX0P == 0x02)                     // This switches the AMUX between
   {
         ADC0_A = ADC0;
                    Delay(200);

    ADC0_N = ADC0;
       
      flicker_a = ADC0_A-(ADC0_A/32)+(ADC0_N/32);                   //result;
    if(flicker_a > 21)
      {
          flicker = flicker_a;
          }
      AMX0P       = 0x02;              //0x04;                 // switch to potentiometer ('F340 - P2.5)
      ADC0CF      = 0xF8;                 // place ADC0 in left-adjusted mode                

   }
   else
   {
     // Potentiometer = ADC0H;
      AMX0P       = 0x02; //1E;                 // switch to temperature sensor
      ADC0CF      = 0xF8;                  // place ADC0 in right-adjusted mode
   }

   AD0INT = 1;
   Block_Write(In_Packet, 8);
}


// Example ISR for USB_API
INTERRUPT(USB_API_TEST_ISR, INTERRUPT_USBXpress)
{
   U8 INTVAL = Get_Interrupt_Source(); //得到中斷類型

   if (INTVAL & RX_COMPLETE)    //數據發送完成
   {
      Block_Read(Out_Packet, 8);
   }

   if (INTVAL & DEV_SUSPEND)   //設備掛起
   {
        Suspend_Device();
   }

   if (INTVAL & DEV_CONFIGURED)  //設備初始化
   {
      Initialize();
   }

}

void Delay(unsigned int x)
{
unsigned int a,b;
for(a=x;a>0;a--)
    for(b=100;b>0;b--);
}

// Startup code for SDCC to disablt WDT before initializing variables so that
// a reset does not occur
#if defined SDCC
void _sdcc_external_startup (void)
{
   PCA0MD &= ~0x40;                       // Disable Watchdog timer
}
#endif

// ============================================================================
// *** END OF FILE ***
// ============================================================================

TOP

剛測試了你的code, 沒有發生
"ADC0輸出的結果都會突然下降",
1. 請確定你要量測的訊號是什麼.
2. 請不要把adc input 端 floating, 這有可能出現adc值突然上下變動.

你是否外掛osc當input, C8051F340 內部沒有辦法產成24500000Hz.

TOP

小弟的版子沒有外掛osc當input, 那想在請教一下C8051F340的CLOCK要調多少才可以呢?要怎麼調呢?
還是很感謝板主的回覆。

TOP

1. 你這份code是使用USBXPRESS 來完成的,
請參考 an169:USBXPRESS® PROGRAMMER’S GUIDE 中的 APPENDIX A — SFRS THAT SHOULD NOT BE   MODIFIED AFTER CALLING USB_CLOCK_START AND USB_INIT.

2. 對應在c8051f340 datasheet 部份請參考 14.Oscillators 中的選項去設定.

TOP

發新話題