// Pic Perpetual Calendar Date Controller // // PIC16F628A // // Pin connections // // RA0 (17) out SCL // RA1 (18) out SDA8 // RA2 (1) out SDA9 // RA3 (2) out SDA10 // RA4 (3) open // RA5 (4) out to master // RA6 (15) out SDA2 // RA7 (16) open // RB0 (6) out SDA1 // RB1 (7) in Serial from master // RB2 (8) out TX // RB3 (9) out SDA3 // RB4 (10) out SDA4 // RB5 (11) out SDA5 // RB6 (12) out SDA6 // RB7 (13) out SDA7 // data direction registers 1=input 0=out // trisa = 00110000 0x00 // trisb = 01111000 0x02 // // #include #include #pragma CLOCK_FREQ 4000000 #pragma DATA _CONFIG , _INTOSC_OSC_NOCLKOUT & _WDT_OFF & _LVP_OFF &_MCLRE_OFF & _BODEN_OFF unsigned char bright[37]; // 0 for normal >0 for bright // i2c connection routines, have these next 5 call bit and delay routines void sda_high(unsigned char a) { switch(a) { case 1: set_bit( portb, 0 ); break; case 2: set_bit( porta, 6 ); break; case 3: set_bit( portb, 3 ); break; case 4: set_bit( portb, 4 ); break; case 5: set_bit( portb, 5 ); break; case 6: set_bit( portb, 6 ); break; case 7: set_bit( portb, 7 ); break; case 8: set_bit( porta, 1 ); break; case 9: set_bit( porta, 2 ); break; case 10: set_bit( porta, 3 ); break; default: break; } } void sda_low(unsigned char a) { switch(a) { case 1: clear_bit( portb, 0 ); break; case 2: clear_bit( porta, 6 ); break; case 3: clear_bit( portb, 3 ); break; case 4: clear_bit( portb, 4 ); break; case 5: clear_bit( portb, 5 ); break; case 6: clear_bit( portb, 6 ); break; case 7: clear_bit( portb, 7 ); break; case 8: clear_bit( porta, 1 ); break; case 9: clear_bit( porta, 2 ); break; case 10: clear_bit( porta, 3 ); break; default: break; } } void scl_high(void) { set_bit( porta, 0 ); } void scl_low(void) { clear_bit( porta, 0 ); } void i2c_delay() { delay_us(5); } // i2c routines void i2c_start(void) { unsigned char i; scl_high(); for(i=1;i<11;i++) { sda_high(i); } i2c_delay(); for(i=1;i<11;i++) { sda_low(i); } i2c_delay(); scl_low(); i2c_delay(); } void i2c_stop(void) { unsigned char i; for(i=1;i<11;i++) { sda_low(i); } scl_low(); i2c_delay(); scl_high(); i2c_delay(); for(i=1;i<11;i++) { sda_high(i); } i2c_delay(); } // bit out // takes one bit from each byte in listof 10 void i2c_bitsout(unsigned char data[],unsigned char bitnum) { unsigned int d; unsigned char i; // extract bit from array for (i=0;i<10;i++) { if ((data[i]>>bitnum)&1) sda_high(i+1); else sda_low(i+1); } // pulse clock i2c_delay(); scl_high(); i2c_delay(); scl_low(); i2c_delay(); } void i2c_ack() { i2c_delay(); scl_high(); i2c_delay(); scl_low(); i2c_delay(); } // // send ten bytes to displays // void i2c_byteout(unsigned char data[]) { unsigned char i; for(i=0;i<8;i++) i2c_bitsout(data,7-i); // send bit n of each int i2c_ack(); // ack cycle } // // send 10 pairs of bytes (segment data) to an address // add = 0-3 // void show_array(unsigned int data[],unsigned char add,unsigned char bb[]) { unsigned char line[10]; unsigned char i; switch(add) { case 0: add=0x70; break; case 1: add=0x72; break; case 2: add=0x74; break; default: add=0x76; break; } i2c_start(); // for(i=0;i<10;i++) line[i]=add; // address i2c_byteout(line); // for(i=0;i<10;i++) i2c_delay(); // for(i=0;i<10;i++) line[i]=0x00; // instruction i2c_byteout(line); // for(i=0;i<10;i++) i2c_delay(); // for(i=0;i<10;i++) { #define GREEN_LEDS 1 //#define RED_LEDS 1 #ifdef RED_LEDS if(bb[i]>0) line[i]=0x46; // control !bright! else line[i]=0x16; // control normal #endif #ifdef GREEN_LEDS if(bb[i]>0) line[i]=0x76; // control !bright! else line[i]=0x26; // control normal #endif } i2c_byteout(line); // for(i=0;i<10;i++) i2c_delay(); // for(i=0;i<10;i++) line[i]=data[i]&0xff; // low bytes i2c_byteout(line); // for(i=0;i<10;i++) i2c_delay(); // for(i=0;i<10;i++) line[i]=data[i]>>8; // high bytes i2c_byteout(line); // i2c_stop(); } // // high and low bytes for 7 segment displays // rom unsigned char *segments ={ 189 , 175 , 17 , 33 , 229 , 230 , 241 , 227 , 89 , 105 , 248 , 203 , 252 , 207 , 49 , 35 , 253 , 239 , 249 , 235 , 0 , 0 }; unsigned int getsegs(unsigned char left,unsigned char right) { unsigned int segs,l,r; unsigned char i; // get left segs i=left; if(i>9) i=10; i=i*2; l=segments[i]; // get right segs i=right; if(i>9) i=10; i=i*2; r=segments[i+1]; segs= ((l&0xf0)<<8)|((r&0xf0)<<4)|((l&0xf)<<4)|((r&0xf)); return(segs); } // // position mapping // rom unsigned char *mappings ={ // mapping SAA1064 address to cal address 14,7,0,6,21,34,30,5,4,28, // address 0 15,8,1,13,22,99,31,12,11,29, // address 1 16,9,2,20,23,99,32,19,18,35, // address 2 17,10,3,27,24,99,33,26,25,36, // address 3 }; // // // void showall(unsigned char d[]) { unsigned char i; unsigned char p; // pointer unsigned char n; // number to display unsigned char z; // upper digit unsigned int dispbits[10]; unsigned char hl[10]; // show first 10 at address 0 for(i=0;i<10;i++) { p=mappings[i]; if(p<37) { n=d[p]; hl[i]=bright[p]; } else { n=100; hl[i]=0; } if (n<100) { z=n/10; dispbits[i]=getsegs(z,n%10); if((n!=0)&&(z==0)) dispbits[i]=dispbits[i]&0x0f0f; } else dispbits[i]=0; } show_array(dispbits,0,hl); // show 10 at address 1 for(i=0;i<10;i++) { p=mappings[i+10]; if(p<37) { n=d[p]; hl[i]=bright[p]; } else { n=100; hl[i]=0; } if (n<100) { z=n/10; dispbits[i]=getsegs(z,n%10); if((n!=0)&&(z==0)) dispbits[i]=dispbits[i]&0x0f0f; } else dispbits[i]=0; } show_array(dispbits,1,hl); // show 10 at address 2 for(i=0;i<10;i++) { p=mappings[i+20]; if(p<37) { n=d[p]; hl[i]=bright[p]; } else { n=100; hl[i]=0; } if (n<100) { z=n/10; dispbits[i]=getsegs(z,n%10); if((n!=0)&&(z==0)) dispbits[i]=dispbits[i]&0x0f0f; } else dispbits[i]=0; } show_array(dispbits,2,hl); // show 10 at address 3 for(i=0;i<10;i++) { p=mappings[i+30]; if(p<37) { n=d[p]; hl[i]=bright[p]; } else { n=100; hl[i]=0; } if (n<100) { z=n/10; dispbits[i]=getsegs(z,n%10); if((n!=0)&&(z==0)) dispbits[i]=dispbits[i]&0x0f0f; } else dispbits[i]=0; } show_array(dispbits,3,hl); } // // receive from serial, returns 0 if no data, 0x01nn if nn has been received // unsigned int getbyte() { unsigned int rv; // check and clear error flag if set; if(rcsta.1) { rcsta = 0x80; rcsta = 0x90; rv=rcreg; rv=rcreg; return(0); } if(pir1.5) { rv=rcreg|0x0100; return(rv); } else { return(0); } } unsigned char firstday; // 1-37 unsigned char monthsize; unsigned char entry; unsigned char highlite; // 0=no highlight unsigned char opcommand; // 0 = no test 1=count 2=alt all segs // 0n decode: // // 0 low byte // 1 high byte // 2 set first day // 3 set month size // 4 set highlight // 5 do op 0=stop 1=blank 2=fill 3=count 4=seg test void interrupt() { unsigned char command; unsigned char d; unsigned int rec; rec=rcreg; command=(rec>>4)&0xf; d=rec&0x0f; switch(command) { case 0: entry=(entry&0xf0)|d; break; case 1: entry=(entry&0x0f)|(d<<4); break; case 2: firstday=entry; break; case 3: monthsize=entry; break; case 4: highlite=entry; break; case 5: opcommand=d; break; } // check and clear error flag if set; if(rcsta.1) { rcsta = 0x80; rcsta = 0x90; d=rcreg; d=rcreg; } } // // segment test alternate segs // // show one segment // void segtest(unsigned char p) { unsigned int segs[10]; unsigned int v; unsigned char i; unsigned char b[10]; switch(p) { case 0: v=8194; break; case 1: v=528; break; case 2: v=4097; break; case 3: v=34816; break; case 4: v=68; break; case 5: v=136; break; case 6: v=17408; break; case 7: v=288; break; } for(i=0;i<10;i++) { segs[i]=v; } //no bright segs for(i=0;i<10;i++) b[i]=0; for(i=0;i<4;i++) { show_array(segs,i,b); } } // // mainline loop // void main() { unsigned char i; unsigned char c; unsigned int dispbits[10]; unsigned int b; unsigned char display[37]; // 0-99 blank if 0 // set port directions trisa = 0x00; // porta direction trisb = 0x06; // portb direction cmcon = 0x07; // turn off comparitors //clear_bit( option_reg, 7 ); // turn on portb pullups // enable interrupts //set_bit( intcon, T0IE ); //enable TMR0 overflow bit set_bit( pie1, RCIE ); //enable TMR0 overflow bit set_bit( intcon, PEIE ); // start interrupts set_bit( intcon, GIE ); // start interrupts // turn on serial receiver spbrg = 25; // 2400 BAUD txsta = 0x20; // TXEN = 1, 8 bit, async rcsta = 0x90; // SPEN = 1 , CREN = 1 b=0; c=0; firstday=0; monthsize=0; entry=0; highlite=0; opcommand=0; // clear dates for(i=0;i<37;i++) display[i]=100; showall(display); while( 1 ) { switch(opcommand) { case 1: // blank for(i=0;i<37;i++) display[i]=100; showall(display); opcommand=0; break; case 3: // show address for(i=0;i<37;i++) display[i]=i+1; showall(display); opcommand=0; break; case 4: // seg segtest(c); c++; if(c>7) c=0; delay_ms(200); break; case 2: // fill dates for(i=0;i<37;i++) display[i]=100; for(i=0;i