#include "allpic.h" #pragma config = 0b000000001101 // grundkonfiguration des PICs //#define JUST 1 #define OSC_JUST 3 // genau auf 1 MHz am Pin 3 abgleichen #define TONE_OUT 0 // hier kommt die PWM raus #define LADUNG 1 // "Masse" des 100k/10k Spannungsteilers #define LINE_IN 2 // "Schleifer" des Spannungsteilers auf ST #define NC_3 3 // konstant auf Masse #define CLK_OUT 4 // Testausgang für OSC_JUST #define TEST_OUT 5 // Debug-Ausgang #define _GIE 7 #define MAX_ZIFFER 40 // so viele ziffern werden gespeichert #define make_save_regs unsigned char s1, s2 #define save_W { s1 = W;} #define restore_W { s1 = swap(s1); W = swap(s1);} #define save_regs { save_W; s2 = swap(STATUS); } #define restore_regs_return { STATUS = swap(s2); restore_W; return; } uns8 tlow; // lowtimer für MFV im ISR #pragma origin 4 interrupt server(void) // ISR { /*** takte einzeln gezählt, um schleife abzugleichen ***/ make_save_regs; // sicherungsregister deklarieren save_regs; // W, STATUS retten GPIO.TONE_OUT = FALSE; // port aus TMR0 = ~tlow; // schnell den timer neu setzen T0IF = T0IE = FALSE; // ints aus restore_regs_return; // W and STATUS } #include "timeloop.h" // 16 bit DDS algorithm for dual simultaneous sinewaves with 1 MHz timer // Step = f_soll * 64 (Länge der Tabelle = obere 6 Bits) // * 1024 (untere 10 Bits des Akkus) * 0.0001 (PWM-Periode = 100 us) #define ROW_0 4568 // 697 Hz DTMF zeilen #define ROW_1 5046 // 770 Hz #define ROW_2 5584 // 852 Hz #define ROW_3 6167 // 941 Hz #define COL_0 7923 // 1209 Hz DTMF spalten #define COL_1 8756 // 1336 Hz #define COL_2 9680 // 1477 Hz // tabellen auf 100us abgeglichen! const uns8 sine64col[64] = { // hohe frequenz = hohe amplitude 40,44,48,51,55,58,62,65,68,70,72,74,76,77,78,79, 79,79,78,77,76,74,72,70,68,65,62,58,55,51,48,44, 40,36,32,29,25,22,18,15,12,10, 8, 6, 4, 3, 2, 1, 1, 1, 2, 3, 4, 6, 8,10,12,15,18,22,25,29,32,36}; const uns8 sine64row[64] = { // kleine frequenz = kleine amplitude 40,43,45,48,50,53,55,57,59,61,63,64,65,66,67,67, 67,67,67,66,65,64,63,61,59,57,55,53,50,48,45,43, 40,37,35,32,30,27,25,23,21,19,17,16,15,14,13,13, 13,13,13,14,15,16,17,19,21,23,25,27,30,32,35,37}; void dtmf(uns8 code) { uns16 col, row, waveA, waveB; switch(code) { case 1: case 2: case 3: row = ROW_0; break; case 4: case 5: case 6: row = ROW_1; break; case 7: case 8: case 9: row = ROW_2; break; case 10: row = ROW_3; break; default: return; // damit kann ich nichts anfangen } switch(code) { case 1: case 4: case 7: col = COL_0; break; case 2: case 5: case 8: case 10: col = COL_1; break; case 3: case 6: case 9: col = COL_2; break; default: return; // damit kann ich nichts anfangen } waveA = waveB = 0; // phasenakkus resetten uns16 zyklen = 500; // 50 ms einpegeln lassen while(--zyklen) { // ....da pwm-schleife 100us dauert while(GPIO.TONE_OUT); // synchronisation! high-zeit abwarten while(!T0IF); // low-zeit abwarten /*** takte einzeln gezählt, um schleife abzugleichen ***/ tlow = 40; // 10 Takte Latenz, 40 T0-Takte GPIO.TONE_OUT = TRUE; TMR0 = ~40; // 1:1 verhältnis = 100us T0IF = FALSE; // flags aus T0IE = TRUE; // ints scharf schalten } zyklen = 500; // gibt 50 ms Tonsignal while(--zyklen) { // ....da pwm-schleife 100us dauert waveA += row; // schon mal alles ausrechnen uns8 tmp = waveA.high8 >> 2; // nur die obene 6 Bits nehmen uns8 pwm = sine64row[tmp]; // niedrige frequenz.. niedrige amplitude waveB += col; tmp = waveB.high8 >> 2; // nur die oberen 6 Bits nehmen pwm += sine64col[tmp]; // hohe frequenz.. hohe amplitude pwm >>= 1; // auf 100us runterskalieren while(GPIO.TONE_OUT); // synchronisation! high-zeit abwarten while(!T0IF); // low-zeit abwarten /*** takte einzeln gezählt, um schleife abzugleichen ***/ tlow = 80 - pwm; // timer neu aufsetzen: low-zeit GPIO.TONE_OUT = TRUE; TMR0 = ~pwm; // jetzt schnell den timer setzen T0IF = FALSE; // flags aus T0IE = TRUE; // ints scharf schalten } } #define WDT_mal_2_hoch(d) { /* 17 ms mal 2 hoch x */\ RP0 = 1; /* spezialregister */\ OPTION = 0b00001000 | (d); /* WDT-Teiler setzen, Pullups enable */\ RP0 = 0; /* normalregister */\ clrwdt(); /* wdt resetten */\ } #define WAIT_1MS { \ clrwdt(); \ usec100(10); \ } #define WAIT_10MS { \ clrwdt(); \ usec100(100); \ } void main(void) { WDT_mal_2_hoch(7); // bitte keine störungen RP0 = 1; // erstmal alle spezialregister... #asm DW /*CALL*/ 0x2000 + /*ADRESSE*/ 0x03FF // oscal abholen #endasm OSCCAL = W + (OSC_JUST << 2); // osc kalibration justieren INTCON = (1 << _GIE); // interrupts erlauben TRISIO = (1 << LINE_IN) | (1 << NC_3); WPU = 0; // keine pullups RP0 = 0; // nun die normalen register und ram CMCON = 0b00000111; // komparator aus, spart strom GPIO = 0; // alle portpins auf low // das war nur init des pics. jetzt gehts erst richtig los... timeloop_init(); #ifdef JUST FOREVER; // OSC_JUST #endif uns8 ziffer, oldziff, nummer[MAX_ZIFFER], ind;// ziffernspeicher uns16 msec; // für timeouts restart: WDT_mal_2_hoch(2); // warte auf high do { sleep(); } while(!GPIO.LINE_IN); // warte auf schleifenspannung do { // warte auf low, lade akku GPIO.LADUNG = TRUE; sleep(); // leg dich schlafen GPIO.LADUNG = FALSE; } while(GPIO.LINE_IN); // warte auf hörerabnahme WDT_mal_2_hoch(5); // halbe sekunde warten sleep(); // stromsparend warten if(GPIO.LINE_IN) goto restart; // abbruch, wenn low instabil WDT_mal_2_hoch(7); // ab nun samplen im msec-raster! msec = 0; // timeout vorbereiten do { // warte auf high-flanke WAIT_1MS; // zeit vermessen in ms-Steps if(!--msec) goto restart; // timeout erkannt } while(!GPIO.LINE_IN); ind = ziffer = 0; // ziffer neu befüllen FOREVER { msec = 0; while(!GPIO.LINE_IN) { // warte auf high WAIT_1MS; // zeit vermessen in ms-Steps if(msec == 100) { // eine ziffer beendet, nächste ziffer oldziff = nummer[ind]; // erste ziffer retten nummer[ind] = ziffer; // neue ziffer speichern if(++ind >= MAX_ZIFFER) goto restart; // überlauf ziffer = 0; // nächste pulsezählung vorbereiten } if(++msec > 2000) { // alle ziffern fertig? if(ind) { // ist überhaupt was zu wählen? if((ind == 1)&&(nummer[0] == 1)) // kurzwahl nummer[0] = oldziff; // erste ziffer restaurieren else nummer[ind] = 0; // ende-marker setzen ind = 0; // wählschleife while(nummer[ind]) { // wähle bis ende-marker clrwdt(); dtmf(nummer[ind++]); } msec10(10); // noch etwas abwarten } goto restart; // alles fertig } } WAIT_10MS; // nach 10 ms immer noch high? if(!GPIO.LINE_IN) goto restart; // leider nicht, also abbruch ziffer++; // ein weiterer impuls gezählt msec = 0; // high-impuls zählen while(GPIO.LINE_IN) { // warte auf low-flanke WAIT_1MS; // zeit vermessen in ms-Steps if(++msec > 200) goto restart; // timeout erkannt } } } /* ENDE */