William Sandqvist Melodispelaren Denna demonstrationslaboration visar, steg för steg, hur man skriver ett kort program i programspråket C, och hur man "laddar ned det" det till en PIC-krets ( Perpherial Interface Computer ) med en kretsprogrammerare. Om PIC-kretsen förses med några elektroniska kringkomponenter kan den sedan utföra den uppgift den programmerats för. Som programmeringsuppgift har vi valt att låta PIC-kretsen spela upp en melodi. Detta är inte bara en "lek", utan det kan faktiskt vara en viktig funktion hos en datorstyrd konsumentprodukt av idag. Möjligheten att få en personlig ringsignal till sin mobiltelefon har varit ett av de viktigaste konkurensmedlen mellan mobiltelefontillverkarna! Uppgiften är tillräckligt komplex för att visa PIC-kretsens möjligheter, och för den delen, egenheter. Som programmeringsuppgift kommer Du sedan att få välja en egen uppgift som Du realiserar med en likadan PIC-krets.
William Sandqvist Stämgaffel Vi börjar med att göra en "stämgaffel", det vill säga låta PIC-kretsen avge en kontinuerlig 440 Hz ton.
William Sandqvist playtone.c /* playtone.c Generates a 440 Hz "A4" tone */ /* Use processor 16F628 */ #include " 16F628.h " #pragma config |= 0x3f90 void main(void ) { char note = 114; /* gives pitch A4 440 Hz */ TRISB = 0b ; /* B.0 is output */ while (1) /* forever */ { char i; /* local variable */ for(i = note; i > 0; i--) { /* Delay. Loop + nop()'s totals 10 us */ nop(); nop(); nop(); nop(); } PORTB.0 = !PORTB.0; /* Toggle bit B.0 */ } }
William Sandqvist Delay 10 s När man kompilerar C-programmet får man också en fil med motsvarande assemblerkod! Man undersöker assemblerkoden, varje instruktion kommer att ta 1 s, förutom hoppinstruktioner som tar 2 s. Vid behov ”kryddar” man med att lägga till eller ta bort någon NOP, nop() i C-koden. ; The 10 us delay loop. m002 MOVF i,1 ; 1 us BTFSC 0x03,Zero_ ; 2 us (When skipped) GOTO m003 ; NOP ; 1 us NOP ; 1 us NOP ; 1 us NOP ; 1 us DECF i,1 ; 1 us GOTO m002 ; 2 us ; Total of 10 us!
William Sandqvist Hela skalans toner … Tabellen innehåller tal mellan 51…255. Bland de lediga talen låter vi 0 betyda “slut på melodin” och 1 betyda “paus”.
William Sandqvist TIMER0 TIMER0 är en 8-bitars modulo 256-räknare som kan läsas/skrivas med program. Om biten TOCS i OPTION -registret är "0" så räknas var fjärde av processorns klockcykler ( Fosc/4 ). Om biten TOCS är "1" räknas de pulsflanker som inkommer på pinnen T0CKI. Med biten TOSE bestämmer man om det är positiva eller negativa "flanker" som ska räknas. Med biten PSA =0 kan man koppla in en prescaler, en frekvensdelare. Med den inkopplad räknas bara en bråkdel av de inkommande pulserna, och det tar då längre tid innan TIMER0 "räknar runt". Med bitarna PS2 PS1 PS0 ställer man in prescalerns delningstal.
William Sandqvist Melodyplayer Alla noter är 1/8 långa. En ”helnot” får man genom att upprepa 1/8 not 8 ggr. Funktionen LookUpNote( i) returnerar melodins not nr i. Notvärdet 0 betyder att melodin är slut och notvärdet 1 att det är en paus.
William Sandqvist Computed GoTo ? PIC-processorns instruktioner är 14 bitar långa. Konstanter, sk "literals", lagras i programminnet inbakade i instruktioner. Tabellvärden lagras i med assemblerinstruktionen RETLW k ( RETurn with Litteral in W ), där k är den 8 bitars konstant som ska bakas in i instruktionen. Om processorn "hoppar" till en sådan instruktion, skickas den tillbaks med talet k i arbetsregistret, W-registret. Vid assemblerprogrammering används detta tillsammans med indexerad adressering så att man med hjälp av ett index kan styra vilken av tabellens konstanter man ska komma tillbaks med. Detta kallas för Computed GOTO.
William Sandqvist Tabell i assemblerprogram CALL TABLE ; W contains table offset... TABLE ADDWF PC ; W = offset, go to offset table entry RETLW k1 ; Begin table, return with k1 in w RETLW k2 ; return with k2 in w RETLW k3 ; End of table, return with k3 in w Tabell i assemblerprogram. k1 k2 k3 är tabellens tre konstanter. Det finns inget "självklart" sätt att utrycka detta med C-språket. B Knutsen har infört en (inbyggd) funktion skip(i) som ska lösa detta. Denna betyder att man hoppar över det antal C-instruktioner som anges med "i".
William Sandqvist Tabell i C-program char table(char i) { skip(i); /* internal function in CC5X */ return k1; return k2; return k3; } Exempel C-funktion (enligt CC5X). k1 k2 k3 är tabellens tre konstanter.
William Sandqvist En melodi char LookUpNote(char W) { skip(W); /* internal function to CC5X compiler */ return 1; /* Pause */ return 76; /* E5 */ return 85; /* D5 */ return 76; /* E5 */ return 76; return 76; return 76; return 114; /* A4 */ return 114; return 114;... return 101; /* B4 */ return 101; return 1; /* Pause */ return 0; /* End */ } Här använder vi arbetsregistret W som variabel, på så sätt ”sparar” vi en lokal variabel i funktionen. Provkör programmet så får Du veta vilken melodi det är …