/********************************************************/
/*** ***/
/*** 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 <htc.h>
// PIC12F1840 Configuration Bit Settings
// 'C' source line config statements
#include <xc.h>
// #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<length;n++)
{
I2C_Write_Byte(data);
}
I2C_Stop();//Send the Stop condition
}
void OLInitialise(void)
{
//command = 0, data =1
OLWriteByte(OL_C,0xaf); //display on
//OLWriteByte(OL_C,0xae); //display off
OLWriteByte(OL_C,0xa8); // set multiplex ratio
OLWriteByte(OL_C,0x3f); // multiplex ratio = 64MUX
//OLWriteByte(OL_C,0xd3); // set display offset
//OLWriteByte(OL_C,0x00); // display offset = 0 (no vertical shift)
OLWriteByte(OL_C,0x40); // set display start line to 0
OLWriteByte(OL_C,0xa1); // set segment re-map to invert horizontally
OLWriteByte(OL_C,0xc8); // set COM scan direction to invert vertically
OLWriteByte(OL_C,0xda); // set COM pins hardware configuration
OLWriteByte(OL_C,0x12); // COM pins hardware configuration = alternative, no left/right remap
OLWriteByte(OL_C,0x81); // set contrast
OLWriteByte(OL_C,0xbf); // contrast = 75%
OLWriteByte(OL_C,0xa4); // disable entire display on
OLWriteByte(OL_C,0xa6); // set normal display
OLWriteByte(OL_C,0xb0); // set page address
OLWriteByte(OL_C,0xd5); // set oscillator frequency
OLWriteByte(OL_C,0x80); // oscillator frequency = default
OLWriteByte(OL_C,0x8d); // set charge pump
OLWriteByte(OL_C,0x14); // charge pump = on
//OLWriteByte(OL_C,0x20); // set memory addressing mode
//OLWriteByte(OL_C,0x00); // memory addressing mode page
//OLWriteByte(OL_C,0x21); // Column address (Set up 128x64) display
//OLWriteByte(OL_C,0x00); // Column start
//OLWriteByte(OL_C,0x7f); // Column end
//OLWriteByte(OL_C,0x22); // Row address
//OLWriteByte(OL_C,0x00); // Row start
//OLWriteByte(OL_C,0x07); // Row end
//OLWriteByte(OL_C,0x20); // set memory addressing mode
//OLWriteByte(OL_C,0x02); // memory addressing mode page
}
// Function Purpose: Set initial values of SCK and SDA pins
void InitI2C(void)
{
//DataPinADCMask = 1; // Make analog output
// Make SDA and SCK pins input initially
SDA_DIR = 1;
SCK_DIR = 1;
// Write zero in output register of SDA and SCK pin
SDA = 0;
SCK = 0;
}
// Function Purpose: I2C_Start sends start bit sequence
void I2C_Start(void)
{
SDA = 0; // Write zero in output register
SCK = 0; // of SDA and SCK pin
Set_SCK_High; // Make SCK pin high
Set_SDA_High; // Make SDA pin High
Set_SDA_Low; // Make SDA Low
}
//Function : I2C_Stop sends stop bit sequence
void I2C_Stop(void)
{
Set_SCK_Low; // Make SCK pin low
Set_SDA_Low; // Make SDA pin low
Set_SCK_High; // Make SCK pin high
Set_SDA_High; // Make SDA high
}
// Function Purpose: I2C_Write_Byte transfers one byte
void I2C_Write_Byte(unsigned char Byte)
{
static bit ACK = 0;
unsigned char i; // Variable to be used in for loop
for(i=0;i<8;i++) // Repeat for every bit
{
Set_SCK_Low; // Make SCK pin low
if((Byte<<i)&0x80) // Place data bit value on SDA pin
Set_SDA_High; // If bit is high, make SDA high
else // Data is transferred MSB first
Set_SDA_Low; // If bit is low, make SDA low
Set_SCK_High; // So that slave can
}
// Get ACK from slave
Set_SCK_Low;
Set_SDA_High;
Set_SCK_High;
}
Comments
Please log in or sign up to comment.