AP KS GM-control panel code.c

From Mech
Revision as of 01:06, 19 March 2009 by Kwang Sim (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search
/**********************************************
 * controlpanel.c
 * Author:Greg McGlynn
 * Persistence-of-Vision Display project
 * Alexander Park, Kwang Xiong Sim, Grag McGlynn 
 * ME 333 Mechatronics - Winter 2008
 * Northwestern University 
 *
 *     This code runs on the control panel PIC. It polls the potentiomemters
 * and pushbutton for significant changes; when one of the inputs changes (i.e.,
 * when the button is pressed or a potentiometer is turned), it sends a
 * command to the display PIC informing the display of the change.
 *
 *    Simultaneously, the PIC is listening for RS232 signals coming in on
 * pin B1. If the USB cable is plugged in this is connected to PC transmit. The
 * PC will send commands along this line intended for the display PIC. The
 * control panel PIC's job is to accept these commands and relay them verbatim
 * to the display PIC through the XBee.
 **********************************************/
 
#include <18f4520.h>
#device adc=8
#fuses EC,NOLVP,NOWDT,NOPROTECT
#use delay(clock=40000000)

//We use software RS232
//Signals are sent out to the XBee on pin B3 and signals come from PC
//on pin B1. 
#use rs232(baud=9600, xmit=PIN_B3, rcv=PIN_B1)

//image angle is a number 0-192 that gives the home column of the POV
int16 image_angle = 0; //the current image angle setting

// - scroll speed is a number 0-255
// - 128 is stationary; higher numbers scroll one way; lower numbers the other
// - (scroll speed) - 128 is proportional change in image angle per second
int16 scroll_speed = 128; //the current scroll speed setting

int button_state = 0; //the current button state (1 = pressed, 0 = not)
int16 button_cooldown_counter = 0; //a debouncing measure

//the adc channels of the four inputs:
#define IMAGE_ANGLE_CHAN 3
#define SCROLL_SPEED_CHAN 2
#define MESSAGE_NUM_CHAN 1
#define MESSAGE_BUTTON_CHAN 0

//constants controlling sensitivity of controls
#define POT_CHANGE_WINDOW 5
#define MESSAGE_BUTTON_COOLDOWN 500


int ignore = true; //ignore the first interrupt on B1; it's a false alarm

//this is called when we start to receive a 4-byte message from the PC
#int_ext1
void incoming_rs232() {
    int byte1, byte2, byte3, byte4;

    //this interupt fires on startup even though there's no message. so 
    //ignore this first message
    if(ignore) {
        ignore = false;
        return;
    }

    //get the four bytes
    byte1 = getc();
    byte2 = getc();
    byte3 = getc();
    byte4 = getc();
    
    //relay them to the xbee
    putc(byte1);
    putc(byte2);
    putc(byte3);
    putc(byte4);
    
}

//read from a specified ADC channel
int pot_read(int chan) {
    set_adc_channel(chan);
    delay_us(10);
    return read_adc();
}

//the absolute value of the difference between two int16's:
int16 diff(int16 a, int16 b) {
    if(a > b) return a - b;
    else      return b - a;
}

//send a command to the display PIC
//commands are four bytes:
//byte 1: 0xff
//byte 2: 0xff
//byte 3: command type
//byte 4: command argument
void send_command(int type, int argument) {
    //we disable interrupts while we send commands so that we don't get 
    //interrupted by an incoming command from the PC
    disable_interrupts(INT_EXT1);
    putc(0xff);
    putc(0xff);
    putc(type);
    putc(argument);
    enable_interrupts(INT_EXT1);
}

//a forumula for converting the reading from the message # pot to a number
//from 0 to 10
int interpret_message_reading(int16 message_reading) {
    if(message_reading == 0) return 0;
    if(message_reading == 255) return 10;
    else return (int)((int16)message_reading*(int16)9/(int16)254+(int16)1);
}

void main() {
    //readings from each pot:
    int16 angle_reading;
    int16 scroll_reading;
    int button_reading;
    int16 message_reading;    

    //setup an interrupt on high-to-low transistions on pin B1. This means
    //that an interrupt is triggered when we start to receive an RS232 signal
    //from the PC, so we can read the incoming message.
    enable_interrupts(INT_EXT1);
    enable_interrupts(GLOBAL);
    ext_int_edge(1, H_TO_L);
    
    setup_adc_ports(AN0_TO_AN3); 
    setup_adc(ADC_CLOCK_INTERNAL);
    set_adc_channel(3);
    
    //main loop: poll the controls
    while(true) {
        //read the image angle pot and convert it to an image angle; if there's
        //been a significant change send a command to the display
        angle_reading = pot_read(IMAGE_ANGLE_CHAN);
        angle_reading = angle_reading * 192 / 255;
        angle_reading = 192 - angle_reading;
        if(diff(angle_reading, image_angle) > POT_CHANGE_WINDOW) {
            image_angle = angle_reading;
            send_command(0x01, image_angle);            
        }
        
        //read the scroll speed pot; if there's
        //been a significant change send a command to the display   
        scroll_reading = pot_read(SCROLL_SPEED_CHAN);
        if(diff(scroll_reading, scroll_speed) > POT_CHANGE_WINDOW) {
            scroll_speed = scroll_reading;
            send_command(0x02, scroll_speed);
        }
        
        //check the button state; if it's been pressed read the message number
        //pot and send a command to the display to show the corresponding
        //builtin message
        button_reading = (pot_read(MESSAGE_BUTTON_CHAN) > 128 ? 1 : 0);
        if(button_reading == 1 && button_state == 0) {
            if(button_cooldown_counter == 0) {
                message_reading = pot_read(MESSAGE_NUM_CHAN);
                message_reading = interpret_message_reading(message_reading);
                output_d(message_reading);
                send_command(0x03, message_reading);
                button_cooldown_counter = MESSAGE_BUTTON_COOLDOWN;
            }
        }
        button_state = button_reading;
        if(button_cooldown_counter != 0) button_cooldown_counter -= 1; 
            
            
        
        delay_ms(1);
    }
}