// File: curlycrt.c // // This is the control program for the CurlyCart, which is a // modified Fisher-Price Power Wheels ride-on toy. // The program is meant for a PIC 16F874 microcontroller. // This program uses I2C to interface with a Microchip // 256Kbit Serial EEPROM, which stores movements and allows them // to be retrieved later. // // For full details of the CurlyCart, refer to: // http://www.media.mit.edu/~spiegel/CurlyCart // // Matthew Lee // mattlee@media.mit.edu // March 7, 2001 // // Program written by Matthew Lee and Adam Smith // #include <16F874.H> // Configure PIC to use: HS clock, Watchdog Timer, // no code protection, enable Power Up Timer // #fuses HS,NOWDT,NOPROTECT,PUT,NOBROWNOUT // Tell compiler clock is 10MHz. This is required for delay_ms() // and for all serial I/O (such as printf(...). These functions // use software delay loops, so the compiler needs to know the // processor speed. // #use DELAY(clock=10000000) // Declare that we'll manually establish the data direction of // each I/O pin on port B. // #use fast_io(A) #use fast_io(B) #use fast_io(D) #use fast_io(E) // definitions for the curly cart // #define MOTORLEFT_FWD PIN_B1 #define MOTORLEFT_REV PIN_E1 #define MOTORRIGHT_FWD PIN_B0 #define MOTORRIGHT_REV PIN_B4 #define STICKLEFT_FWD PIN_A1 #define STICKLEFT_REV PIN_A2 #define STICKRIGHT_FWD PIN_A3 #define STICKRIGHT_REV PIN_A4 #define GAS_PEDAL PIN_A5 #define MODE_BUTTON PIN_E0 #define SERIALRAM_CLK PIN_C6 #define SERIALRAM_DATA PIN_C7 #define RED_LED PIN_B5 #define RECORD_LED PIN_B6 #define PLAY_LED PIN_B7 // Macros to simplify I/O operations // #define RED_LED_ON output_low(RED_LED) #define RED_LED_OFF output_high(RED_LED) #define RECORD_LED_ON output_high(RECORD_LED) #define RECORD_LED_OFF output_low(RECORD_LED) #define PLAY_LED_ON output_high(PLAY_LED) #define PLAY_LED_OFF output_low(PLAY_LED) // state defines for the three run states // #define STATE_NORMAL 0 #define STATE_RECORD 1 #define STATE_PLAYBACK 2 #define MAX_SAMPLES 65535 // Default tri-state port direction bits: all PORT B bits are // output except for IR_SENSOR (bit 4) and RC232_RCV (bit 5). // #define IRX_A_TRIS 0b11111110 #define IRX_B_TRIS 0b00000000 #define IRX_D_TRIS 0b00000000 #define IRX_E_TRIS 0b00000001 int debounce; byte curlyState = STATE_NORMAL; long sampleCount = 0; long currentSample = 0; #inline void left_motor_stop(void) { output_low(MOTORLEFT_FWD); output_low(MOTORLEFT_REV); } #inline void left_motor_fwd(void) { output_low(MOTORLEFT_REV); output_high(MOTORLEFT_FWD); } #inline void left_motor_rev(void) { output_low(MOTORLEFT_FWD); output_high(MOTORLEFT_REV); } #inline void right_motor_stop(void) { output_low(MOTORRIGHT_FWD); output_low(MOTORRIGHT_REV); } #inline void right_motor_fwd(void) { output_low(MOTORRIGHT_REV); output_high(MOTORRIGHT_FWD); } #inline void right_motor_rev(void) { output_low(MOTORRIGHT_FWD); output_high(MOTORRIGHT_REV); } void all_off(void) { left_motor_stop(); right_motor_stop(); RED_LED_OFF; RECORD_LED_OFF; PLAY_LED_OFF; } byte get_stick_positions(void) { byte result; /* if (!input(GAS_PEDAL)) { return 0; } */ result = 0xF0; if (input(STICKLEFT_FWD)) result += 0x01; else if (input(STICKLEFT_REV)) result += 0x02; if (input(STICKRIGHT_FWD)) result += 0x04; else if (input(STICKRIGHT_REV)) result += 0x08; return result; } void perform_motor_actions(byte input) { /* if (!input(GAS_PEDAL)) { left_motor_stop(); right_motor_stop(); return; } */ if (input & 0x01) { left_motor_fwd(); } else if (input & 0x02) { left_motor_rev(); } else { left_motor_stop(); } if (input & 0x04) { right_motor_fwd(); } else if (input & 0x08) { right_motor_rev(); } else { right_motor_stop(); } } #use i2c(MASTER, SDA=SERIALRAM_DATA, SCL=SERIALRAM_CLK, FORCE_SW) void init_ram() { output_high(SERIALRAM_DATA); output_high(SERIALRAM_CLK); } void write_ram(long address, byte data) { byte b; i2c_start(); i2c_write(0b10100000); b = (byte)((address >> 8) & 0xFF); i2c_write(b); b = (byte)(address & 0xFF); i2c_write(b); i2c_write(data); i2c_stop(); } void write_ram_old(byte addresshi, byte addresslo, byte data) { i2c_start(); i2c_write(0b10100000); i2c_write(addresshi); i2c_write(addresslo); i2c_write(data); i2c_stop(); } byte read_ram(long address) { byte data; byte b; i2c_start(); i2c_write(0b10100000); b = (byte)((address >> 8) & 0xFF); i2c_write(b); b = (byte)(address & 0xFF); i2c_write(b); i2c_start(); i2c_write(0b10100001); data=i2c_read(); i2c_stop(); return(data); } #inline void check_mode_button() { if (debounce > 0) { debounce--; return; } if (input(MODE_BUTTON)) { delay_ms(50); while(input(MODE_BUTTON)) { delay_ms(10); } debounce = 10; curlyState++; if (curlyState > STATE_PLAYBACK) curlyState = STATE_NORMAL; if (curlyState == STATE_RECORD) { sampleCount = 0; currentSample = 0; } else if (curlyState == STATE_PLAYBACK) { currentSample = 0; } } } void display_mode_indicators() { if (curlyState == STATE_NORMAL) { RECORD_LED_OFF; PLAY_LED_OFF; } else if (curlyState == STATE_RECORD) { RECORD_LED_ON; PLAY_LED_OFF; } else if (curlyState == STATE_PLAYBACK) { RECORD_LED_OFF; PLAY_LED_ON; } } void main() { byte inputbyte; byte heartbeat; // since we've declared #use fast_io(B) (above), we MUST // include a call to set_tris_b() at startup. // set_tris_a(IRX_A_TRIS); set_tris_b(IRX_B_TRIS); set_tris_d(IRX_D_TRIS); set_tris_e(IRX_E_TRIS); setup_port_a(NO_ANALOGS); port_b_pullups(TRUE); all_off(); RED_LED_ON; // reality check at startup RECORD_LED_ON; PLAY_LED_ON; left_motor_fwd(); delay_ms(250); left_motor_rev(); delay_ms(250); left_motor_stop(); right_motor_fwd(); delay_ms(250); right_motor_rev(); delay_ms(250); right_motor_stop(); RED_LED_OFF; RECORD_LED_OFF; PLAY_LED_OFF; delay_ms(500); init_ram(); while (1) { check_mode_button(); display_mode_indicators(); inputbyte = get_stick_positions(); if (curlyState == STATE_NORMAL) { perform_motor_actions(inputbyte); } else if (curlyState == STATE_RECORD) { perform_motor_actions(inputbyte); write_ram(sampleCount, inputbyte); sampleCount++; if (sampleCount >= MAX_SAMPLES) { curlyState = STATE_PLAYBACK; currentSample = 0; } } else if (curlyState == STATE_PLAYBACK) { inputbyte = read_ram(currentSample); if ((inputbyte & 0xF0) == 0xF0) perform_motor_actions(inputbyte); currentSample++; if (currentSample >= sampleCount) currentSample = 0; } if (heartbeat == 0) { RED_LED_ON; heartbeat = 1; } else { RED_LED_OFF; heartbeat = 0; } delay_ms(50); } }