Back to Electronics Cookbook Back to Smart&Small  

 

Combined MEMS sensor for robots and inertial navigation systems. Three axis gyroscope and three axis accelerometer. The high precision and low cost sensor based on ADXL203 accelerometers, ADXRS300 gyroscopes, AD7718 DAC IC and ATmega8 microcontroller.

Schematic diagram part 1. Click to enlarge.



Schematic diagram part 2. Click to enlarge.



MEMS Sensor PCAD2006 Schematic file. Click to download.

Source code (IAR Embedded Workbench):

// Inertial Cluster
// Processor ATmega8
// Clock rate 8 MHz
// Clock source - Internal RC Oscillator

#include <iom8.h> // Declares the internal register addresses for ATmega8
#include <inavr.h> // Intrinsics for iccAVR

// Function declaration
void initPorts (void); // ATmega8 Ports init
void clearReadings (void); // Clear all readings

void resetADC (void); // ADC reset
void initUSART (unsigned char baud); // USART initialization

void initMasterSPI (void); // SPI initialization as a Master
void transmitMasterSPI (unsigned char SPIData); // Perform a SPI transmission

void configADC (void); // Configure ADC
void setChannel (unsigned char channel); // Set ADC channel

long ReadADC (void); // ADC reading
long SetAndReadADC (unsigned char channel); // Set & Read ADC at once

void transmitUSART(unsigned char tdata); // USART transmit
void clearADCreadings(void);

// Selftest control
#define ST1 PB0 // Selftest pin for accelerometers and angular rate sensor
#define ST2 PB1 // Selftest pin for angular rate sensor only
// ADC AD7718 control
#define DRDY (PIND & 4) // ADC Data Ready (active low, ADC master)
#define RSTADC PD3 // ADC Reset (active low, ADC slave)
// SPI
#define MOSI PB3
#define SCK PB5
// UART
#define TXDPIN PD1
// AD7718 register model
#define CommWR 0
#define CommRD 64
#define CommMode 1
#define CommControl 2
#define CommFilter 3
#define CommData 4
#define CommOffset 5
#define CommGain 6
#define CommIO 7
#define CommTest1 12
#define CommTest2 13
#define CommID 15
// AD7718 variables
// ADC update rate for CHOP disabled
#define updateRateNoCHOP1365Hz 3 // ADC update rate = 1365.33 Hz
#define updateRateNoCHOP315Hz 13 // ADC update rate = 315 Hz
#define updateRateNoCHOP59Hz 69 // ADC update rate = 59.36 Hz
#define updateRateNoCHOP16Hz 255 // ADC update rate = 16.06 Hz
// ADC update rate for CHOP enabled
#define updateRateCHOP105Hz 13 // ADC update rate = 105.3 Hz
#define updateRateCHOP59Hz 23 // ADC update rate = 59.36 Hz
#define updateRateCHOP51Hz 27 // ADC update rate = 50.56 Hz
#define updateRateCHOP30Hz 45 // ADC update rate = 30.3 Hz

#define BaseModeNoCHOP 147 // Chopping is disabled
#define BaseModeCHOP 19 // Chopping is enabled
#define BaseControl 15 // Select input AIN1, enable unipolar coding, select the ADC input range as 0...+5 V
// AD7718 channels

#define accelerXnoFch 1

#define RNUM 200

unsigned long ulAccXZeroCode;
unsigned long ulAccXCurCode; // Accelerometer 1 (X-axis) current reading
unsigned long ulAccXCurCode2;

long ADCreadings[RNUM];

long num = 0;

void main (void)
{
    __disable_interrupt();
    initPorts();

    initUSART(12); // 38.4 k @ 8 MHz
    initMasterSPI();
    resetADC();
    configADC();

    setChannel(accelerXnoFch);
    clearADCreadings();

    for (num = 0; num < RNUM ; num++)

        ADCreadings[num] = ReadADC();

    for (num = 0; num < RNUM ; num++)

        ulAccXZeroCode += ADCreadings[num];
    ulAccXZeroCode /= RNUM;

    while (1) // Main loop
    {
        ulAccXCurCode = ReadADC();

        if (ulAccXCurCode > ulAccXZeroCode) ulAccXCurCode = (ulAccXCurCode - ulAccXZeroCode) + 0x80000000;

        else ulAccXCurCode = 0x80000000 - (ulAccXZeroCode - ulAccXCurCode);

        transmitUSART((unsigned char)(ulAccXCurCode>>24));
        transmitUSART((unsigned char)(ulAccXCurCode>>16));

        transmitUSART((unsigned char)(ulAccXCurCode>>8));
        transmitUSART((unsigned char)(ulAccXCurCode));
    }
}

void clearADCreadings(void)
{
    long numr = 0;

    for (numr = 0; numr < RNUM ; numr++) ADCreadings[num] = 0;
}

void initPorts(void) // ATmega8 Ports init
{
    DDRB = 0; // All ports direction = input

    DDRC = 0;
    DDRD = 0;

    DDRB |= ( 1 << ST1 ); // Selftest pins = output
    DDRB |= ( 1 << ST2 );

    DDRD |= ( 1 << RSTADC ); // ADC reset and TxD = output
    DDRD |= ( 1 << TXDPIN );

    PORTB &= ~( 1 << ST1 ); // Selftest pins = 0 (no selftest)
    PORTB &= ~( 1 << ST2 );

    PORTD &= ~( 1 << RSTADC ); // ADC reset = 0
}

void initUSART(unsigned char baud) // USART initialization
{
    UBRRH = (unsigned char)(baud>>8);

    UBRRL = (unsigned char) baud;
    UCSRB = (( 1 << RXEN ) | ( 1 << TXEN )); // RX, TX enable

    UCSRC = ( 1 << URSEL ) | ( 1 << USBS ) | ( 3 << UCSZ0 );// Two stop bits, 8 bit

}

void transmitUSART(unsigned char tdata) // USART transmit
{
    while ( !( UCSRA & (1<<UDRE)) );

    UDR = tdata;
}

void resetADC(void) // ADC reset

{
    PORTD &= ~( 1 << RSTADC ); // ADC reset pin = 0
    __delay_cycles( 3200000 );

    PORTD |= ( 1 << RSTADC ); // ADC reset pin = 1
    __delay_cycles( 3200000 ); // The oscillator will require the 300 ms start-up time

}

void initMasterSPI(void) // SPI initialization as a Master
{
    DDRB |= (( 1 << MOSI ) | ( 1 << SCK )); // Set MOSI and SCK output, all others input

    SPCR = ( 1 << SPE ) | ( 1 << MSTR ) | ( 1 << SPR0 );// Enable SPI, Master, set clock rate fck/16

}

void transmitMasterSPI(unsigned char SPIData ) // Perform a SPI transmission
{
    SPDR = SPIData; // Start transmission

    while( !( SPSR & ( 1 << SPIF ))); // Wait for transmission complete

}

void configADC (void) // Configure ADC
{
    transmitMasterSPI( CommWR | CommFilter );

    transmitMasterSPI( updateRateNoCHOP315Hz );

    transmitMasterSPI( CommWR | CommMode );

    transmitMasterSPI( BaseModeNoCHOP );

    transmitMasterSPI( CommWR | CommControl );

    transmitMasterSPI( BaseControl );

    while ( DRDY ) ;
}

void setChannel (unsigned char channel) // Set ADC channel
{
    channel <<= 4;

    transmitMasterSPI( CommWR | CommControl );
    transmitMasterSPI( channel | BaseControl );

    while ( DRDY ) ;
}

long ReadADC (void) // ADC reading

{
    long ADCword = 0; // ADC current reading

    while ( DRDY ) ;

    transmitMasterSPI( CommRD | CommData );
    transmitMasterSPI( 0xFF );

    ADCword = SPDR;
    ADCword <<= 8;

    transmitMasterSPI( 0xFF );
    ADCword |= SPDR;
    ADCword <<= 8;

    transmitMasterSPI( 0xFF );
    ADCword |= SPDR;

    return ADCword;
}

long SetAndReadADC (unsigned char channel) // Set & Read ADC at once

{
    setChannel ( channel );
    return ReadADC ();
}

 

  Contact us: inbox@smasma.com © Smart&Small Webmaster: webmaster@smasma.com