/***************************************************** This program was produced by the CodeWizardAVR V1.25.7a Standard Automatic Program Generator © Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l. http://www.hpinfotech.com Project : Version : Date : 7/27/2008 Author : Theodore Johnson Company : 225 e. 36th st 17B NY Comments: Chip type : ATmega168 Program type : Application Clock frequency : 8.000000 MHz Memory model : Small External SRAM size : 0 Data Stack size : 256 *****************************************************/ #include #include // Standard Input/Output functions #include /* #define LE_5622 PORTB.1 #define DATA_5622 PORTB.2 #define CLK_5622 PORTB.3 */ #define ENABLE_5122 PORTB.1 #define DATA_5122 PORTB.2 #define CLOCK_5122 PORTB.3 #define STROBE_5122 PORTB.4 #define DATA_513 PORTD.1 #define BL_513 PORTD.2 #define CLK_513 PORTD.3 #define LE_513 PORTD.4 #define BTN PINC.5 #define LED0 PORTC.0 #define LED1 PORTC.1 // Timer 0 overflow interrupt service routine unsigned char dpos = 0; unsigned int posbuf; unsigned int segbuf; unsigned int display[13]; flash unsigned int transpos[13] = { 0x0100,0x0200,0x0400,0x0800, 0x1000,0x2000,0x4000,0x8000, 0x0001,0x0002,0x0004,0x0008, 0x0010 }; void init_segments(){ ENABLE_5122=1; CLOCK_5122 = 0; STROBE_5122 = 1; } void load_segments(){ unsigned char i, v; //unsigned long int bitpos; unsigned int bitpos; bitpos=1; ENABLE_5122=0; for(i=0;i<12;i++){ CLOCK_5122 = 1; v = (segbuf & bitpos) != 0; // if(v>0) // v=1; DATA_5122 =v; bitpos = bitpos << 1; delay_us(1); CLOCK_5122=0; } CLOCK_5122 = 0; ENABLE_5122=1; } void initpos(){ BL_513 = 0; CLK_513 = 0; LE_513 = 0; } void load_pos(){ unsigned char i, bytepos, v; unsigned int bitpos; BL_513 = 0; bitpos=1; bytepos=0; for(i=0;i<16;i++){ CLK_513 = 0; v = (posbuf & bitpos)>0; if(v>0) v=1; DATA_513 = v; bitpos = bitpos << 1; CLK_513=1; } LE_513 = 1; delay_us(1); LE_513 = 0; BL_513 = 1; } flash unsigned int digits[10] = { 0x0c4d,0x0041,0x080f,0x084b,0x0443,0x0c4a,0x044e,0x0841,0x0c4f,0x0c43 // 10,1,2,3,4,5,6,7,8,9 }; #define BLANK 0x0000 #define ERROR 0x0C0E //#define DOT 0x0020 #define DOT 0x0030 #define COMMA 0x0030 #define MINUS 0x0002 #define PENDING 0x0800 #define BADKEY 0x0040 #define OVFL 0x0080 #define DASH 0x0100 #define PIP 0x0200 interrupt [TIM0_COMPA] void timer0_ovf_isr(void){ dpos++; if(dpos>12){ dpos = 0; } posbuf=transpos[dpos]; segbuf = display[dpos]; BL_513 = 0; if(segbuf != 0){ load_segments(); load_pos(); if((segbuf & (~DOT))==0) TCNT0 = 0x7f; } } // #define SHIFT 20 // ---------------------------------------------- // err_code 0 means no character. // 1 means garbled char. // 2 means valid char. unsigned char get_char(unsigned char *err_code){ unsigned char c, status; if((UCSR0A & 0x80) == 0){ *err_code = 0; return 0; } status = UCSR0A; c = UDR0; if((status & 0x18)>0) *err_code = 1; else *err_code = 2; return c; } // ---------------------------------------------------------- #define VISDIG 12 #define COMPDIG 16 #define N_BIG 16 struct bigdig{ unsigned char v[N_BIG]; // 0 - 9 unsigned char decimal; // decimal position from left. unsigned char sign; // 0 is positive, 1 is negative. }; void copy_dig(struct bigdig *to, struct bigdig *from){ unsigned char i; to->decimal = from->decimal; to->sign = from->sign; for(i=0;iv[i] = from->v[i]; } // positive if b1 > b2, negative if b1 < b2, zero if b1 == b2 // Assume that b1, b2 are normalized int compare(struct bigdig *b1, struct bigdig *b2){ unsigned char i; if(b1->decimal != b2->decimal){ if(b1->decimal > b2->decimal){ return 1; }else{ return -1; } } for(i=0;iv[i]!=b2->v[i]){ if(b1->v[i] > b2->v[i]) return 1; else return -1; } } return 0; } void zero_bigdig(struct bigdig *b){ unsigned char i; b->decimal=0; b->sign = 0; for(i=0;iv[i]=0; } unsigned char is_zero(struct bigdig *b){ unsigned char p; for(p=0;pv[p] != 0) break; if(p==N_BIG) return 1; return 0; } void normalize(struct bigdig *b){ unsigned char i,p,top; // Clear any -0 if(is_zero(b)){ b->sign = 0; b->decimal = 0; return; } for(p=0;pdecimal;p++){ if(b->v[p]!=0) break; } if(p==0) return; top=N_BIG-p; for(i=0;iv[i]=b->v[i+p]; for(;iv[i]=0; b->decimal -= p; } void shift_r(struct bigdig *b,unsigned char o){ unsigned char i; for(i=N_BIG;i>o;){ i--; b->v[i] = b->v[i-o]; } for(i=0;iv[i]=0; b->decimal += o; } void shift_l(struct bigdig *b,unsigned char o){ unsigned char i; for(i=0;iv[i] = b->v[i+o]; } for(;iv[i]=0; b->decimal += o; } // b3 <- b1 + b2 // Assume they are normalized - but probabaly not important here. // Ignore sign (assume b1, b2 are positive). void add_abs(struct bigdig *b1, struct bigdig *b2, struct bigdig *b3){ unsigned char i, ovfl; // first, align the two digits if(b1->decimal > b2->decimal){ shift_r(b1,1); shift_r(b2,b1->decimal - b2->decimal); }else{ shift_r(b2,1); shift_r(b1,b2->decimal - b1->decimal); } b3->decimal = b2->decimal; ovfl = 0; for(i=COMPDIG;i>0;){ i--; b3->v[i] = ovfl + b1->v[i]+b2->v[i]; if(b3->v[i]>9){ b3->v[i]-=10; ovfl=1; }else{ ovfl=0; } } normalize(b1); normalize(b2); normalize(b3); } // b1 <- b1 - b2 // Assume they are normalized - but probabaly not important here. // ASSUME |b1| > |b2| // b1, b2 are positive void sub_abs(struct bigdig *b1, struct bigdig *b2, struct bigdig *b3){ unsigned char i,borrow,val,do_renorm = 0; // first, align the two digits if(b1->decimal > b2->decimal){ shift_r(b2,b1->decimal - b2->decimal); do_renorm = 1; } b3->decimal = b1->decimal; borrow = 0; for(i=COMPDIG;i>0;){ i--; val=borrow+b2->v[i]; if(b1->v[i]>=val){ b3->v[i]=b1->v[i]-val; borrow=0; }else{ b3->v[i]=(10+b1->v[i])-val; borrow=1; } } normalize(b3); if(do_renorm) normalize(b2); } void sub(struct bigdig *b1, struct bigdig *b2, struct bigdig *b3); void add(struct bigdig *b1, struct bigdig *b2, struct bigdig *b3){ if(b1->sign==1 && b2->sign == 0){ b1->sign = 0; sub(b2,b1,b3); b1->sign = 1; return; } if(b1->sign == 0 && b2->sign == 1){ b2->sign = 0; sub(b1,b2,b3); b2->sign = 1; return; } if(b1->sign == 1 && b2->sign == 1){ b1->sign = 0; b2->sign = 0; add_abs(b1,b2,b3); b1->sign = 1; b2->sign = 1; b3->sign = 1; return; } // b1->sign==0 && b2->sign == 0; add_abs(b1,b2,b3); b3->sign = 0; } void sub(struct bigdig *b1, struct bigdig *b2, struct bigdig *b3){ if(b1->sign == 0 && b2->sign == 0){ if(compare(b1,b2)>0){ sub_abs(b1,b2,b3); b3->sign = 0; }else{ sub_abs(b2,b1,b3); if(! is_zero(b3)) b3->sign=1; } return; } if(b1->sign == 1 && b2->sign == 0){ add_abs(b1,b2,b3); if(! is_zero(b3)) b3->sign=1; return; } if(b1->sign == 0 && b2->sign == 1){ add_abs(b1,b2,b3); b3->sign = 0; return; } // b1->sign==1 && b2->sign == 1 if(compare(b2,b1)>0){ sub_abs(b2,b1,b3); b3->sign = 0; }else{ sub_abs(b1,b2,b3); if(! is_zero(b3)) b3->sign=1; } return; } unsigned char mult_1_dig(struct bigdig *src, unsigned char d, struct bigdig *res, unsigned char sum){ unsigned char i, ovfl; if(sum==0) zero_bigdig(res); for(i= N_BIG-1;i>0; i--){ res->v[i] += d*src->v[i]; if(res->v[i] >= 10){ ovfl = res->v[i] / 10; res->v[i-1] += ovfl; res->v[i] -= 10*ovfl; } } res->v[0] += d*src->v[i]; if(res->v[0] >= 10){ res->v[0] -= 10; return 1; } return 0; } struct bigdig tmpsrc1, tmpsrc2, divmult; void mult(struct bigdig *src1, struct bigdig *src2, struct bigdig *res){ unsigned char i; copy_dig(&tmpsrc1, src1); zero_bigdig(res); // An optimization opportunity is to limit // mult_1_dig to do multiplication on non-zeros in src1. for(i=0;iv[i] != 0) mult_1_dig(&tmpsrc1,src2->v[i],res,1); } res->sign = src1->sign ^ src2->sign; res->decimal = src1->decimal + src2->decimal; normalize(res); return; } int adjust_left(struct bigdig *d){ int i,k; if(d->decimal > 0) return (int)d->decimal; for(i=0;iv[i] != 0) break; } if(i == N_BIG) // is zero return 0; for(k=i;kv[k-i] = d->v[k]; for(k=N_BIG-i;kv[k] = 0; return -1*((int)i); } void div(struct bigdig *src1, struct bigdig *src2, struct bigdig *res){ unsigned char i, appdiv, app_r, v, ovfl; int real_dec1, real_dec2; // dvide by zero : return zero. Can check for error elsewhere. zero_bigdig(res); if(is_zero(src1) || is_zero(src2)) return; copy_dig(&tmpsrc1, src1); copy_dig(&tmpsrc2, src2); real_dec1 = adjust_left(&tmpsrc1); real_dec2 = adjust_left(&tmpsrc2); appdiv = tmpsrc2.v[0]; // Try to get the 1st digit if(appdiv <= tmpsrc1.v[0]){ app_r = tmpsrc1.v[0] / appdiv; if(app_r > 9) app_r = 9; ovfl = mult_1_dig(&tmpsrc2,app_r,&divmult,0); divmult.decimal = 0; tmpsrc1.decimal=0; while(app_r > 0 && ovfl > 0 || compare(&divmult,&tmpsrc1)>0){ app_r--; mult_1_dig(&tmpsrc2,app_r,&divmult,0); } sub_abs(&tmpsrc1, &divmult, &tmpsrc1); res->v[0] = app_r; }else{ res->v[0] = 0; } shift_r(&tmpsrc2,1); for(i=1;i 9) app_r = 9; if(app_r > 0){ ovfl = mult_1_dig(&tmpsrc2,app_r,&divmult,0); divmult.decimal = 0; tmpsrc1.decimal=0; while(app_r > 0 && ovfl>0 || compare(&divmult,&tmpsrc1)>0){ app_r--; mult_1_dig(&tmpsrc2,app_r,&divmult,0); } sub_abs(&tmpsrc1, &divmult, &tmpsrc1); res->v[i] = app_r; shift_l(&tmpsrc1,1); }else{ shift_l(&tmpsrc1,1); res->v[i] = 0; } } if(real_dec1+1 >= real_dec2){ res->decimal = real_dec1+1 - real_dec2; }else{ shift_r(res,real_dec2-real_dec1-1); res->decimal = 0; } res->sign = src1->sign ^ src2->sign; normalize(res); } // ---------------------------------------------- //unsigned char disp[VISDIG]; //unsigned char punct[VISDIG]; // 0 if OK, 1 if overflow. unsigned char set_disp(struct bigdig *b, unsigned char digit_pos, unsigned char decimal_set){ unsigned char i,d, last_nonz, ext_nonz,visdig=VISDIG-1; if(b->decimal > VISDIG-1){ return 1; } for(i=0;isign == 1) display[0] = MINUS; for(last_nonz=visdig;last_nonz>0;){ last_nonz--; if(b->v[last_nonz]!=0) break; } if(digit_pos > last_nonz && digit_pos <= visdig) last_nonz = digit_pos-1; // if(b->sign == 1 || (b->decimal == 0 && (decimal_set || last_nonz > 0) )) // visdig--; // if(visdig > last_nonz) // visdig--; ext_nonz = 0; for(d=visdig;dv[d]!=0) ext_nonz = 1; } // Handle case of zero. if(last_nonz == 0 && b->v[0] == 0){ display[VISDIG-1] = digits[0]; if(ext_nonz == 0 && decimal_set && digit_pos>0){ display[VISDIG-2] = DOT; }else{ if(ext_nonz || decimal_set) display[VISDIG-1] |= DOT; } return 0; } // 1.0 or larger if(b->decimal > 0){ d=visdig; for(i=last_nonz+1;idecimal;i++){ display[d] = digits[0]; d--; } for(i=last_nonz+1;i>0;){ i--; display[d] = digits[b->v[i]]; d--; } if(b->decimal == last_nonz+1){ if(ext_nonz) display[VISDIG-1] |= DOT; }else{ if(d+b->decimal < visdig) display[d+b->decimal] |= DOT; } }else{ d=VISDIG-1; for(i=last_nonz+1;i>0;){ i--; display[d] = digits[b->v[i]]; d--; } display[d] |= DOT; } return 0; } struct bigdig disp_dig, lhs_dig, result_dig; unsigned char do_op(unsigned char pending_op){ switch(pending_op){ case '+': add(&lhs_dig, &disp_dig, &result_dig); return 1; case '-': sub(&lhs_dig, &disp_dig, &result_dig); return 1; case '*': mult(&lhs_dig, &disp_dig, &result_dig); return 1; case '/': div(&lhs_dig, &disp_dig, &result_dig); return 1; } return 0; } void main(void){ unsigned char err_code, c, i; unsigned char decimal_set, digit_pos, is_neg, disp_ret, pending_op = ' '; unsigned char op_performed, reset_dig=0, previous_char = ' '; unsigned char neg_set = 0; // Crystal Oscillator division factor: 1 #pragma optsize- CLKPR=0x80; CLKPR=0x00; #ifdef _OPTIMIZE_SIZE_ #pragma optsize+ #endif // Input/Output Ports initialization // Port B initialization // Func7=In Func6=In Func5=In Func4=In Func3=Out Func2=Out Func1=Out Func0=In // State7=T State6=T State5=T State4=T State3=0 State2=0 State1=0 State0=T PORTB=0x00; DDRB=0x1E; // Port C initialization // Func6=In Func5=In Func4=In Func3=In Func2=In Func1=Out Func0=Out // State6=T State5=T State4=T State3=T State2=T State1=T State0=0 PORTC=0x00; DDRC=0x03; // Port D initialization // Func7=In Func6=In Func5=In Func4=Out Func3=Out Func2=Out Func1=Out Func0=In // State7=T State6=T State5=T State4=T State3=0 State2=0 State1=0 State0=T PORTD=0x00; DDRD=0x1E; // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: 1000.000 kHz // Mode: CTC top=OCR0A // OC0A output: Disconnected // OC0B output: Disconnected TCCR0A=0x02; TCCR0B=0x03; TCNT0=0x00; OCR0A=0xa0; OCR0B=0x00; // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: Timer 1 Stopped // Mode: Normal top=FFFFh // OC1A output: Discon. // OC1B output: Discon. // Noise Canceler: Off // Input Capture on Falling Edge // Timer 1 Overflow Interrupt: Off // Input Capture Interrupt: Off // Compare A Match Interrupt: Off // Compare B Match Interrupt: Off TCCR1A=0x00; TCCR1B=0x00; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // Timer/Counter 2 initialization // Clock source: System Clock // Clock value: Timer 2 Stopped // Mode: Normal top=FFh // OC2A output: Disconnected // OC2B output: Disconnected ASSR=0x00; TCCR2A=0x00; TCCR2B=0x00; TCNT2=0x00; OCR2A=0x00; OCR2B=0x00; // External Interrupt(s) initialization // INT0: Off // INT1: Off // Interrupt on any change on pins PCINT0-7: Off // Interrupt on any change on pins PCINT8-14: Off // Interrupt on any change on pins PCINT16-23: Off EICRA=0x00; EIMSK=0x00; PCICR=0x00; // Timer/Counter 0 Interrupt(s) initialization TIMSK0=0x02; // Timer/Counter 1 Interrupt(s) initialization TIMSK1=0x00; // Timer/Counter 2 Interrupt(s) initialization TIMSK2=0x00; // USART initialization // Communication Parameters: 8 Data, 1 Stop, No Parity // USART Receiver: On // USART Transmitter: Off // USART0 Mode: Asynchronous // USART Baud Rate: 9600 UCSR0A=0x00; UCSR0B=0x10; UCSR0C=0x06; UBRR0H=0x00; UBRR0L=0x33; // Analog Comparator initialization // Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off ACSR=0x80; ADCSRB=0x00; // Global enable interrupts #asm("sei") init_segments(); initpos(); zero_bigdig(&disp_dig); set_disp(&disp_dig,0,0); decimal_set = 0; digit_pos = 0; is_neg = 0; pending_op = ' '; previous_char = ' '; LED0=0; LED1=0; while(1){ c=get_char(&err_code); if(err_code == 2){ if(c>='0' && c <= '9'){ if(reset_dig){ copy_dig(&lhs_dig, &disp_dig); zero_bigdig(&disp_dig); decimal_set = 0; digit_pos = 0; if(neg_set){ is_neg = 1; disp_dig.sign = 1; }else{ is_neg = 0; disp_dig.sign = 0; } neg_set = 0; } if(c!='0' || digit_pos != 0 || decimal_set){ if(digit_pos < VISDIG-1){ disp_dig.v[digit_pos] = c-'0'; digit_pos++; if(! decimal_set) disp_dig.decimal++; }else{ LED0=1; display[0] |= BADKEY; delay_ms(40); display[0] &= ~BADKEY; LED0=0; } } reset_dig = 0; }else{ switch(c){ case '.': if(reset_dig){ copy_dig(&lhs_dig, &disp_dig); zero_bigdig(&disp_dig); decimal_set = 0; digit_pos = 0; if(neg_set){ is_neg = 1; disp_dig.sign = 1; }else{ is_neg = 0; disp_dig.sign = 0; } neg_set = 0; } if(digit_pos <= VISDIG-is_neg){ decimal_set = 1; }else{ LED0=1; delay_ms(10); LED0=0; } reset_dig = 0; break; case 'l': if(reset_dig){ pending_op = ' '; } zero_bigdig(&disp_dig); decimal_set = 0; digit_pos = 0; is_neg = 0; reset_dig = 0; break; case 'e': zero_bigdig(&disp_dig); zero_bigdig(&lhs_dig); decimal_set = 0; digit_pos = 0; is_neg = 0; reset_dig = 0; pending_op = ' '; break; case '<': if(previous_char=='+' || previous_char=='+'){ pending_op = ' '; break; } if(is_zero(&disp_dig)){ pending_op = ' '; } if(decimal_set && (disp_dig.decimal==digit_pos)){ decimal_set = 0; break; } if(digit_pos>0){ digit_pos--; if(! decimal_set) disp_dig.decimal--; disp_dig.v[digit_pos] = 0; }else{ display[0] |= BADKEY; delay_ms(40); display[0] &= ~BADKEY; } break; case '-': if(reset_dig && previous_char != '='){ neg_set = 1-neg_set; break; } if(pending_op != ' '){ if(do_op(pending_op)){ copy_dig(&lhs_dig, &result_dig); copy_dig(&disp_dig, &result_dig); digit_pos = 0; decimal_set = 0; reset_dig = 1; } } pending_op = '-'; if(previous_char != '<' && previous_char != 'l') reset_dig = 1; break; case '+': if(pending_op != ' '){ if(do_op(pending_op)){ copy_dig(&lhs_dig, &result_dig); copy_dig(&disp_dig, &result_dig); digit_pos = 0; decimal_set = 0; reset_dig = 1; } } pending_op = '+'; if(previous_char != '<' && previous_char != 'l') reset_dig = 1; break; case '*': if(pending_op != ' '){ if(do_op(pending_op)){ copy_dig(&lhs_dig, &result_dig); copy_dig(&disp_dig, &result_dig); digit_pos = 0; decimal_set = 0; reset_dig = 1; } } pending_op = '*'; if(previous_char != '<' && previous_char != 'l') reset_dig = 1; break; case '/': if(pending_op != ' '){ if(do_op(pending_op)){ copy_dig(&lhs_dig, &result_dig); copy_dig(&disp_dig, &result_dig); digit_pos = 0; decimal_set = 0; reset_dig = 1; } } pending_op = '/'; if(previous_char != '<' && previous_char != 'l') reset_dig = 1; break; case '=': op_performed = do_op(pending_op); if(op_performed){ copy_dig(&lhs_dig, &result_dig); copy_dig(&disp_dig, &result_dig); digit_pos = 0; decimal_set = 0; reset_dig = 1; } pending_op = ' '; break; default: display[0] |= BADKEY; delay_ms(40); display[0] &= ~BADKEY; } } if(BTN){ LED1 = 1; disp_ret = set_disp(&lhs_dig,0, 0); }else{ LED1 = 0; disp_ret = set_disp(&disp_dig,digit_pos, decimal_set); display[12] = 0; if(disp_ret){ display[12] = OVFL | DASH |PIP; display[0] = ERROR; } if(pending_op != ' ') display[0] |= PENDING; } if(neg_set){ display[0] |= MINUS; } previous_char = c; } } for(i=0;i<10;i++) display[i] = ((unsigned long int)digits[i]); display[10] = COMMA; display[11] = MINUS; display[12] = OVFL; while(0){ c=get_char(&err_code); if(err_code == 2){ switch(c){ case '0': LED0=0; LED1=0; segbuf = 0x1111; posbuf = 0x1111; break; case '1': LED0=0; LED1=0; segbuf = 0x2222; posbuf = 0x2222; break; case '2': LED0=0; LED1=1; segbuf = 0x4444; posbuf = 0x4444; break; case '3': LED0=0; LED1=1; segbuf = 0x8888; posbuf = 0x8888; break; default: break; } LED0=1; load_segments(); load_pos(); LED0=0; } delay_ms(10); } while (1){ get_char(&err_code); if(err_code == 1) LED0 = 1; if(err_code == 2) LED1 = 1; delay_ms(10); LED0=0; LED1=0; }; }