Silver Sumo Home

Revised IgORElib Main Sumo Program  Guardian Program 

Silver Sumo Hardware Routines

You can download the files from here


SS_Hardware.h :

#ifndef __SS_HARDWARE_H__
#define __SS_HARDWARE_H__


#include "igorelib.h"

#define BATTERY_VOLTAGE LIGHT_RIGHT                            
// I have connected a zener/resistor to the right photo diodes AD line to get the battery level

// *************************** Globals **************************
extern uint8 Meter_Mode;
extern uint8 Meter_Scan;

// *************************** Prototypes ***********************
void Reset_Hardware( void );
void Check_Sharp( void );
void Check_Battery( void );
void Sound(uint16 freq);
void Sound_Ramp( uint16 freq_start, uint16 freq_end, uint8 steps);
void Light_Display( uint8 pattern );
void Meter_Display( uint16 pattern );
void Meter_Set( uint16 pattern, uint8 meter);
void Meter_Update( void );

uint16 sample_AD( uint8 );

#endif


SS_Hardware.c :

#include "SS_Hardware.h"

// *************************** Globals **************************
uint16 Meter_Bitmap = 0; // bit map to be sent to the level meter LEDS
uint8 Meter_Mode = AUTO_UPDATE; // Flag to control the mode of the level meters
uint8 Meter_Scan = ON; // Flag to control the cosmetic scanning of the top level meter

uint8 display_index = 0; // Used mainly for wakeup routine
uint8 Display_Bitmap = 0; // Used mainly for wakeup routine


//---------------------------------------------------------------
// Reset_Hardware
//
// Any additional hardware setup routines should be placed into this 
// routine.
//
//---------------------------------------------------------------
void Reset_Hardware( void )
{
    uint8 index;

    if ( check_bumper(LEFT) )           
// This is used to re-calibrate
    {                                                  
// the ground IR sensors.
        Sound_Ramp(100, 1000, 50);
        set_line_threshold();
        Sound_Ramp(1000, 100, 50); 
    }

    for(index = 0; index < 4; index++)
// General pause to let subsystems start
    {                                                  
// and to make sure that shift registers for 
        delay_ms(250); // LEDs are blank
        Light_Display(0x00);
        Meter_Display(0x0000);
    }
}


//---------------------------------------------------------------
// Check_Battery
//
// This will give a meter-like reading on the left line of the front 
// meter display based on a reading from the battery level. The 
// battery level was taken from the right photo ADC line because 
// I never did install the photo diode into that side, so it was 
// the easiest to steal. =)
//
// This is to give some kind of social interaction to any
// viewers, other than just blinky lights.
//---------------------------------------------------------------
void Check_Battery( void )
{
    uint16 battery_level = 0;

    battery_level = sample_AD(BATTERY_VOLTAGE);
// Get current battery level

    if ( battery_level > 0x03B0 )
        Meter_Set(0x1F, 3);
    else if ( battery_level > 0x0300 )
        Meter_Set(0x0F, 3);
    else if ( battery_level > 0x02A0 )
        Meter_Set(0x07, 3);
    else if ( battery_level > 0x0250 )
        Meter_Set(0x03, 3);
    else if ( battery_level > 0x0200 )
        Meter_Set(0x01, 3);
    else
        Meter_Set(0x00, 3);
}

//---------------------------------------------------------------
// Check_Sharp
//
// This will give a meter-like reading on two of the front meter 
// displays.
//
// This is to give some kind of social interaction to any
// viewers, other than just blinky lights.
//---------------------------------------------------------------
void Check_Sharp( void )
{
    uint8 ir_reading;

    ir_reading = read_sharp_cm(LEFT);
// Get current Sharp Reading

    if ( ir_reading < 10 ) // Display it to one of the level meters
        Meter_Set(0x1F, 2);
    else if ( ir_reading < 15 )
        Meter_Set(0x0F, 2);
    else if ( ir_reading < 20 )
        Meter_Set(0x07, 2);
    else if ( ir_reading < 25 )
        Meter_Set(0x03, 2);
    else if ( ir_reading < 40 )
        Meter_Set(0x01, 2);
    else
        Meter_Set(0x00, 2);
}


//---------------------------------------------------------------
// Sound
//
// This function is connected to a piezo electric speaker/buzzer
// on port B, pin 5. The other side is connected to +5V.
//
// This is to give some kind of social interaction to any
// viewers, other than just blinky lights.
//---------------------------------------------------------------
void Sound(uint16 freq)
{
    uint16 inv_freq;
    uint16 duration = freq/100;                    
// This seemed to be a nice length

    if ( read_switch(2) )                              
// Check for mute switch
    {
        if (freq > 1000)                                
// If freq asked for is too high, another time delay function
        {                                                      
// needs to be used (delay_us vs. delay_ms)
            inv_freq = 1000000/freq;

            while (duration > 0)
            {
                PORTBbits.RB5 = 0;
                delay_us(inv_freq);
                PORTBbits.RB5 = 1;
                delay_us(inv_freq);
                duration--;
            }
        }
        else
        {
            inv_freq = 1000/freq;                    
// (1/freq) * 20000/2 ---> the 2 is from the fact that half the wave is on, and half is off

            while (duration > 0)
            {
                PORTBbits.RB5 = 0;
                delay_ms(inv_freq);
                PORTBbits.RB5 = 1;
                delay_ms(inv_freq);
                duration--;
            }
        }
    }
}

//---------------------------------------------------------------
// Sound_Ramp
//
// Just a little something to augment the Sound() function.
//
// This is to give some kind of social interaction to any
// viewers, other than just blinky lights.
//---------------------------------------------------------------
void Sound_Ramp( uint16 freq_start, uint16 freq_end, uint8 steps)
{
    uint16 step_size;

    if ( read_switch(2) )                            
// Check for mute switch (This is checked here as well as the other
    {                                                        
// sound function, so time isn't wasted on a routine that doesn't need
                                                              // to be run when the switch is off)


        if (freq_start < freq_end)                
// Sound ramping up
        {
            step_size = (freq_start - freq_end)/ steps;
            while(freq_start < freq_end)
            {
                Sound(freq_start);
                freq_start += step_size;
            }
            Sound(freq_end);
        } 
        else                                                
// Sound ramping down
        {
            step_size = (freq_end - freq_start)/ steps;
            while(freq_start > freq_end)
           {
                Sound(freq_start);
                freq_start -= step_size;
            }
            Sound(freq_end);
        }
    }
}

//****************************************************************************
// Light_Display
//
// Additional hardware to the igore produced by Nicholas Cogghe has required
// certain additional calls to access this hardware. Display lights for the 
// top of Igore have been added for debugging and/or entertainment purposes.
//
// This hardware is a simple shift register attached to 8 LEDs.
//
//TODO: no control over the Master Reset from the shift register is 
//available, this would be handy in the future.
//
//****************************************************************************
void Light_Display( uint8 pattern )
{
    int index;

    for(index = 0; index < 8; index++)
    {
        PORTDbits.RD3 = !(0x01 & pattern);
// Put Data to Pin D3
                                                                  
// Pause for Effect/Applause
        PORTDbits.RD2 = 1;
        PORTDbits.RD2 = 0;
        pattern = pattern >> 1;                       
// Lather, Rinse, Repeat.
    }
}

//****************************************************************************
// Meter_Display
//
// Additional hardware to the igore produced by Nicholas Cogghe has required
// certain additional calls to access this hardware. Display lights for the 
// top of Igore have been added for debugging and/or entertainment purposes.
//
// This hardware is a simple shift register attached to 8 LEDs. (NOTE: Last
// bit is not connected to any LED in hardware)
//
//TODO: no control over the Master Reset from the shift register is 
//available, this would be handy in the future.
//
//****************************************************************************
void Meter_Display( uint16 pattern )
{
    int index;

    for(index = 0; index < 16; index++)
    {
        PORTDbits.RD4 = !(0x01 & pattern);
// Put Data to Pin D3
                                                                   
// Pause for Effect/Applause
        PORTAbits.RA4 = 1;                          // Clock goes up,
        PORTAbits.RA4 = 0;                          // Clock goes down 
        pattern = pattern >> 1;                        
// Lather, Rinse, Repeat.
    }
}

//****************************************************************************
// Meter_Set
//
// Additional hardware to the igore produced by Nicholas Cogghe has required
// certain additional calls to access this hardware. Display lights for the 
// top of Igore have been added for debugging and/or entertainment purposes.
//
// This routine is used to turn on or off the front meter lights,
// yet changes to the lights will not be noticeable until the 10Hz
// update clock calls the Meter_Update routine.
//
// NOTE: This routine is only useful if the flag Meter_Mode is in 
// AUTO_UPDATE mode. Otherwise, no updates will occur.
//****************************************************************************
void Meter_Set(uint16 pattern, uint8 meter)
{
    uint16 new_pattern = 0x001F & pattern;        
// Each meter only contains 5 LEDs

    new_pattern = new_pattern << 1;

    switch(meter)
    {
        case 0:                                                        
// Set all meters to same value
        Meter_Bitmap = (Meter_Bitmap & 0xFFC1) | new_pattern;
        new_pattern = new_pattern << 5;
        Meter_Bitmap = (Meter_Bitmap & 0xF83F) | new_pattern;
        new_pattern = new_pattern << 5;
        Meter_Bitmap = (Meter_Bitmap & 0x07FF) | new_pattern;
        break;
        case 1:                                                        
// Meter 1, top row, LED 1 (far left/outside)
        Meter_Bitmap = (Meter_Bitmap & 0xFFC1) | new_pattern;
        break;

        case 2:                                                        
// Meter 2, Left Vertical Row (Outside), LED 1 bottom
        new_pattern = new_pattern << 5;
        Meter_Bitmap = (Meter_Bitmap & 0xF83F) | new_pattern;
        break;

        case 3:                                                        
// Meter 3, Right Vertical Row (Inside), LED 1 bottom
        new_pattern = new_pattern << 10;
        Meter_Bitmap = (Meter_Bitmap & 0x07FF) | new_pattern;
        break;
    }
}

// --------------------------------------------------------------
// Meter_Update
//
// This function was created to operate as an update routine
// to be triggered by an interrupt. This will be updated by the 
// 10Hz clock, when it is in auto_update move.
//
// This routine is specifically ornamental, to give the robot a 
// bit of class.
// --------------------------------------------------------------
void Meter_Update( void )
{
static uint8 Scan_Position = 0, Scan_Dir = RIGHT;
int index;
uint16 pattern = Meter_Bitmap;

if (Meter_Scan == ON)                                    
// The Meter_Scan routines only serves
{                                                                      
// cosmetic and haptic purposes
    if (Scan_Dir == RIGHT)
    {
        Scan_Position++;
        if (Scan_Position == 4)
        Scan_Dir = LEFT;
    }
    else
    {
        Scan_Position--;
        if (Scan_Position == 0)
        Scan_Dir = RIGHT;
    }

    switch(Scan_Position)
    {
        case 0:
        Meter_Set(0x01, 1); break;
        case 1:
        Meter_Set(0x02, 1); break;
        case 2:
        Meter_Set(0x04, 1); break;
        case 3:
        Meter_Set(0x08, 1); break;
        case 4:
        Meter_Set(0x10, 1); break;
        }
    }                                                                
// End of Meter_Scan cosmetic routines

    for(index = 0; index < 16; index++)            
// This is to actually shove the data to the shift register
    {
    PORTDbits.RD4 = !(0x01 & pattern);       
// Put Data to Pin D3
                                            
                          // Pause for Effect/Applause =)
    PORTAbits.RA4 = 1;                                
// Clock goes up,
    PORTAbits.RA4 = 0;                                
// Clock goes down 
    pattern = pattern >> 1;                               
// Lather, Rinse, Repeat.
    }

}