/* mini4.c Firmware for MiniLogger V3.0 89C51RD2+ICL7109+128kB SRAM+RTC+LCD+GPIO Copyright (C) 2003 WICHIT SIRICHOTE, 29 June 2003 Department of Applied Physics Faculty of Science King Mongkut's Institute of Technology Ladkrabang, Bangkok 10250 THAILAND June 7, 2004 found bug on compare time, DS1307 uses BCD for time updating but compare function uses binary number, need to fix it! June 16, 2004 fixed AUTO mode! Sep 6, 2004 save and restore flag1 Nov 17, 2004 use Manual start/stop for external trigger */ #include <8051io.h> #include <8051reg.h> #include <8051int.h> #include <8051bit.h> // require preprocessor -P when compiling #include "c:\mc\tiny\minilcd.c" #define word unsigned int #define byte unsigned char #define beginsysdata 0 #define beginrecord 100 #define begincrc 1000 #define status 0 /* system status eg., main/battery power, door open/close , digital input, analog input */ #define name 2 #define adc 0x08 // ICL7109 12-bit ADC #define gpio1 0x0c // 8-bit output port #define gpio2 0x0e // 8-bit input port #define lcd 0x0a // LCD // flag1 bit usages #define keypressed 0x01 //extern register char cputick; register unsigned char sec100,sec,sec5,min,hour,day,month,year,flag1,ACCU,temp,led; register unsigned char i,command,counter3; register unsigned char BUFFER[30],mode,key; register old,new; register char n,page,channel,POL,OV; register int temp3, temp4,k; register int buffer[4]; register unsigned char tbuffer[8]; extern register char lastread // flag for last byte to be read char title[] = "\n\nMiniLOGGER V3.0 (? help)"; char prompt[] = "\n>>"; char menu[] = "\n\nHELP MENU\ \n/ print analog reading\ \nt TIME set\ \nd DATE set\ \nc Clock display\ \ns set START/STOP recording time\ \ni sampling Interval\ \n= display setting parameters\ \nr number of record\ \nb terminal connection\ \nn New record\ \na ALL read: sample real-time and data\ \nx Read All: sample and data\ \nu About MiniLOGGER V3.0\ \n? help"; char _about[] = "\nMiniLOGGER was desinged by Wichit SIRICHOTE 28 June 2003\ \nApplied Physics Dept. KMITL\ \nfirmware updated: 25 June 2004\ \nURL: www.kmitl.ac.th/~kswichit email: kswichit@kmitl.ac.th"; char _terminal[] = "\n 1 2 3 4 5 6 7 8 9 10 11 12\ \nIN1+ IN1- IN2+ IN2- IN3+ IN3- IN4+ IN4- -5V +5V 0V +V"; register unsigned int blink_every; register unsigned int count,number_of_record,counter1,counter2,interval,temp16,j; register char counter4; register unsigned char pointer[3]; // 24 bit long number for external RAM pointer register unsigned char temp1[3], temp2[3]; // temp1 and temp2 are used for 24-bit storage extern register char Longreg[]; register unsigned char channel_display; /*-------------------- constant definition -------------------------*/ #define XOFF 0x13 // transmission flow control #define XON 0x11 #define adj 2 #define LED P1.7 #define trigger P3.5 #define standby_blink 100 #define recording_blink 300 #define base 100 // start address for NVRAM storage #define max_record 5000 //limit maximum record for 256kB SRAM (5000*50) /*-------- address for setting parameters saved in NVSRAM 256 bytes page 0--*/ #define start_hour 0 #define start_min 1 #define stop_hour 2 #define stop_min 3 #define interval_saved 4 // 4-5 (16-bit) #define record_saved 6 // 6-7 (16-bit) #define description 8 // 8-58 (max description string 50 characters) #define mode_saved 60 // mode 1 manual, -1 auto #define save_flag1 61 // for flag1 saving main() { asm" MOV $8E,#3"; // normal access to external memory, emits ALE when access ram IE = 0x81; // enable external interrupt0 TCON |= 0x01; // edge trigger channel = 0; channel_display = 0; xpoke(gpio1,0,channel); // select mux channel 0 old = new = 0; counter4=0; flag1 = 0; interval = 6000; // 60000 ms = 1 min blink_every = standby_blink; longset(pointer,100); /* initialize pointer to 100 */ reload_setting(); // reload previous recording setting InitLcd(); Puts("MiniLOGG"); goto_xy(0,1); Puts("ER V3.0"); delay(1000); key = 0xbf; flag1 |= 0x02; execute_key(); // emulate key S5 was pressed serinit(9600); putstr(title); sendprompt(); // clr_screen(); while(1) { tick_wait(); /*------------- the following tasks execute every 10ms ------*/ // cputick = 0; cpubeat(); getcommand(); printtime(); settime(); setdate(); set_interval(); dec_counter2(); start_record(); save_record(); print_number_of_record(); set_start_stop(); new_record(); show_setting(); print_menu(); clock(); read_all(); xread_all(); manual_start_stop(); about(); get_key(); key_released(); execute_key(); terminal_signal(); prompting(); print_adc(); print_no_record(); } /************************************************************/ } INTERRUPT(_IE0_) service_adc() { // P1 &= ~0x40; // hold ADC // asm" MOV $8F,#0"; // x1 mode temp3 = xpeek(adc,2); // get low byte temp4 = xpeek(adc,1); // get high byte // asm" MOV $8F,#1"; // x2 mode // printf("\r %02x %02x",temp1,temp2); POL = temp4&0x10; OV = temp4&0x20; temp4 &= 0x0f; temp4 <<= 8; temp3 |= temp4; if(!POL) temp3*=-1; if(OV) temp3 = 9999; buffer[channel] = temp3; channel++; channel &=3; xpoke(gpio1,0,channel); // select next channel delay(1); // wait for mux settled // P1 |= 0x40; // run ADC after mux settled for next channel scanning if(channel ==0) { P1 &= ~0x40; //stop ADC flag1 |= 0x80; // set ADC result bit // printf(" %d %d %d %d",buffer[0],buffer[1],buffer[2],buffer[3]); } } terminal_signal() { if(command == 'b') { putstr(_terminal); sendprompt(); } } setpage(char x) // emit A16,A17,A18,A19 to P1.0-P1.3 { temp = x; asm{ MOV A,temp MOV C,ACC.0 MOV P1.0,C MOV C,ACC.1 MOV P1.1,C MOV C,ACC.2 MOV P1.2,C MOV C,ACC.3 MOV P1.3,C } } xpeek(char x,int y) // read byte with page, address { setpage(x); return peek(y); } xpoke(char x,int y,char z) // write byte with page,address,data { setpage(x); poke(y,z); } output_1Hz() { send_start(); send_byte(0xd0); send_byte(0x07); // pointed to address 7 send_byte(0x90); // enable 1Hz output send_stop(); } readRTC() { send_start(); send_byte(0xD0); send_byte(0x00); send_stop(); send_start(); send_byte(0xD1); lastread = 0; for(i=0; i<6 ; i++) tbuffer[i] = read_byte(); lastread = 1; tbuffer[i] = read_byte(); send_stop(); // printf("\n %02x-%02x-%02x %02x:%02x:%02x",tbuffer[4],tbuffer[5],tbuffer[6],tbuffer[2],tbuffer[1],tbuffer[0]); } initRTC() { send_start(); send_byte(0xD0); send_byte(0x00); send_byte(0x00); send_byte(0x30); send_byte(0x12); send_byte(0x03); send_byte(0x25); send_byte(0x07); send_byte(0x00); send_stop(); } send_time() { readRTC(); } about() { if(command == 'u') { putstr(_about); sendprompt(); } } settime() { if (command == 't') { putstr("\nenter current time HH:MM:SS >"); hour = getbyte(); putch(':'); min = getbyte(); putch(':'); sec = getbyte(); send_start(); send_byte(0xD0); send_byte(0x00); send_byte(sec); send_byte(min); send_byte(hour); send_stop(); sendprompt(); } } int getnum() { char s[6]; /* five characters plus terminator */ char c; int i; for (i = 0; (c = putch(getch())) != 13; i++) s[i] = c; s[i] = '\0'; if (i==0) return (-1); else return (_atoi(s)); } getbyte() { char s[3]; /* two characters plus terminator */ int i; for (i = 0; i < 2; i++) /* read two characters then return value */ s[i] = putch(getch()); // echo to terminal s[i] = '\0'; return(((s[0]-0x30)<<4)|(s[1]-0x30)); // return BCD // return (_atoi(s)); // return binary } char getbyte_dec() { char s[3]; /* two characters plus terminator */ int i; for (i = 0; i < 2; i++) /* read two characters then return value */ s[i] = putch(getch()); // echo to terminal s[i] = '\0'; // return(((s[0]-0x30)<<4)|(s[1]-0x30)); // return BCD return (_atoi(s)); // return binary } set_interval() { if(command == 'i'){ putstr("\n interval 1-600 sec > "); setpage(0); pokew(interval_saved,(getnum()*100)); // convert to *10 ms interval = peekw(interval_saved); counter2 = interval; // load interval to counter2 sendprompt(); } } dec_counter2() { if (flag1&0x08){ counter2--; if(counter2 <= 0){ counter2 = interval; flag1 |= 0x04; after_save(); // reset manual start flag1 &= ~0x20; // enable trigger read again } } } start_record(){ unsigned char temp; counter3--; if ( counter3 <= 0){ counter3 = 100; // run this task every 1 second readRTC(); temp = tbuffer[2]>>4; // convert BCD to binary for hour temp *=10; tbuffer[2] = temp+(tbuffer[2]&0xf); temp = tbuffer[1]>>4; // convert BCD to binary for min temp *=10; tbuffer[1] = temp+(tbuffer[1]&0xf); setpage(0); // printf("\n%d:%d==%d:%d",tbuffer[2],tbuffer[1],peek(start_hour),peek(start_min)); if((tbuffer[2] == peek(start_hour)) && (tbuffer[1]== peek(start_min))) {flag1 |= 0x08; // start dec counter2 blink_every = recording_blink; poke(save_flag1,flag1); // save start flag has been set } if ((tbuffer[2] == peek(stop_hour)) && (tbuffer[1] == peek(stop_min))) {flag1 &= ~0x08; // disable running dec_counter2 blink_every = standby_blink; } } } setdate() { if (command == 'd') { putstr("\nenter current date DD-MM-YR >"); day = getbyte(); putch('-'); month = getbyte(); putch('-'); year = getbyte(); send_start(); send_byte(0xD0); send_byte(0x04); send_byte(day); send_byte(month); send_byte(year); send_stop(); sendprompt(); } } prompting() { if (command == 13) { putstr(title); sendprompt(); } } printtime() { if (command == '/') { readRTC(); printf("\n%02x-%02x-%02x ",tbuffer[4],tbuffer[5],tbuffer[6]); printf("%02x:%02x:%02x ",tbuffer[2],tbuffer[1],tbuffer[0]); read_ICL7109(); printf(" %d %d %d %d",buffer[0],buffer[1],buffer[2],buffer[3]); sendprompt(); } } getcommand() { if (SCON&0x01) command = putch(getch()); else command = -1; /* no cammand has entered */ } sendprompt() { putstr(prompt); } pause(int j) { int i; for (i = 0; i < j; i++) ; } cpubeat() { beat5sec(); livecpu(); } beat5sec() /* clear P3.4 every 500 tocks */ { counter1++; if (counter1 > blink_every ) { counter1 = 0; flag1 |= 0x40; /* set bit 6 of flag1 to signal livecpu task */ clrbit(LED) //asm " CLR P3.4"; led = 5; /* 5*10ms = 50ms LED on */ } } livecpu() { if (flag1&0x40) { led--; if (led == 0) { setbit(LED) //asm " SETB P3.4"; flag1 &= ~0x40; } } } read_ICL7109() /* read analog from ICL7109, save in BUFFER */ { // clrbit(LED) // while reading ADC turns LED on P1 |= 0x40; // start ADC while((flag1&0x80)==0) ; flag1 &= ~0x80; // clear flag1 // setbit(LED) // printf(" %d %d %d %d",buffer[0],buffer[1],buffer[2],buffer[3]); } tick_wait() { asm { JNB TCON.5,* /* wait for timer0 overflow */ CLR TCON.5 ORL TH0,#$DC /* reload $DC00, i.e., for 10ms overflow */ } } int get_address() /* return address pointer */ { int i; i = pointer[1]; i <<= 8; return(i|pointer[0]); } inc_pointer() { asm{ MOV A,#1 ADD A,pointer MOV pointer,A CLR A ADDC A,pointer+1 MOV pointer+1,A CLR A ADDC A,pointer+2 MOV pointer+2,A } } int set_RAM_address() /* increment next address SRAM */ { inc_pointer(); setpage(pointer[2]); return(get_address()); } int iset_RAM_address() /* increment next address word based */ { inc_pointer(); inc_pointer(); setpage(pointer[2]); return(get_address()); } char convert_hi_nibble(unsigned char c) { return((c>>=4)+0x30); } char convert_lo_nibble(char c) { return((c&0x0f)+0x30); } // format raw data saved in external ram // number day month year hr min sec adc0 adc1 adc2 adc3 * // number = 16-bit // adc0-adc3 = 16-bit // 17 bytes each record save_record() { if(flag1&0x04) { read_ICL7109(); readRTC(); pokew(iset_RAM_address(),number_of_record); // save date & time poke(set_RAM_address(),tbuffer[4]); // save day poke(set_RAM_address(),tbuffer[5]); // save month poke(set_RAM_address(),tbuffer[6]); // save year poke(set_RAM_address(),tbuffer[2]); // save hr poke(set_RAM_address(),tbuffer[1]); // save min poke(set_RAM_address(),tbuffer[0]); // save sec // now save the buffer read from ICL7109 pokew(iset_RAM_address(),buffer[0]); pokew(iset_RAM_address(),buffer[1]); pokew(iset_RAM_address(),buffer[2]); pokew(iset_RAM_address(),buffer[3]); flag1 &= ~0x04; ++number_of_record; max_limit(); // check maximum for 5000 records setpage(0); pokew(record_saved,number_of_record); // save available records // printf("%u",number_of_record); } } max_limit(){ // disable recording mode if number of record > max_record if(number_of_record > max_record) {flag1 &= ~0x08; // disable running dec_counter2 blink_every = standby_blink; poke(mode_saved,-1); // change to auto mode indicating maximum limited } } print_number_of_record() { if (command == 'r') { printf("\n%u records available",number_of_record); sendprompt(); } } /* get_record() // test reading until found record terminator { char i; if (command == 'g') { putch('\n'); j = 101; for (j = 101; j< 101+(number_of_record*46); j = j+46) { for ( i = 0; i <46; i++) { if(peek(i+j) != 0) putch(peek(i+j)); else putch('\n'); } } sendprompt(); } } */ get_key() { if((xpeek(gpio2,0) != 0xff)&& ((flag1&keypressed)==0)) { flag1 |= keypressed; // enter only after key was pressed key = xpeek(gpio2,0); // printf("%x", key); } else key = -1; } key_released() { if(xpeek(gpio2,0) == 0xff) flag1 &= ~keypressed; } execute_key() { if(key != -1) { switch (key) { case 0x7f: channel_display++; break; case 0xbf: flag1^=0x02; flag1 &= ~0x10; // show unit clr_screen(); goto_xy(0,1); Puts("x0.1mV "); if(flag1&0x02) { putch_lcd('*'); } else { clr_screen(); show_mode_on_lcd(); goto_xy(0,0); Puts("Record= "); flag1 |= 0x10; // show number of record on LCD } break; case 0xdf: break; case 0xef: break; } } } set_start_stop() { if (command == 's'){ setpage(0); printf("\nSTART %02d:%02d >",peek(start_hour),peek(start_min)); poke(start_hour,getbyte_dec()); // save new start time putch(':'); poke(start_min,getbyte_dec()); printf("\nSTOP %02d:%02d >",peek(stop_hour),peek(stop_min)); poke(stop_hour,getbyte_dec()); putch(':'); poke(stop_min,getbyte_dec()); printf("\n %02d:%02d %02d:%02d",peek(start_hour),peek(start_min),peek(stop_hour),peek(stop_min)); swapping_mode(); show_mode_on_lcd(); sendprompt(); } } swapping_mode() // enable/disable manual check { if (peek(start_hour) == 99) poke(mode_saved,1); // manual mode else (poke(mode_saved,-1)); // automatic mode } show_setting(){ if (command == '='){ setpage(0); printf("\n START %02d:%02d",peek(start_hour),peek(start_min)); printf("\n STOP %02d:%02d",peek(stop_hour),peek(stop_min)); printf("\n SAMPLING INTERVAL(sec) = %u",peekw(interval_saved)/100); if (peek(mode_saved) == 1) printf("\n MANUAL"); else (printf("\n AUTO")); sendprompt(); } } reload_setting(){ setpage(0); flag1 = peek(save_flag1); // restore flag1 interval = peekw(interval_saved); counter2 = interval; number_of_record= peekw(record_saved); longset(temp2,46); // temp2 = 46 longset(temp1,number_of_record); // temp1 = number of record longmul(temp1,temp2); // Longreg = temp1*temp2 longset(temp1,base); // temp1 = base = 100 longadd(Longreg,temp1); // Longreg = Longreg + temp1 longcpy(pointer,Longreg); // restore pointer } new_record() { if (command == 'n') { putstr("\n New record?(Y/N)"); if (getch() == 'y') { flag1 &= ~0x08; // reset start bit enable number_of_record = 0; setpage(0); pokew(record_saved,0); // reset number of record to 0 // printf("%d",peekw(record_saved)); longset(pointer,base); enter_description(); } sendprompt(); } } print_menu(){ if (command == '?'){ putstr(menu); sendprompt(); } } clock(){ if (command == 'c'){ readRTC(); printf("\n%02x-%02x-%02x ",tbuffer[4],tbuffer[5],tbuffer[6]); printf("%02x:%02x:%02x ",tbuffer[2],tbuffer[1],tbuffer[0]); sendprompt(); } } read_all() // read all record from 100 to current pointer { if (command == 'a'){ send_description(); longset(temp1,1); // decrement pointer longsub(pointer,temp1); longcpy(temp1,pointer); // copy end address to temp1 longset(pointer,100); // point to start of NVRAM // while (longcmp(temp1,pointer) > 0) for(j=0; j 0) for(j=0; j\n"); _getstr(BUFFER,30); // get string max 30 characters setpage(0); for (j = 0; BUFFER[j] != '\0'; j++) // save to NVRAM poke((description+j),BUFFER[j]); poke((description+j),'\0'); // put line terminator // sendprompt(); } send_description() { char c; send(0x0d); send(0x0a); setpage(0); for (j = 0; (c = peek(description+j)) != '\0'; j++) putch(c); } after_save() { flag1 &= ~0x08; // disable running dec_counter2 blink_every = standby_blink; } // detect edge every 0.5s char falling_edge() { if(++counter4>50) { counter4 = 0; old = new; if(P3&0x08) new = 1; else new = 0; return (new-old); } else return 0; } manual_start_stop(){ setpage(0); if (peek(mode_saved)==1){ if(falling_edge()<0) {flag1 |= 0x08; // start dec counter2 counter2 =interval; // reload interval blink_every = recording_blink; // printf("\n start dec counter2"); } } } show_mode_on_lcd() { setpage(0); if (peek(mode_saved)==1) { goto_xy(7,1); putch_lcd('M'); } else { goto_xy(7,1); putch_lcd('A'); } } print_adc() { if(flag1&0x02) { read_ICL7109(); goto_xy(0,0); channel_display &= 0x03; // only 0-3 can be used putch_lcd(channel_display+49); // show channel 1 to 4 instead putch_lcd(' '); print_4digit(buffer[channel_display]); } } print_no_record() { if(flag1&0x10) // print number of record on lcd { goto_xy(0,1); print_4digit(number_of_record); } }