微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > 求助 C51F500开发板AD的一个程序 求讲解

求助 C51F500开发板AD的一个程序 求讲解

时间:10-02 整理:3721RD 点击:
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include <compiler_defs.h>
#include <C8051F500_defs.h>            // SFR declarations
#include <stdio.h>
//-----------------------------------------------------------------------------
// Global CONSTANTS
//-----------------------------------------------------------------------------
#define SYSCLK         24000000        // 系统时钟频率(Hz)
#define BAUDRATE         115200        // UART波特率,单位为bps
#define ANALOG_INPUTS         8        // 衡量AIN引脚数,
                                       // 跳过UART0引脚
#define INT_DEC             256        // 集成和抽取比
#define TIMER0_RELOAD_HIGH    0        // Timer0的高字节寄存器
#define TIMER0_RELOAD_LOW   255        // Timer0的低字节寄存器
//-----------------------------------------------------------------------------
// 函数原型
//-----------------------------------------------------------------------------
void OSCILLATOR_Init (void);
void PORT_Init (void);
void TIMER2_Init (void);
void ADC0_Init (void);
void UART0_Init (void);
void Timer0_wait (int ms);
INTERRUPT_PROTO (ADC_ISR, INTERRUPT_ADC0_EOC);
INTERRUPT_PROTO (TIMER2_ISR, INTERRUPT_TIMER2);
//-----------------------------------------------------------------------------
// Global Variables
//-----------------------------------------------------------------------------
// ADC0 decimated value, one for each analog input
SEGMENT_VARIABLE (RESULT[ANALOG_INPUTS], U32, xdata);      
// ADC0 input matrix.  Bit-wise OR with 0x10 to get the ADC0MX setting for P2
U8 PIN_TABLE[ANALOG_INPUTS] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 };
U8 AMUX_INPUT = 0;          // Index of analog MUX inputs
// Integrate accumulator for the ADC samples from input pins
U32 accumulator[ANALOG_INPUTS];
//-----------------------------------------------------------------------------
// MAIN Routine
//-----------------------------------------------------------------------------
void main (void)
{
   U8  i;                              // Loop counter
   U32 measurement;                    // Voltage measurement
   SFRPAGE = ACTIVE_PAGE;              // Set for PCA0MD and for printf()
   PCA0MD &= ~0x40;                    // Disable the watchdog timer
   OSCILLATOR_Init ();                 // Initialize system clock
   PORT_Init ();                       // Initialize crossbar and GPIO
   TIMER2_Init ();                     // Init Timer2 to trigger ADC
   UART0_Init ();                      // Initialize UART0 for printf's
   ADC0_Init ();                       // Initialize ADC0
   // Initialize global variable
   for (i = 0; i < ANALOG_INPUTS; i++)
   {
      accumulator[i] = 0;
   }
   EA = 1;                             // Enable global interrupts
   while (1)
   {
      EA = 0;                          // Disable interrupts
      printf ("\f");
      for (i = 0; i < ANALOG_INPUTS; i++)
      {
         // The 12-bit ADC value is averaged across INT_DEC measurements.
         // The result is then stored in RESULT, and is right-justified
         // The measured voltage applied to the port pins is then:
         //
         //                           Vref (mV)
         //   measurement (mV) =   --------------- * Result (bits)
         //                        (2^12)-1 (bits)
         //
         // Then multiply the result by 2.27 to account for the 0.44 gain
         // applied earlier
         measurement =  RESULT[i] * 2400 / 4096 * 227 / 100;
         printf("P2.%bu voltage: %4ld mV\n", PIN_TABLE[i], measurement);
      }
      EA = 1;                          // Re-enable interrupts
      Timer0_wait(20);                 // Wait before displaying new values
   }
}
//-----------------------------------------------------------------------------
// Initialization Subroutines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// OSCILLATOR_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// This routine initializes the system clock to use the internal 24 MHz
// oscillator as its clock source.  Also enables missing clock detector reset.
//
//-----------------------------------------------------------------------------
void OSCILLATOR_Init (void)             //振荡器
{
   U8 SFRPAGE_save = SFRPAGE;
   SFRPAGE = CONFIG_PAGE;
   OSCICN = 0x87;                      // 配置内部振荡器forits的最高frequencyEnable的时钟丢失检测器
   RSTSRC = 0x04;                     
   SFRPAGE = SFRPAGE_save;
}
//-----------------------------------------------------------------------------
// PORT_Init
//-----------------------------------------------------------------------------
//
// Return Value:  None
// Parameters:    None
//
// Configure the Crossbar and GPIO ports.
//
// P0.0 -          analog               VREF
// P0.4 -          digital  push-pull   UART TX
// P0.5 -          digital  open-drain  UART RX
//
// P1.3 -          digital  push-pull   LED
//
// P2.0 - P2.7     analog               ADC inputs
//
//-----------------------------------------------------------------------------
void PORT_Init (void)                   //光电记录跟踪
{
   U8 SFRPAGE_save = SFRPAGE;
   SFRPAGE = CONFIG_PAGE;
   P0SKIP  |= 0x01;                    // Skip P0.0 (VREF)
   P0MDOUT |= 0x10;                    // Set TX pin to push-pull
   P0MDIN  &= ~0x01;                   // Set VREF to analog
   P1MDOUT |= 0x08;                    // Enable LED as a push-pull output
   P2SKIP  = 0xFF;                     // Skip all of P2 for analog inputs
   P2MDIN  = 0x00;                     // Configure all of P2 as analog inputs
   XBR0     = 0x01;                    // Enable UART0
   XBR2     = 0x40;                    // Enable crossbar and weak pull-ups
   SFRPAGE = SFRPAGE_save;
}
//-----------------------------------------------------------------------------
// TIMER2_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// Configure Timer2 to 16-bit auto-reload and generate an interrupt at 10 us
// intervals.  Timer2 overflows automatically triggers ADC0 conversion.
//
//-----------------------------------------------------------------------------
void TIMER2_Init (void)
{
   U8 SFRPAGE_save = SFRPAGE;
   SFRPAGE = ACTIVE_PAGE;
   TMR2CN = 0x00;                      // Stop Timer2; Clear TF2;
                                       // use SYSCLK as timebase, 16-bit
                                       // auto-reload
   CKCON |= 0x10;                      // Select SYSCLK for timer 2 source
   TMR2RL = 65535 - (SYSCLK / 10000);  // Init reload value for 10 us
   TMR2 = 0xFFFF;                      // Set to reload immediately
   ET2 = 1;                            // Enable Timer2 interrupts
   TR2 = 1;                            // Start Timer2
   SFRPAGE = SFRPAGE_save;
}
//-----------------------------------------------------------------------------
// ADC0_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// Configures ADC0 to make single-ended analog measurements on Port 0 according
// to the values of <ANALOG_INPUTS> and <PIN_TABLE>.
//
//-----------------------------------------------------------------------------
void ADC0_Init (void)
{
   U8 SFRPAGE_save = SFRPAGE;
   SFRPAGE = ACTIVE_PAGE;
   // Initialize the Gain to account for a 5V input and 2.25 VREF
   // Solve the equation provided in Section 9.3.1 of the Datasheet
   // The 5V input is scaled by a factor of 0.44 so that the maximum input
   // voltage seen by the pin is 2.2V
   // 0.44 = (GAIN/4096) + GAINADD * (1/64)
   // Set GAIN to 0x6CA and GAINADD to 1
   // GAIN = is the 12-bit word formed by ADC0GNH[7:0] ADC0GNL[7:4]
   // GAINADD is bit ADC0GNA.0
   ADC0CF |= 0x01;                     // Set GAINEN = 1
   ADC0H   = 0x04;                     // Load the ADC0GNH address
   ADC0L   = 0x6C;                     // Load the upper byte of 0x6CA
   ADC0H   = 0x07;                     // Load the ADC0GNL address
   ADC0L   = 0xA0;                     // Load the lower nibble of 0x6CA
   ADC0H   = 0x08;                     // Load the ADC0GNA address
   ADC0L   = 0x01;                     // Set the GAINADD bit
   ADC0CF &= ~0x01;                    // Set GAINEN = 0
   ADC0CN = 0x03;                      // ADC0 disabled, normal tracking,
                                       // conversion triggered on TMR2 overflow
                                       // Output is right-justified
   REF0CN = 0x33;                      // Enable on-chip VREF and buffer
                                       // Set VREF to 2.25V setting
   ADC0MX = 0x10 | PIN_TABLE[AMUX_INPUT];  // Set ADC input to initial setting
   ADC0CF = ((SYSCLK / 3000000) - 1) << 3; // Set SAR clock to 3MHz
   EIE1 |= 0x04;                       // Enable ADC0 conversion complete int.
   AD0EN = 1;                          // Enable ADC0
   SFRPAGE = SFRPAGE_save;
}
//-----------------------------------------------------------------------------
// UART0_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// Configure the UART0 using Timer1, for <BAUDRATE> and 8-N-1.
//-----------------------------------------------------------------------------
void UART0_Init (void)
{
   U8 SFRPAGE_save = SFRPAGE;
   SFRPAGE = CONFIG_PAGE;
   SCON0 = 0x10;                       // SCON0: 8-bit variable bit rate
                                       // clear RI0 and TI0 bits
   // Baud Rate = [BRG Clock / (65536 - (SBRLH0:SBRLL0))] x 1/2 x 1/Prescaler
#if   ((SYSCLK / BAUDRATE / 2 / 0xFFFF) < 1)
      SBRL0 = -(SYSCLK / BAUDRATE / 2);
      SBCON0 |= 0x03;                  // Set prescaler to 1
#elif ((SYSCLK / BAUDRATE / 2 / 0xFFFF) < 4)
      SBRL0 = -(SYSCLK / BAUDRATE / 2 / 4);
      SBCON0 &= ~0x03;
      SBCON0 |= 0x01;                  // Set prescaler to 4
#elif ((SYSCLK / BAUDRATE / 2 / 0xFFFF) < 12)
      SBRL0 = -(SYSCLK / BAUDRATE / 2 / 12);
      SBCON0 &= ~0x03;                 // Set prescaler to 12
#else
      SBRL0 = -(SYSCLK / BAUDRATE / 2 / 48);
      SBCON0 &= ~0x03;
      SBCON0 |= 0x02;                  // Set prescaler to 48
#endif
   SBCON0 |= 0x40;                     // Enable baud rate generator
   TI0 = 1;                            // Indicate TX0 ready
   SFRPAGE = SFRPAGE_save;
}

#ifdef SDCC
// SDCC does not include a definition for putchar(), which is used in printf()
// and so it is defined here.  The prototype does not need to be explicitly
// defined because it is provided in stdio.h
//-----------------------------------------------------------------------------
// putchar
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : character to send to UART
//
// This function outputs a character to the UART.
//-----------------------------------------------------------------------------
void putchar (char output)
{
   if (outptrr0ut == '\n')
   {
      while (!TI0);
      TI0 = 0;
      SBUF0 = 0x0D;
   }
   while (!TI0);
   TI0 = 0;
   SBUF0 = output;
}
#endif
//-----------------------------------------------------------------------------
// Interrupt Service Routines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Timer2_ISR
//-----------------------------------------------------------------------------
//
// This routine changes to the next Analog MUX input whenever Timer2 overflows
// for the next ADC sample.  This allows the ADC to begin setting on the new
// input while converting the old input.
//
//-----------------------------------------------------------------------------
INTERRUPT (TIMER2_ISR, INTERRUPT_TIMER2)
{
   TF2H = 0;                           // Clear Timer2 interrupt flag
   // Set up the AMUX for the next ADC input
   if (AMUX_INPUT == (ANALOG_INPUTS - 1))
   {
      ADC0MX = PIN_TABLE[0] | 0x10;
   }
   else
   {
      ADC0MX = PIN_TABLE[AMUX_INPUT+1] | 0x10;
   }
}
//-----------------------------------------------------------------------------
// ADC0_ISR
//-----------------------------------------------------------------------------
//
// This ISR averages <INT_DEC> samples for each analog MUX input then prints
// the results to the terminal.  The ISR is called after each ADC conversion,
// which is triggered by Timer2.
//
//-----------------------------------------------------------------------------
INTERRUPT (ADC_ISR, INTERRUPT_ADC0_EOC)
{
   static U16 int_dec = INT_DEC;       // Integrate/decimate counter
                                       // A new result is posted when
                                       // int_dec is 0
   U8 i;                               // Loop counter

   AD0INT = 0;                         // Clear ADC conversion complete
                                       // overflow

   accumulator[AMUX_INPUT] += ADC0;    // Read the ADC value and add it to the
                                       // running total
   // Reset sample counter <int_dec> and <AMUX_INPUT> if the final input was
   // just read
   if(AMUX_INPUT == (ANALOG_INPUTS - 1))
   {
      int_dec--;                       // Update decimation counter
                                       // when the last of the analog inputs
                                       // is sampled
      if (int_dec == 0)                // If zero, then post the averaged
      {                                // results
         int_dec = INT_DEC;            // Reset counter
         // Copy each averaged ADC0 value into the RESULT array
         for(i = 0; i < ANALOG_INPUTS; i++)
         {
            // Copy averaged values into RESULT
            RESULT[i] = accumulator[i] / int_dec;
            // Reset accumulators
            accumulator[i] = 0x00000000;
         }
      }
      AMUX_INPUT = 0;                  // Reset input index back to P0.1
   }
   // Otherwise, increment the AMUX channel counter
   else
   {
      AMUX_INPUT++;                    // Step to the next analog mux input
   }
}
//-----------------------------------------------------------------------------
// Support Subroutines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Timer0_wait
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   :
//   1) int ms - number of milliseconds to wait
//                        range is positive range of an int: 0 to 32767
//
// This function configures the Timer0 as a 16-bit timer, interrupt enabled.
// Using the internal osc. at 24.5MHz with a prescaler of 1:8 and reloading the
// T0 registers with TIMER0_RELOAD_HIGH/LOW, it will wait for <ms>
// milliseconds.
// Note: The Timer0 uses a 1:12 prescaler
//-----------------------------------------------------------------------------
void Timer0_wait(int ms)
{
   U8 SFRPAGE_save = SFRPAGE;
   SFRPAGE = ACTIVE_PAGE;
   TH0 = TIMER0_RELOAD_HIGH;           // Init Timer0 High register
   TL0 = TIMER0_RELOAD_LOW ;           // Init Timer0 Low register
   TMOD |= 0x01;                       // Timer0 in 16-bit mode
   CKCON &= 0xFC;                      // Timer0 uses a 1:12 prescaler
   TR0  = 1;                           // Timer0 ON
   while(ms)
   {
      TF0 = 0;                         // Clear flag to initialize
      while(!TF0);                     // Wait until timer overflows
      ms--;                            // Decrement ms
   }
   TR0 = 0;                            // Timer0 OFF
   SFRPAGE = SFRPAGE_save;
}
//-----------------------------------------------------------------------------
// End Of File
//-----------------------------------------------------------------------------

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top