/* lcd.c firmware for Distant Meter V1.0 the sensor is simple reed switch with magnet tied to bycycle wheel. Optional 8-bit analog display for user sensor. MC908QY4CP 16-pin MCU compiled with icc08 Copyright (c) 2004 Wichit Sirichote */ #include #define one_revolution 157 // 2PIr, radius is 25cm #define p 1 // scale of ADC reading char temp,k; unsigned int PV,temp16; char i,n,timer1,timer2; unsigned char sec; char x1,x2,x3; long average,length, count; char diff,old, now; char *title = "DISTANCE METER 1"; char buffer[10]; /* signal for lcd interface E PTB1 RS PTB0 D4 PTB4 D5 PTB5 D6 PTB6 D7 PTB7 D0-D3 and R/W# are tied to GND */ void delay(int j) { unsigned int i; for (i = 0; i < j; i++) COPCTL = 0; // clear COP otherwise the cpu itself will be reset } void pulseE() { PTB |= 2; delay(10); PTB &= ~2; } void LCDWI(char c) /* write instruction to instruction register */ { temp = c; PTB &= ~3; // clear RS and E PTB &= 0x0f; // clear high nibbel to low c &= 0xf0; // prepare only high nibble PTB |= c; pulseE(); c = temp; c <<=4; PTB &= 0x0f; PTB |= c; pulseE(); delay(50); } void LCDWD(char c) /* write data to data register */ { temp = c; PTB |= 1; // set bit RS PTB &= ~2; // clear bit E PTB &= 0x0f; // clear high nibbel to low c &= 0xf0; // prepare only high nibble PTB |= c; // mearge high nibble first pulseE(); c = temp; c <<=4; PTB &= 0x0f; PTB |= c; pulseE(); delay(50); } void i_LCD() /* initialize LCD in accordance with Hitachi 44780 4-bit mode */ { PTB &= ~3; // clear RS and E PTB |= 0x30; pulseE(); delay(200); pulseE(); delay(50); pulseE(); delay(50); PTB &= 0x0f; PTB |= 0x20; pulseE(); pulseE(); pulseE(); LCDWI(0x28); // set 4-bit bus, 1/16 line, 5*7 dots LCDWI(0x0c); // display on/off on display,off cursor, no blink LCDWI(0x06); // entry mode DDRAM auto address increment LCDWI(1); // clear display delay(50); } // print LCD text >8 // the 16x1 line LCD has two blocks start address! void print_lcds(char *s) { char i; LCDWI(1); // clear display LCDWI(0x80); // start at left most position for(i=0; i<8; i++) LCDWD(*s++); LCDWI(0xc0); // new address for position 9 for(i=0; i<8; i++) LCDWD(*s++); } char read_ADC() { ADSCR = 0; // read channel 0 one time while(!(ADSCR&0x80)) ; return ADR; } // 3-point moving average (digital filtering) long read_ADC_filter(){ PV = read_ADC(); x3 = x2; x2 = x1; x1 = PV; PV = (x1+x2+x3)/3; return PV; } int read_adc_scale(){ long k; k = read_ADC_filter()*p; return k; } void print_dec(char d,unsigned int n) { buffer[0] = n/10000+48; temp16 = n%10000; buffer[1] = temp16/1000+48; temp16 %=1000; buffer[2] = temp16/100+48; temp16 %=100; buffer[3] = temp16/10+48; buffer[4] = temp16%10+48; LCDWI(d); for(i=0; i<5; i++) LCDWD(buffer[i]); } void print_distant() { if(++timer1>10) { timer1 = 0; PTA ^= 2; // toggle PA1 // count++; // test auto increment length = count*one_revolution; // one revolution = 157cm print_dec(0x80,length/100); // 100cm = 1m LCDWD(' '); LCDWD('m'); print_dec(0xc0,read_adc_scale()); } } void task_led() { if(++timer2>50) { timer2 =0; LCDWI(0xc7); k^=1; if (k) LCDWD('-'); else LCDWD('_'); } } // PTA2 input bit for reed swicth sensor // detect rising edge void detect_pulse_input() { now = PTA&4; // read only PTA2 diff = old-now; if(diff>4) count++; old = now; } void print_average() { average += count; average /= 2; print_dec(0xc0,average); } void main() { // OCSTRIM = 0x81; // trim internal oscillator delay(1000); // powerup delay for LCD n = k=0; count = 0; average = 0; TMODH = 0x01; TMODL = 0xf4; TSC = 0x06; // run timer DDRA = ~0x1; // PA0 is ADC input DDRB = 0xff; // port B is output port PTB = 0; // clear port B PTAPUE = ~0x81; // osc2 pin is PTA4 I/O ADCLK = 0x40; // ADC clock= fbus/4 i_LCD(); print_lcds(title); delay(60000); now = old = PTA&4; LCDWI(1); // clear lcd //asm(" cli"); //enable irq interrupt for(;;) { while(!(TSC&0x80)) ; TSC &= ~0x80; // clear TOF // PTA ^= 2; // task running ~60Hz so the loop running is 120Hz or 1/120Hz task_led(); print_distant(); detect_pulse_input(); COPCTL = 0; // clear COP } }