Za tiste, ki C-ja ne poznajo, podajam kratek opis programa. C-program sestoji iz funkcij, ki jih kliče med izvajanjem programa. Funkcija, ki jo pokličemo prvo, pri zagonu programa, je vedno funkcija “main()” in to je edina funkcija, ki je v programu obvezna. Po potrebi se definirajo tudi druge funkcije; ker je naš primer zelo enostaven, druge funkcije niso bile potrebne ter se vsa koda nahaja znotraj funkcije main(). Na začetku se določijo smeri posameznih portov z vpisom ustreznih vrednosti v registra TRISA in TRISB. Prav tako se določijo parametri mikrokontrolerja z vpisom ustreznih vrednosti v registra OPTION in INTCON. Ker se v tem demo programu ne uporabljajo opcije (prekinitve, TMR0, WDT), so vpisane vrednosti 0.
Nato sledi deklaracija spremenljivke “i”, ki jo uporabljamo kot števec v zanki. Za razliko od standardnega C-ja, ki ga nekateri verjetno že poznajo, deklaracija spremenljivk ne mora biti na začetku funkcije, kot je to v C-ju običajno. Spremenljivka “i” je tipa “char”. Zakaj ne “int”? V CC5X je tip “int” 8-bitno celo število s predznakom (in z razponom vrednosti od –127 do 127), medtem ko je “char” 8-bitni podatek z razponom vrednosti 0-255. Torej je “char” primernejši izbor za števce.
Za definicijo spremenljivke sledi glavna zanka. Najprej se števec “i” poveča za ena (i++ je pravzaprav i=i+1), nato sledi preverjanje, ali je števec dosegel 100. Vrednost 100 določa trajanje cikla, to je čas, v katerem je LED-ica prižgana ali ugasnjena. Ko vrednost števca doseže 100, se invertira bit 0 porta B, števec se vrne na nič in cikel štetja se začne od začetka.
Poglejmo si sedaj generirano asemblersko kodo:
; CC5X Version 3.1J, Copyright (c) B Knudsen Data
; C compiler for the PICmicro family
;
************ 29. Sep 2003 12:20 *************
processor 16F84
radix DEC
TRISA EQU 0x85
PORTB EQU 0x06
TRISB EQU 0x86
INTCON EQU 0x0B
Carry EQU 0
RP0 EQU 5
OPTION_REG EQU 0x81
i EQU 0x0C
GOTO main
; FILE C-compiler.c
;
;void main()
;{
main
; TRISA=0; //vsi pini porta A so izhodni
BSF 0x03,RP0
CLRF TRISA
; TRISB=0; //vsi pini porta B so izhodni
CLRF TRISB
; OPTION_REG=0; //vrednost registra OPTION
CLRF OPTION_REG
; INTCON=0; //prekinitev ne uporabljamo
CLRF INTCON
;
; char i; //dekaracija spremenljivke števca
;zanka:
; i++; //i=i+1
m001 INCF i,1
; if (i<100) goto zanka;//i=100 -> žtrajanje enega cikla
MOVLW .100
SUBWF i,W
BTFSS 0x03,Carry
GOTO m001
; PORTB.0=!PORTB.0; //prižgi-ugasni LED-ico
MOVLW .1
BCF 0x03,RP0
XORWF PORTB,1
; i=0; //začetek novega cikla
CLRF i
; goto zanka; //vrnitev v zanko
GOTO m001
;}
END
; *** KEY INFO ***
; 0x0001 15 word(s) 0 % : main
; RAM usage: 1 bytes (1 local), 67 bytes free
; Maximum call level: 0
; Total of 16 code words (1 %)
Uporabljena je samo ena lokacija RAM-a (spremenljivka “i”), celoten program pa je realiziran s samo 16 instrukcijami. Kot sem že prej omenil, je vsaka C-instrukcija navedena kot komentar, za katerim sledi njen asemblerski prevod. Mislim, da nobene instrukcije ni mogoče realizirati z manj asemblerske kode od te, ki jo je generiral prevajalnik CC5X. Še več, če bi program napisal v asemblerju, bi izgledal enako kot generirana koda!
Seveda na osnovi enega samega enostavnega primera ni mogoče skleniti splošnega zaključka o kakovosti prevajalnika, bilo bi ga potrebno testirati na zahtevnejših aplikacijah in kompleksnejših programih. CC5X sem odkril šele pred kratkim in sem napisal šele nekaj programov, vendar lahko povem, da vsi ti programi delujejo brez težav in da do sedaj nisem imel razloga za dodatno optimzacijo asemblerske kode. Čeprav je po podatkih proizvajalca v brezplačni download verziji zmanjšan obseg optimizacije (ažuriranje pomnilniških bank in večkratno nalaganje v delovni (W) register), do sedaj nisem naletel na kodo, ki ne bi bila popolnoma optimirana.
Virtualna trgovina, nakup brošure in informacije!
Avtor: Darko Dužanec
Ljubljana, avgust 2004