Springe zum Inhalt

Quellcode des LC-Meters

Im folgenden ist der gesamte Quellcode des LC-Meters dargestellt, wie ich ihn für die einzelnen Experimente und Meßvorschriften im Hauptartikel benutzt habe. Die verwendete CPU ist ein Atmel ATmega163. Wird eine andere CPU aus der ATmega-Reihe verwendet, dann sind gegebenenfalls ein paar Namen (etwa bei den Timern und bei den Interruptvektoren) auszuwechseln. Wird eine völlig andere CPU verwendet, dann sind natürlich alle die Ports, Counter und Interrupts betreffenden Stellen anzupassen. Der Bequemlichkeit halber kann der Qullcode auch hier direkt heruntergeladen werden. Außerdem müssen die Anmerkungen im Artikel Verdrahtung berücksichtigt werden. Dort ist neben der Verkabelung vor allem beschrieben, wie eine notwendige Modifikation durchzuführen ist.

1// Firmware for an experimental LC-Meter
2// (c) 2005-2009 by DL8NCI
3// Compiled with WinAVR 20071221
4// and avr libc 1.6.0
5// fuse bits: LOW: 0xda HIGH:0xff
6//  BOOTSZ   = 128 word (irrelevant)
7//  BOOTRST  = not checked
8//  BODLEVEL = 2,7 V (irrelevant)
9//  BODEN    = not checked
10//  SPIEN    = checked
11//  CKSEL    = Crystal Oscillator slowly raising power
12// Lockbits: 0xff
13 
14#include <inttypes.h>
15#include <avr/io.h>
16#include <avr/interrupt.h>
17#include <stdio.h>
18#include <util/delay.h>
19#include <avr/pgmspace.h>
20 
21// for the LC-Display
22#define LCD_DDR     DDRA
23#define LCD_PORT    PORTA  
24#define LCD_PIN     PINA
25#define LCD_PORT_E  PORTC
26#define LCD_DDR_E   DDRC
27#define LCD_E       2
28#define LCD_RW      3
29#define LCD_RS      4
30 
31// some convenient functions
32#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
33#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
34 
35// global variables for LC-display
36uint8_t LCD_pos;
37uint8_t LCD_esc;
38 
39// counter value and ready status for interrupt
40volatile uint32_t CNT;
41volatile uint8_t ready;
42uint8_t n_CNT;
43 
44// measuring mode, calibration mode and range
45uint8_t mmode;
46uint8_t cmode;
47uint8_t rmode;
48 
49// key status
50uint8_t keys;
51 
52#define NX_MAX 16
53 
54// some fixed values
55double C13 = 470e-12;
56double C15 = 330e-12;
57 
58#define PI 3.1415926535
59#define TF 200      // ca. 50 ms
60double t_gate;
61 
62// the relays/switches
63#define SHORT_LX cbi(PORTB,4);
64#define OPEN_LX  sbi(PORTB,4);
65#define ON_330   cbi(PORTB,3);
66#define OFF_330  sbi(PORTB,3);
67#define SHORT_L3 cbi(PORTB,2);
68#define OPEN_L3  sbi(PORTB,2);
69 
70#define ON_33k   cbi(PORTD, 1);
71#define OFF_33k  sbi(PORTD, 1);
72#define ON_1M    cbi(PORTD, 2);
73#define OFF_1M   sbi(PORTD, 2);
74#define ON_1k    cbi(PORTD, 0);
75#define OFF_1k   sbi(PORTD, 0);
76 
77// all the LCD stuff - connected to the printf statement
78void LCD_PulseE(void) {
79    sbi(LCD_PORT_E,LCD_E);
80    _delay_us(2);       // 2 us
81    cbi(LCD_PORT_E,LCD_E);
82    }
83 
84void LCD_WaitBusy(void) {
85    uint8_t h=0x80;
86 
87    LCD_DDR = 0x0c;
88    LCD_PORT = 0x00;
89 
90    while(h!=0) {
91        LCD_PORT = 0x04;
92        sbi(LCD_PORT_E,LCD_E);
93        _delay_us(1);       // 1 us
94        h = LCD_PIN & 0x80;
95        cbi(LCD_PORT_E,LCD_E);
96        LCD_PulseE();
97        }
98    LCD_DDR = 0xfc;
99    }
100 
101void LCD_SendCmd(char c) {
102    char ch;
103         
104    LCD_WaitBusy();
105    LCD_PORT = c & 0xf0;
106    LCD_PulseE();
107 
108    ch = c;
109    asm("swap %0" : "=r" (ch) : "0" (ch));
110    LCD_PORT = ch & 0xf0;
111    LCD_PulseE();
112    }
113 
114void LCD_SendChar_int(char c) {
115    char ch;
116 
117    LCD_WaitBusy();
118    LCD_PORT = (c & 0xf0) | 0x08;
119    LCD_PulseE();
120 
121    ch = c;
122    asm("swap %0" : "=r" (ch) : "0" (ch));
123    LCD_PORT = (ch & 0xf0) | 0x08;
124    LCD_PulseE();
125    LCD_pos++;
126    }
127 
128int LCD_SendChar(char c, FILE *stream) {
129    if (LCD_esc==0) {
130        if (c!='\001') {
131            LCD_SendChar_int(c);
132            }
133        else {
134            LCD_esc = 1;
135            }
136        }
137    else {
138        switch(c) {
139            case '\001':
140                LCD_SendCmd(0x80);
141                LCD_pos = 0;
142                LCD_esc = 0;
143                break;
144            case '\002':
145                LCD_SendCmd(0xc0);
146                LCD_pos = 0;
147                LCD_esc = 0;
148                break;
149            case '\003':
150                LCD_SendCmd(0x94);
151                LCD_pos = 0;
152                LCD_esc = 0;
153                break;
154            case '\004':
155                LCD_SendCmd(0xd4);
156                LCD_pos = 0;
157                LCD_esc = 0;
158                break;
159            case '\005':
160                while(LCD_pos<20) LCD_SendChar_int(0x20);
161                LCD_esc = 0;
162                break;
163            }
164        }
165    return 0;
166    }
167 
168void LCD_Goto(uint8_t line, uint8_t column) {
169    LCD_SendCmd(87 + column + 40*line);
170    LCD_pos = column - 1;
171    }
172 
173void LCD_Init(void) {
174    uint8_t i;
175 
176    for (i=0;i<20;i++) { _delay_ms(15.0); }  // 300 ms
177    sbi(LCD_DDR_E,LCD_E);
178    LCD_DDR = 0xfc;
179    LCD_PORT = 0x30;
180    LCD_PulseE();
181 
182    _delay_ms(15.0);    // 15 ms
183 
184    LCD_PORT = 0x30;
185    LCD_PulseE();
186 
187    _delay_ms(1.0);     // 1 ms
188 
189    LCD_PORT = 0x30;
190    LCD_PulseE();
191 
192    LCD_PORT = 0x20;
193    LCD_PulseE();
194                 
195    LCD_SendCmd(0x28);
196    LCD_SendCmd(0x0c);
197    LCD_SendCmd(0x06);
198 
199    LCD_SendCmd(0x01);
200 
201    static FILE mystdout = FDEV_SETUP_STREAM(LCD_SendChar,NULL,_FDEV_SETUP_WRITE);
202    stdout = &mystdout;
203 
204    LCD_pos = 0;
205    LCD_esc = 0;
206    }
207 
208 
209// sometimes we have nothing to do
210void idle(void) { asm("nop" "\n\t"  ::); }
211 
212// the handlers for key status changes
213void key0on(void) { }   // not used
214 
215void key0off(void) {    // togle light on/off
216    if ((PORTD & 0x80)==0x80) cbi(PORTD,7); else sbi(PORTD,7);
217    }
218 
219void key1on(void) { }   // not used
220 
221void key1off(void) {    // range selection
222    rmode++;
223    cmode = 0;
224    if (rmode==3) rmode=0;
225    }
226 
227void key2on(void) { }   // not used
228 
229void key2off(void) {    // toggle calibration/measurement
230    if (cmode==0) cmode=1; else cmode=0;
231    }
232 
233void key3on(void) { }   // not used
234 
235void key3off(void) {    // switch to next measuring mode
236    mmode++;
237    cmode = 0;
238    rmode = 0;
239    if (mmode==5) mmode=0;
240    }
241 
242 
243// the timer2-compare interrupt
244ISR(TIMER2_COMP_vect) {
245    uint16_t l,h;
246 
247    TCCR1B = 0;     // stop counter
248    TCCR2 = 0;      // stop timer
249 
250    // read counter and ...
251    l = TCNT1L;
252    h = TCNT1H;
253    // ... add to global counter
254    CNT = CNT + l + (h << 8);
255    ready=1;
256    }
257 
258// the timer1-capture interrupt
259ISR(TIMER1_CAPT_vect) {
260    uint16_t l,h;
261 
262    TCCR1B = 0;     // stop timer
263 
264    // read counter and ...
265    l = TCNT1L;
266    h = TCNT1H;
267    // ... add to global counter
268    CNT = CNT + l + (h << 8);
269    ready = 1;
270    }
271 
272// some preparation - mainly determine t_gate (done once only)
273void Calibrate(void) {
274 
275    CNT = 0;
276 
277    // setup timer 1 as counter and timer 2 as timer   
278    cli();
279 
280    TCCR1A = 0x00;
281    TCCR1B = 0x00;
282 
283    TCNT1H = 0;
284    TCNT1L = 0;
285 
286    TCCR2 = 0x00;
287    OCR2 = TF;
288    TCNT2 = 0;
289 
290    sbi(SFIOR,PSR2);        // Resest Timer Prescaler
291 
292    //start counter
293    TCCR1B = 0x02;          // 0.5 MHz
294 
295    //start timer
296    TCCR2 = 0x07;
297    //sbi(PORTD,5);
298 
299    //some further initializations
300    ready = 0;
301 
302    sbi(TIMSK,OCIE2);               // timer2-compare interrupt on
303    sbi(TIFR,OCF2);                 // terminate active interrupts, if existing
304    sei();
305 
306    while (ready==0) idle();
307 
308    t_gate = 8*(double)CNT/(double)F_CPU;
309    }
310 
311// scan the keyboard
312void scan_keys(void) {
313    uint8_t h1,h2,h3;
314     
315    h1 = PINC;
316 
317    h2 = h1 & 0x10;     // current key0
318    h3 = keys & 0x10;   // previous key0
319    if ((h3==0x10)&&(h2==0x00)) key0on();
320    if ((h3==0x00)&&(h2==0x10)) key0off();
321 
322    h2 = h1 & 0x20;     // current key1
323    h3 = keys & 0x20;   // previous key1
324    if ((h3==0x20)&&(h2==0x00)) key1on();
325    if ((h3==0x00)&&(h2==0x20)) key1off();
326 
327    h2 = h1 & 0x40;     // current key2
328    h3 = keys & 0x40;   // previous key2
329    if ((h3==0x40)&&(h2==0x00)) key2on();
330    if ((h3==0x00)&&(h2==0x40)) key2off();
331 
332    h2 = h1 & 0x80;     // current key3
333    h3 = keys & 0x80;   // previous key3
334    if ((h3==0x80)&&(h2==0x00)) key3on();
335    if ((h3==0x00)&&(h2==0x80)) key3off();
336 
337    keys = h1;
338 
339    }
340 
341 
342// measure one time the current frequency
343void Measure_1(void) {
344 
345    // prepare timer 1 as counter and timer 2 as timer 
346    cli();
347 
348    TCCR1A = 0x00;
349    TCCR1B = 0x00;
350 
351    TCNT1H = 0;
352    TCNT1L = 0;
353 
354    TCCR2 = 0x00;
355    OCR2 = TF;
356    TCNT2 = 0;
357 
358    sbi(SFIOR,PSR2);                // Resest Timer Prescaler
359 
360    //start counter
361    TCCR1B = 0x06;
362 
363    //start timer
364    TCCR2 = 0x07;
365 
366    //some further initializations
367    ready = 0;
368 
369    sbi(TIMSK,OCIE2);               // timer2-compare interrupt on
370    sbi(TIFR,OCF2);                 // terminate active interrupts, if existing
371    sei();
372 
373    while (ready==0) idle();
374 
375    n_CNT++;
376    // ready for next block
377 
378    cbi(TIMSK,OCIE2);               // timer2-compare interrupt off
379    scan_keys();
380     
381    }
382 
383// measure one time the pulse length of the NE555
384void Measure_555_1(void) {
385    cli();                      // disable all interrupts
386    TCCR1A = 0x00;              // prepare timer 1 and ...
387    TCCR1B = 0;                 // ... stop timer 1
388 
389    TCNT1H = 0;                 // set timer1 count value to 0
390    TCNT1L = 0;
391 
392    // start measurement
393    ready = 0;                  // clear the ready status
394    sbi(TIFR,ICF1);             // terminate active interrupts, if existing
395    sbi(TIMSK,TICIE1);          // timer1-capture Interrupt on
396 
397    sbi(SFIOR,PSR10);           // reset prescaler
398    TCCR1B=0x01;                // start Timer 1
399 
400    cbi(PORTD,5);               // start NE555
401    sei();                      // enable interrupts
402    sbi(PORTD,5);               // return to high level
403 
404    while (ready==0) idle();    // wait until ready
405 
406    n_CNT++;                    // this was one more measurement
407    cbi(TIMSK,TICIE1);          // timer1-capture Interrupt off
408    scan_keys();                // the keys
409 
410    }
411 
412// execute the frequency measuremnt n times
413double Measure_M(uint8_t n) {
414    double f;
415    CNT = 0;
416    n_CNT = 0;
417    while (n_CNT<n) Measure_1();
418    cli();
419    f=(double)CNT/((double)n*t_gate);
420    return f;
421    }
422 
423// execute the pulse length measurement n times
424double Measure_555_N(uint8_t n) {
425    double t;
426    CNT = 0;
427    n_CNT = 0;
428    while (n_CNT<n) Measure_555_1();
429    cli();
430    t=(double)CNT/((double)F_CPU*(double)n);
431    return t;
432    }
433 
434// the main program
435int main (void) {
436    uint8_t i,lcmode;
437    double f1,f2,f3,f4,Lx,L3,Cy,t1,t2,C13x,Cxa, Cxb, Cx, R;
438 
439    cli();
440 
441    LCD_Init();
442    printf_P(PSTR("\001\001LC-Meter Evaluation\001\005\001\002 (c) 2005 by DL8NCI\001\005"));
443    for(i=0; i<100; i++) _delay_ms(10.0);
444 
445    sbi(DDRB,4);    // for shorting Lx
446    sbi(DDRB,3);    // for 330 pF
447    sbi(DDRB,2);    // for shorting L0
448 
449    sbi(DDRD,0);    // PD0..PD2 as output
450    sbi(DDRD,1);
451    sbi(DDRD,2);
452 
453    SHORT_LX
454    ON_330
455    SHORT_L3
456 
457    OFF_1k
458    OFF_33k
459    OFF_1M
460 
461    keys = PINC;
462 
463    DDRC = DDRC & 0x0f;     // PC4..PC7 as input
464    PORTC = PORTC | 0xf0;   // PC4..PC7 with Pull Up
465 
466    cbi(PORTD,7);           // PD7 - background light for LCD (LED off)
467    sbi(DDRD,7);            // PD7 as output - LED
468 
469    sbi(DDRD,5);            // PD5 as output
470    sbi(PORTD,5);
471 
472    t_gate = 0;
473    Calibrate();            // determine t_gate
474 
475    mmode = 0;              // the initial measuring mode
476    cmode = 0;              // calibrating mode
477    rmode = 0;              // range
478 
479    // forever ...
480    while(1) {
481 
482    lcmode = cmode;
483 
484    switch (mmode) {
485        case 0: // normal operation with L0 and f1, f2, f3
486            OPEN_L3
487 
488            OPEN_LX
489            OFF_330
490            for(i=0; i<10; i++) { _delay_ms(10.0); }
491            f1=Measure_M(8);    // L0 + Lx; 470 pF + Cx
492 
493            SHORT_LX
494            for(i=0; i<10; i++) { _delay_ms(10.0); }
495            f2=Measure_M(8);    // L0; 470 pF + Cx
496 
497            ON_330
498            for(i=0; i<10; i++) { _delay_ms(10.0); }
499            f3=Measure_M(8);    // L0; 470 pF + 330 pF + Cx
500 
501            if (f1>100) {
502                L3 = (f2*f2-f3*f3)/(4*PI*PI*f2*f2*f3*f3*C15);
503                Cy = (C15*f3*f3)/(f2*f2-f3*f3)-C13;
504                Lx = (f2*f2-f1*f1)*(f2*f2-f3*f3)/(4*PI*PI*f1*f1*f2*f2*f3*f3*C15);
505 
506                if (Lx>0.1) {
507                    printf_P(PSTR("\001\001%7.4f  H  %5.1f pF\001\005"),Lx, Cy*1e12);
508                    }
509                else {
510                    printf_P(PSTR("\001\001%7.2f uH  %5.1f pF\001\005"),Lx*1e6, Cy*1e12);
511                    }
512                printf_P(PSTR("\001\002%7.2f uH  ----- pF\001\005"),L3*1e6);
513                }
514            else {
515                printf_P(PSTR("\001\001------- uH  ----- pF\001\005"));
516                printf_P(PSTR("\001\002------- uH  ----- pF\001\005"));
517                }
518 
519            printf_P(PSTR("\001\003%8.3f %8.3f\001\005"),f1/1000, f2/1000);
520            printf_P(PSTR("\001\004%8.3f %8.3f ms\001\005"),f3/1000, t_gate*1e3);
521            break;
522 
523        case 1: // normal operation with L0 and f1, f2, f4
524 
525            OPEN_L3
526 
527            SHORT_LX
528            OFF_330
529            for(i=0; i<10; i++) { _delay_ms(10.0); }
530            f2=Measure_M(8);    // L0 + Lx; 470 pF + Cx
531 
532            OPEN_LX
533            for(i=0; i<10; i++) { _delay_ms(10.0); }
534            f1=Measure_M(8);    // L0; 470 pF + Cx
535 
536            ON_330
537            for(i=0; i<10; i++) { _delay_ms(10.0); }
538            f4=Measure_M(8);    // L0 + Lx; 470 pF + 330 pF + Cx
539 
540            if (f1>100) {
541                L3 = (f1*f1-f4*f4)/(4*PI*PI*f2*f2*f4*f4*C15);
542                Cy = (C15*f4*f4)/(f1*f1-f4*f4)-C13;
543                Lx = (f2*f2-f1*f1)*(f1*f1-f4*f4)/(4*PI*PI*f1*f1*f2*f2*f4*f4*C15);
544 
545 
546                if (Lx>0.1) {
547                    printf_P(PSTR("\001\001%7.4f  H  %5.1f pF\001\005"),Lx, Cy*1e12);
548                    }
549                else {
550                    printf_P(PSTR("\001\001%7.2f uH  %5.1f pF\001\005"),Lx*1e6, Cy*1e12);
551                    }
552                printf_P(PSTR("\001\002%7.2f uH  ----- pF\001\005"),L3*1e6);
553                }
554            else {
555                printf_P(PSTR("\001\001------- uH  ----- pF\001\005"));
556                printf_P(PSTR("\001\002------- uH  ----- pF\001\005"));
557                }
558             
559            printf_P(PSTR("\001\003%8.3f %8.3f\001\005"),f1/1000, f2/1000);
560            printf_P(PSTR("\001\004%8.3f %8.3f ms\001\005"),f4/1000, t_gate*1e3);
561            break;
562 
563        case 2: // normal operation without L0
564 
565            SHORT_L3
566            OPEN_LX
567 
568            OFF_330
569            for(i=0; i<10; i++) { _delay_ms(10.0); }
570            f1=Measure_M(8);    // Lx, C13, Cy
571 
572            ON_330
573            for(i=0; i<10; i++) { _delay_ms(10.0); }
574            f2=Measure_M(8);    // Lx, C13, Cy, C15
575 
576            if (f1>100) {
577 
578                Lx = (f1*f1-f2*f2)/(4*PI*PI*f1*f1*f2*f2*C15);
579                Cy = ((C13+C15)*f2*f2-C13*f1*f1)/(f1*f1-f2*f2);
580 
581                if (Lx>0.1) {
582                    printf_P(PSTR("\001\001%7.4f  H  %5.1f pF\001\005"),Lx, Cy*1e12);
583                    }
584                else {
585                    printf_P(PSTR("\001\001%7.2f uH  %5.1f pF\001\005"),Lx*1e6, Cy*1e12);
586                    }
587                printf_P(PSTR("\001\002\005"));
588                }
589            else {
590                printf_P(PSTR("\001\001------- uH  ----- pF\001\005"));
591                printf_P(PSTR("\001\002------- uH  ----- pF\001\005"));
592                }
593             
594            printf_P(PSTR("\001\003%8.3f %8.3f\001\005"),f1/1000, f2/1000);
595            printf_P(PSTR("\001\004-------- %8.3f ms\001\005"), t_gate*1e3);
596            break;
597 
598        case 3: // C-Measurement with LC-Oscillator
599 
600            if (cmode==0) {
601                printf_P(PSTR("\001\001     Reference      "));
602                OPEN_L3
603                SHORT_LX
604 
605                OFF_330
606                for(i=0; i<10; i++) { _delay_ms(10.0); }
607                f1=Measure_M(8);    // L3, C13
608 
609                ON_330
610                for(i=0; i<10; i++) { _delay_ms(10.0); }
611                f2=Measure_M(8);    // L3, C13, C15
612 
613                C13x = C15*f2*f2/(f1*f1-f2*f2);
614                L3 = (f1*f1-f2*f2)/(4*PI*PI*f1*f1*f2*f2*C15);
615 
616                printf_P(PSTR("\001\002\001\005"));
617                printf_P(PSTR("\001\003\001\005"));
618 
619                }
620            else {
621                printf_P(PSTR("\001\001Measuring   Mode 6.1"));
622                OPEN_L3
623                SHORT_LX
624 
625                OFF_330
626                for(i=0; i<10; i++) { _delay_ms(10.0); }
627                f3=Measure_M(8);    // L3, C13
628 
629                ON_330
630                for(i=0; i<10; i++) { _delay_ms(10.0); }
631                f4=Measure_M(8);    // L3, C13
632 
633                Cxa = (C15*f2*f2*(f1*f1-f3*f3))/(f3*f3*(f1*f1-f2*f2));
634                Cxb = (C15*f1*f1*(f2*f2-f4*f4))/(f4*f4*(f1*f1-f2*f2));
635 
636 
637                printf_P(PSTR("\001\002%9.2f pF     (a)"),Cxa*1e12);
638                printf_P(PSTR("\001\003%9.2f pF     (b)"),Cxb*1e12);
639 
640 
641                }
642 
643            printf_P(PSTR("\001\004%6.2f uH %7.2f pF"),L3*1e6, C13x*1e12);
644 
645            break;
646 
647 
648 
649        case 4: // C-measurement with NE555
650 
651            switch (rmode) {
652                case 0:
653                    R = 1e6;
654                    OFF_1k
655                    OFF_33k
656                    ON_1M
657                    break;
658                case 1:
659                    R = 33e3;
660                    OFF_1k
661                    ON_33k
662                    OFF_1M
663                    break;
664                case 2:
665                    R = 1e3;
666                    ON_1k
667                    OFF_33k
668                    OFF_1M
669                    break;
670                }
671 
672 
673 
674 
675            if (cmode==0) {
676                printf_P(PSTR("\001\001  NE555  Reference  "));
677                 
678                t1=Measure_555_N(64);
679                printf_P(PSTR("\001\002t1 = %9.2f us\001\005"),t1*1e6);
680 
681                Cy = t1/(1.1*R);
682                printf_P(PSTR("\001\003Cy = %9.2f pF\001\005"),Cy*1e12);
683                }
684            else {
685                printf_P(PSTR("\001\001  NE555  Measurement"));
686                 
687                t2=Measure_555_N(64);
688                printf_P(PSTR("\001\002t2 = %9.2f us\001\005"),t2*1e6);
689 
690                Cx = (t2-t1)/(1.1*R);
691                printf_P(PSTR("\001\003Cx = %9.2f pF\001\005"),Cx*1e12);
692                }
693 
694            printf_P(PSTR("\001\004R  = %4.0f kOhm\001\005"),R*1e-3);
695 
696            for(i=0; i<30; i++) _delay_ms(10.0);
697 
698            break;
699 
700            }
701        }
702    return (0);
703    }