/********************************************************/ /*** ***/ /*** 12f1840 ***/ /*** _____ ***/ /*** Vdd [ ] GND ***/ /*** OLED SCK - RA5 [ ] RA0 - TL sw / PGD ***/ /*** OLED SDA - RA4 [ ] RA1 - BL sw / PGD ***/ /*** MCLR - RA3 [_____] RA2 - BR sw ***/ /*** ***/ /********************************************************/ // Source code for PongWatch written by Andrew M Hannay June 2015 // Compiled on MPLABX #include // PIC12F1840 Configuration Bit Settings // 'C' source line config statements #include // #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF. // CONFIG1 #pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin) #pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled) #pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input) #pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled) #pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled) #pragma config BOREN = OFF // Brown-out Reset Enable (Brown-out Reset disabled) #pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin) #pragma config IESO = OFF // Internal/External Switchover (Internal/External Switchover mode is disabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled) // CONFIG2 #pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off) #pragma config PLLEN = OFF // PLL Enable (4x PLL disabled) #pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset) #pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.) #pragma config LVP = ON // Low-Voltage Programming Enable (Low-voltage programming enabled) // Define CPU Frequency #define _XTAL_FREQ 16000000 // Hz #define FALSE 0 #define TRUE !FALSE // Define i2c pins #define SDA LATA4 // Data pin for i2c #define SCK LATA5 // Clock pin for i2c #define SDA_DIR TRISA4 // Data pin direction #define SCK_DIR TRISA5 // Clock pin direction #define DataPinADCMask ANS3 // It is attached on GP4(AN3) pin // Define macros #define Set_SDA_Low SDA_DIR = 0 #define Set_SDA_High SDA_DIR = 1 #define Set_SCK_Low SCK_DIR = 0 #define Set_SCK_High SCK_DIR = 1 #define OL_C 0x00 #define OL_D 0x40 #define OFFSET 0 #define SHORTD 10 #define GAMED 10 #define LONGD 30 #define TIMEMODE 0 #define TESTMODE 1 #define HRSADJUST 2 #define MINSADJUST 3 #define tp 0x0f // 00001111 #define tm 0x3f // 00111111 #define md 0x3c // 00111100 #define bm 0xfc // 11111100 #define bt 0xf0 // 11110000 #define fl 0xff // 11111111 #define nn 0x00 // 00000000 static const unsigned char BIG[][9] = { {fl,tp,fl,fl,nn,fl,fl,bt,fl} // 0 ,{nn,fl,nn,nn,fl,nn,nn,fl,nn} // 1 ,{tp,tp,fl,bm,md,tm,fl,bt,bt} // 2 ,{tp,tp,fl,md,md,fl,bt,bt,fl} // 3 ,{fl,nn,fl,tm,md,fl,nn,nn,fl} // 4 ,{fl,tp,tp,tm,md,bm,bt,bt,fl} // 5 ,{fl,tp,tp,fl,md,bm,fl,bt,fl} // 6 ,{tp,tp,fl,nn,nn,fl,nn,nn,fl} // 7 ,{fl,tp,fl,fl,md,fl,fl,bt,fl} // 8 ,{fl,tp,fl,tm,md,fl,bt,bt,fl} // 9 }; static const unsigned char COLON[][10] = { {nn,nn,nn,bt,bt,bt,bt,nn,nn,nn} ,{nn,nn,nn,nn,nn,nn,nn,nn,nn,nn} ,{nn,nn,nn,tp,tp,tp,tp,nn,nn,nn} ,{nn,nn,nn,bt,bt,bt,bt,nn,nn,nn} ,{nn,nn,nn,nn,nn,nn,nn,nn,nn,nn} ,{nn,nn,nn,tp,tp,tp,tp,nn,nn,nn} ,{nn,nn,nn,bt,bt,bt,bt,nn,nn,nn} ,{nn,nn,nn,nn,nn,nn,nn,nn,nn,nn} }; //Function Declarations void DrawScore(unsigned char score1, unsigned char score2); void ReDrawline(unsigned char line, unsigned char score1, unsigned char score2); void Drawline(unsigned char line, unsigned char score1, unsigned char score2); void DrawNet(void); void DrawBall(unsigned char draw, unsigned char xcoord, unsigned char ycoord); void DrawBat1(unsigned char draw, unsigned char ycoord, signed char dir); void DrawBat2(unsigned char draw, unsigned char ycoord, signed char dir); void OLFill(unsigned char data); void i2c_write(unsigned char* i2c_data, int DataSz); void OLWriteByte(unsigned char dc, unsigned char data); void OLWriteData(unsigned char data, unsigned char length); void OLInitialise(void); void InitI2C(void); void I2C_Start(void); void I2C_Stop(void); void I2C_Write_Byte(unsigned char); /* Pin configuration * * PORTA4 = SDA pin for i2c * PORTA5 = SCK pin for i2c */ unsigned char counter; unsigned char tick; unsigned char watchmode; main() { signed char ballx; signed char bally; signed char dirx; signed char diry; signed char bat1; signed char bat2; signed char bat1dir; signed char bat2dir; unsigned char miss; unsigned char count1sec; unsigned char hours; unsigned char minutes; unsigned char seconds; unsigned char Score1; unsigned char Score2; unsigned char RA0count; unsigned char RA1count; unsigned char RA2count; bat1 = 3; bat2 = 3; bat1dir = 0; bat2dir = 0; ballx = 0; bally = 0; dirx = 0; diry = 0; miss = TRUE; hours = 19; minutes = 17; seconds = 0; count1sec = 0; RA0count = 0; RA1count = 0; RA2count = 0; watchmode = TIMEMODE; CLRWDT(); //clear watchdog __delay_ms(100); //OSCCON = 0x6a; //01101010 4MHz //OSCCON = 0x72; //01110010 8MHz OSCCON = 0x7a; //01111010 16MHz //OSCCON = 0xf0; //11110000 32MHz //APFCON = 0x00; //Alternate Pin Config Register //FVRCON = 0x00; //00000000 //SSP1CON1 = 0x00; //PSTR1CON = 0x00; //ADCON0 = 0x00; //00000000 OPTION_REG = 0x0f; ANSELA = 0x00; //00000000 WPUA = 0x0f; TRISA = 0x3f; //00111111 LATA = 0x00; //00000000 //TMR0IE = 1; // Enable interrupt on TMR0 overflow T2CON = 0x4f; //01001111 TMR2 = 0; PR2 = 124; //20ms interrupt TMR2IE = 1; GIE = 1; // Global interrupt enable PEIE = 1; //peripheral interrupt enable InitI2C(); __delay_ms(100); OLInitialise(); __delay_ms(100); OLFill(0x00); DrawBat1(0xff,bat1,0); DrawBat2(0xff,bat2,0); Score1 = hours; Score2 = minutes; DrawScore(Score1, Score2); DrawNet(); while(1) { if(tick == TRUE) { tick = FALSE; if (watchmode < HRSADJUST) { //Update Clock count1sec++; if (count1sec == 10) //1 second { count1sec = 0; seconds++; if (watchmode == TIMEMODE) { if (seconds == 1) { miss = FALSE; if (minutes == 59) { ballx = 0; bally = bat1; dirx = 1; diry = 1; } else { ballx = 15; bally = bat2; dirx = -1; diry = 1; } } if (seconds == 59) { miss = TRUE; } } if (seconds == 60) //1 minute { seconds = 0; minutes++; if (minutes == 60) //1 hour { minutes = 0; hours++; if (hours == 24) //1 day (24 hours) { hours = 0; } } if (watchmode == TIMEMODE) { Score1 = hours; Score2 = minutes; DrawScore(Score1, Score2); } } } } else { count1sec = 0; seconds = 0; } //Read switches if (RA0 == 1) RA0count = 0; if (RA1 == 1) RA1count = 0; if (RA2 == 1) RA2count = 0; if ((RA0count < 128) && (RA0 == 0)) RA0count++; if ((RA1count < 128) && (RA1 == 0)) RA1count++; if ((RA2count < 128) && (RA2 == 0)) RA2count++; bat1dir = 0; bat2dir = 0; if ((RA0count == 1) || (RA0count == SHORTD)) { if (watchmode == HRSADJUST) { hours++; if (hours == 24) hours = 0; Score1 = hours; DrawScore(Score1, Score2); } else if (watchmode == MINSADJUST) { minutes++; if (minutes == 60) minutes = 0; Score2 = minutes; DrawScore(Score1, Score2); } if (RA0count == SHORTD) RA0count = SHORTD-1; } if ((RA1count == 1) || (RA1count == SHORTD)) { if (watchmode == HRSADJUST) { hours--; if (hours == 0xff) hours = 23; Score1 = hours; DrawScore(Score1, Score2); } else if (watchmode == MINSADJUST) { minutes--; if (minutes == 0xff) minutes = 59; Score2 = minutes; DrawScore(Score1, Score2); } if (RA1count == SHORTD) RA1count = SHORTD-1; } if (RA2count == 1) { if (watchmode == HRSADJUST) watchmode = MINSADJUST; //adjust minutes else watchmode = TIMEMODE; //time adjust off Score1 = hours; Score2 = minutes; DrawScore(Score1, Score2); RA2count = 128; } if (RA2count == LONGD) { if (watchmode < HRSADJUST) watchmode = HRSADJUST; //adjust hours Score1 = hours; Score2 = minutes; DrawScore(Score1, Score2); miss = TRUE; RA2count = 128; } DrawBall(0x00,ballx*8,bally);//remove old ball if ((bally < 3) && ((ballx > 2) && (ballx < 13))) ReDrawline(bally, Score1, Score2); else if ((bally > 2) && ((ballx > 6) && (ballx < 9))) DrawNet(); ballx = ballx + dirx; bally = bally + diry; if (dirx != 0) DrawBall(0xff,ballx*8,bally);//draw new ball if (watchmode == TIMEMODE) { if ((ballx < 8) && (dirx < 0)) { if (miss == FALSE) { if ((bat1 < bally) && (bat1 < 6)) bat1dir = 1; else if ((bat1 > bally) && (bat1 > 1)) bat1dir = -1; } else if (bat1 < 6) bat1dir = 1; } else { if (bat1 < 3) bat1dir = 1; else if (bat1 > 4) bat1dir = -1; } } bat1 = bat1 + bat1dir; DrawBat1(0xff,bat1,bat1dir); if ((ballx > 7) && (dirx > 0)) { if (miss == FALSE) { if ((bat2 < bally) && (bat2 < 6)) bat2dir = 1; else if ((bat2 > bally) && (bat2 > 1)) bat2dir = -1; } else if (bat2 < 6) bat2dir = 1; } else { if (bat2 < 3) bat2dir = 1; else if (bat2 > 4) bat2dir = -1; } bat2 = bat2 + bat2dir; DrawBat2(0xff,bat2,bat2dir); if (bally == 0) diry = 1; if (bally == 7) diry = -1; if (miss == FALSE) { if (ballx == 1) dirx = 1; if (ballx == 14) dirx = -1; } else { if((ballx == 0) || (ballx == 15)) { dirx = 0; diry = 0; } } //LATA2 = ~LATA2; } } } static void interrupt isr(void) //20ms interrupt { //LATA1 = ~LATA1; if (++counter >= 5) //20ms x 5 = 100ms { //LATA0 = ~LATA0; counter = 0; tick = TRUE; } TMR2IF = 0; } #define SIZE 5 //0x05 void DrawScore(unsigned char score1, unsigned char score2) { unsigned char line; for (line = 0; line < 3; line++) { OLWriteByte(OL_C, 0x08 + OFFSET); //24 = 0x18 0x08 0x11 OLWriteByte(OL_C, 0x11); OLWriteByte(OL_C, line | 0xb0); I2C_Start(); //Send the Start Bit I2C_Write_Byte(0x78); //write address and write I2C_Write_Byte(0x40); //write data flag Drawline(line, score1, score2); I2C_Stop();//Send the Stop condition } } void ReDrawline(unsigned char line, unsigned char score1, unsigned char score2) { OLWriteByte(OL_C, 0x08 + OFFSET); //24 = 0x18 0x08 0x11 OLWriteByte(OL_C, 0x11); OLWriteByte(OL_C, line | 0xb0); I2C_Start(); //Send the Start Bit I2C_Write_Byte(0x78); //write address and write I2C_Write_Byte(0x40); //write data flag Drawline(line, score1, score2); I2C_Stop();//Send the Stop condition } void Drawline(unsigned char line, unsigned char score1, unsigned char score2) { unsigned char index; unsigned char sizec; unsigned char number; unsigned char mask; unsigned char num[4]; num[0] = score1/10; num[1] = score1%10; num[2] = score2/10; num[3] = score2%10; for (number = 0; number < 4; number++) { mask = 0xff; //mask for time adjust indicator if (((watchmode == MINSADJUST) && (number < 2)) || ((watchmode == HRSADJUST) && (number > 1))) mask = 0x55; for(index = 0; index < 3; index++) { for (sizec = 0; sizec < SIZE; sizec++) { I2C_Write_Byte((BIG[num[number]][index + line*3]) & mask); } } if ((number == 0) || (number == 2)) //small gap { for (sizec = 0; sizec < 5; sizec++) { I2C_Write_Byte(0); } } else if (number == 1) //large gap { for (sizec = 0; sizec < 10; sizec++) { I2C_Write_Byte(COLON[line][sizec]); } } } } #define NETX 62 + OFFSET void DrawNet(void) { OLWriteByte(OL_C, NETX & 0x0f); OLWriteByte(OL_C, (NETX >> 4) | 0x10); OLWriteByte(OL_C, 0xb3); OLWriteData(bt, 4); OLWriteByte(OL_C, NETX & 0x0f); OLWriteByte(OL_C, (NETX >> 4) | 0x10); OLWriteByte(OL_C, 0xb5); OLWriteData(tp, 4); OLWriteByte(OL_C, NETX & 0x0f); OLWriteByte(OL_C, (NETX >> 4) | 0x10); OLWriteByte(OL_C, 0xb6); OLWriteData(bt, 4); } void DrawBall(unsigned char draw, unsigned char xcoord, unsigned char ycoord) { xcoord = xcoord + OFFSET; OLWriteByte(OL_C, xcoord & 0x0f); OLWriteByte(OL_C, (xcoord >> 4) | 0x10); OLWriteByte(OL_C, ycoord | 0xb0); OLWriteData(draw, 8); } void DrawBat1(unsigned char draw, unsigned char ycoord, signed char dir) { if (dir < 0) { OLWriteByte(OL_C, 0x00 + OFFSET); OLWriteByte(OL_C, 0x10); OLWriteByte(OL_C, ycoord-1 | 0xb0); OLWriteData(draw, 8); OLWriteByte(OL_C, 0x00 + OFFSET); OLWriteByte(OL_C, 0x10); OLWriteByte(OL_C, ycoord+2 | 0xb0); OLWriteData(0, 8); } else if (dir > 0) { OLWriteByte(OL_C, 0x00 + OFFSET); OLWriteByte(OL_C, 0x10); OLWriteByte(OL_C, ycoord+1 | 0xb0); OLWriteData(draw, 8); OLWriteByte(OL_C, 0x00 + OFFSET); OLWriteByte(OL_C, 0x10); OLWriteByte(OL_C, ycoord-2 | 0xb0); OLWriteData(0, 8); } else { OLWriteByte(OL_C, 0x00 + OFFSET); OLWriteByte(OL_C, 0x10); OLWriteByte(OL_C, ycoord-1 | 0xb0); OLWriteData(draw, 8); OLWriteByte(OL_C, 0x00 + OFFSET); OLWriteByte(OL_C, 0x10); OLWriteByte(OL_C, ycoord | 0xb0); OLWriteData(draw, 8); OLWriteByte(OL_C, 0x00 + OFFSET); OLWriteByte(OL_C, 0x10); OLWriteByte(OL_C, ycoord+1 | 0xb0); OLWriteData(draw, 8); } } void DrawBat2(unsigned char draw, unsigned char ycoord, signed char dir) { if (dir < 0) { OLWriteByte(OL_C, 0x08 + OFFSET); OLWriteByte(OL_C, 0x17); OLWriteByte(OL_C, ycoord-1 | 0xb0); OLWriteData(draw, 8); OLWriteByte(OL_C, 0x08 + OFFSET); OLWriteByte(OL_C, 0x17); OLWriteByte(OL_C, ycoord+2 | 0xb0); OLWriteData(0, 8); } else if (dir > 0) { OLWriteByte(OL_C, 0x08 + OFFSET); OLWriteByte(OL_C, 0x17); OLWriteByte(OL_C, ycoord+1 | 0xb0); OLWriteData(draw, 8); OLWriteByte(OL_C, 0x08 + OFFSET); OLWriteByte(OL_C, 0x17); OLWriteByte(OL_C, ycoord-2 | 0xb0); OLWriteData(0, 8); } else { OLWriteByte(OL_C, 0x08 + OFFSET); OLWriteByte(OL_C, 0x17); OLWriteByte(OL_C, ycoord-1 | 0xb0); OLWriteData(draw, 8); OLWriteByte(OL_C, 0x08 + OFFSET); OLWriteByte(OL_C, 0x17); OLWriteByte(OL_C, ycoord | 0xb0); OLWriteData(draw, 8); OLWriteByte(OL_C, 0x08 + OFFSET); OLWriteByte(OL_C, 0x17); OLWriteByte(OL_C, ycoord+1 | 0xb0); OLWriteData(draw, 8); } } void OLFill(unsigned char data) { unsigned char col; unsigned char line; for (line = 0; line < 8; line++) { OLWriteByte(OL_C, line | 0xb0); OLWriteByte(OL_C, 0x00); OLWriteByte(OL_C, 0x10); I2C_Start(); //Send the Start Bit I2C_Write_Byte(0x78); //write address and write I2C_Write_Byte(0x40); //write data flag for(col=0;col<128 + OFFSET + OFFSET;col++) { I2C_Write_Byte(data); } I2C_Stop();//Send the Stop condition } } void i2c_write(unsigned char* i2c_data, int DataSz) { I2C_Start();//Send the Start Bit while( DataSz ) { I2C_Write_Byte(*i2c_data++); DataSz--; } I2C_Stop();//Send the Stop condition } void OLWriteByte(unsigned char dc, unsigned char data) { //write = 0, read = 1 char i2cData[3]; i2cData[0] = 0x78; //slave address of display, write i2cData[1] = 0x80 | dc; i2cData[2] = data; i2c_write(i2cData, 3); } void OLWriteData(unsigned char data, unsigned char length) { unsigned char n; I2C_Start(); //Send the Start Bit I2C_Write_Byte(0x78); //write address and write I2C_Write_Byte(0x40); //write data flag for(n=0;n