PIC-Programmierung in C (mit CC5X)
(Elektronik)


zurück zu Elektronik, Homepage


4. Umgehen der 1k-Grenze

Zum umgehen der 1k-Grenze sind folgende drei Schritte notwendig:

  1. Aufteilen des Projektes in mehrere C-Dateien
  2. Kompilieren mit einer .BAT-Datei
  3. Zusammenfügen der einzelnen .ASM-Dateien

Die folgende Abbildung zeigt diesen prinzipiellen Vorgang

Prinzipabbildung
nach oben

4.1. Schritt 1: Aufteilen des Projektes in mehrere C-Dateien

Wird also eine C-Datei so groß, dass es beim Kompilieren die 1k-Grenze überschreitet, so muss es in mehrere C-Dateien aufgeteilt werden, wobei auch hier gilt: Jede C-Datei darf beim kompilieren die 1k-Grenze nicht überschreiten!
Im Prinzip sieht dann das gesamte Projekt zum Beispiel folgendermaßen aus:
Hier bestehend aus zwei C-Dateien (Demo2_Teil1.C und Demo2_Teil2.C) und einer Header-Datei (PROJEKT.H).
(Achtung: Es geht hier nur um das Prinzip, daher ist der folgende Code-Ausschnitt kein voll funktionsfähiges Projekt!)

Erste C-Datei (z.B. Demo2_Teil1.C)

/****************************************************************************************/
/* Projekt zur Demo (Umgehung der 1k-Grenze)                                            */
/*                                                                                      */
/* Entwickler: Buchgeher Stefan                                                         */
/* Entwicklungsbeginn der Software: 20. Mai 2006                                        */
/* Funktionsfaehig seit: 20. Mai 2006                                                   */
/* Letzte Bearbeitung: 20. Mai 2006                                                     */
/****************************************************************************************/

/****************** Include-Dateien *****************************************************/
#include "PROJEKT.H"
#include <16CXX.H>                      // Ist fuer die Interrupts notwendig
#include <INLINE.H>                     // Ist fuer Assembleranweisungen notwendig


/****************** Konfigurations-Bits *************************************************/
#pragma config |= 0b.11110100111010


/****************** ISR - Timer0 ********************************************************/

/****************************************************************************************/
/* Interrupt Service Routine (ISR):                                                     */
/****************************************************************************************/
#pragma origin 4

interrupt ISR(void)                    // Interruptroutine
{
    int_save_registers                 // W, STATUS (und PCLATH) retten

    // Beginn der eigentlichen ISR-Routine


    int_restore_registers              // W, STATUS (und PCLATH) Wiederherstellen
}


/****************************************************************************************/
/* INIT:                                                                                */
/*                                                                                      */
/* Aufgabe:                                                                             */
/*   Initialisierung des Prozessor:                                                     */
/****************************************************************************************/
void INIT(void)
{
    // Timer-0-Interrupt
    TMR0 = 0;                          // Timer 0 auf 0 voreinstellen
    OPTION = 0b.1000.0011;             // Pull-Up-Widerstaende am Port B deaktivieren
                                       // Timer-ISR (Vorteiler = 16)

    // Ports
    TRISA = 0xFF;                      // Port A  und Port E muessen bei verwendung als
    TRISE = 0xFF;                      //   ADC als Eingang konfiguriert werden
    TRISB = 0;                         // Port B als Ausgang definieren
    TRISC = 0b.1111.1001;              // Port C: Bits 1 und 2 als Ausgang definieren
                                       // Port C: Bits 0 und 3 bis 7 als Eingang definieren
    TRISD = 0;                         // Port D als Ausgang definieren

    // ADC
    ADON = 1;                          // ADC global einschalten
    ADCON1 = 0b.1000.0010;             // Ganzer Port A als Analog; Vref+ = Vdd, Vref- = Vss
                                       //   und linksbuendig
    ADCS0 = 0;                         // Geschwindigkeit des ADC mit ADCS0 und ADCS1
    ADCS1 = 1;

    // usw.
}


void delay_us(char mikro)
{
    #asm
    wdh9   nop
           nop
           decfsz  mikro,f
           goto    wdh9
    #endasm
}


/****************** Unterprogramm zur Analog-Digital-Wandlung ***************************/

/****************************************************************************************/
/* ADC:                                                                                 */
/*                                                                                      */
/* Aufgabe:                                                                             */
/*   Analog-Digital-Wandlung mit dem PIC-interne ADC fuer den ausgewaehlten ADC-Kanal   */
/*   starten, auf das Wandlungsergebnis warten und dieses dem aufrufenden Programm      */
/*   zurueckgeben.                                                                      */
/*                                                                                      */
/* Uebergabeparameter:                                                                  */
/*   kanal:                                                                             */
/*                                                                                      */
/* Rueckgabeparameter:                                                                  */
/*   6-Bit-Ergebnis der Analog-Digital-Wandlung im EXTERNEN UEBERGABEREGISTER           */
/*   (tmp_uebergabe_uns16)                                                              */
/*                                                                                      */
/* Vorgehensweise:                                                                      */
/*   + ADC-Kanal auswaehlen (Bits <3:5> im Register ADCON0). Dazu muss die Kanal-Nummer */
/*     an diese Position geschoben werden und mit dem Register ADCON0 verknuepft werden */
/*   + ca. 50 Mikrosekunden (us) warten. Diese Zeit benoetigt der PIC um den internen   */
/*     Kondensator mit der zu messenden Analogspannung zu laden.                        */
/*   + Analog-Digital-Wandlung starten. Dazu das Flag GO (im Register ADCON0) setzen.   */
/*   + Warten, bis der PIC mit der Wandlung fertig ist. Der PIC setzt das Flag GO auto- */
/*     matisch zurueck, wenn er mit der Analog-Digital-Wandlung fertig ist.             */
/*   + Aus den Registern ADRESL und ADRESH das Ergebnis zusammensetzen und an das auf-  */
/*     rufende Unterprogramm (oder Hauptprogramm) zurueckgeben                          */
/*                                                                                      */
/* Anmerkung:                                                                           */
/*   Das Ausgabeformat der ADC-Wandlung, also wie die 10 Ergebnisbits in den Registern  */
/*   ADRESL und ADRESH abgelegt werden wird an anderer Stelle (z.B. im Unterprogramm    */
/*   INIT) konfiguriert.                                                                */
/****************************************************************************************/
void ADC(char kanal)
{
    ADCON0 = ADCON0 & 0b.1100.0111;
    kanal = kanal << 3;
    ADCON0 = ADCON0 | kanal;

    delay_us(50);

    GO = 1;
    while(GO);

    tmp_uebergabe_uns16.low8 = ADRESL; // externes Uebergaberegister
    tmp_uebergabe_uns16.high8 = ADRESH;
}


/****************** Hauptprogramm *******************************************************/
void main(void)
{
    char Wert1;

    INIT();                            // Controller initialisieren

    INTCON = 0b.1010.0000;             // Timer0 freigeben durch Setzen von
                                       // GIE und T0IE im Register INTCON
    while(1)
    {
        // aktuelle Werte einlesen
        Soll_Istwerte_einlesen();

        // Test-Routine
        UNTERPROGRAMM2();
        Wert1 = UNTERPROGRAMM3(123);
    }
}

Zweite C-Datei (z.B. Demo2_Teil2.C)

/****************************************************************************************/
/* Unterprogramme zur Demo (Umgehung der 1k-Grenze)                                     */
/*                                                                                      */
/* Entwickler: Buchgeher Stefan                                                         */
/* Entwicklungsbeginn der Software: 20. Mai 2006                                        */
/* Funktionsfaehig seit: 20. Mai 2006                                                   */
/* Letzte Bearbeitung: 20. Mai 2006                                                     */
/****************************************************************************************/

/****************** Projekt-Header einbinden ********************************************/
#include "PROJEKT.H"


/****************** externe Register ****************************************************/
uns16 tmp_uebergabe_uns16;

uns16 sollwert;
uns16 istwert;


/****************** weitere Unterprogramme **********************************************/

/****************************************************************************************/
/* Unterprogramm 2                                                                      */
/*                                                                                      */
/****************************************************************************************/
void UNTERPROGRAMM2(void)
{
    // irgendwelche Anweisungen

}


/****************************************************************************************/
/* Unterprogramm 3                                                                      */
/*                                                                                      */
/****************************************************************************************/
char UNTERPROGRAMM3(char Parameter)
{
    char wert;

    // irgendwelche Anweisungen

    return (wert);
}


/****************** Unterprogramm zur Ist- und Sollwerteingabe **************************/

/****************************************************************************************/
/* ADC:                                                                                 */
/*                                                                                      */
/* Aufgabe:                                                                             */
/*   Sollwert und Istwert von den analogen Eingaengen AN0 und AN1 einlesen und in den   */
/*   externen Registern istwert und sollwert sichern                                    */
/****************************************************************************************/
void Soll_Istwerte_einlesen (void)
{
    // Istwert von ADC-Eingang AN0 (Kanal 0) einlesen und in der externen Variable
    //   istwert sichern
    ADC(0);
    istwert = tmp_uebergabe_uns16;

    // Sollwert von ADC-Eingang AN2 (Kanal 2) einlesen und in der externen Variable
    //   sollwert sichern
    ADC(1);
    sollwert = tmp_uebergabe_uns16;
}

Gemeinsame Header-Datei (z.B. PROJEKT.H)

/****************************************************************************************/
/* Header zur Demo (Umgehung der 1k-Grenze)                                             */
/*                                                                                      */
/* Entwickler: Buchgeher Stefan                                                         */
/* Entwicklungsbeginn der Software: 20. Mai 2006                                        */
/* Funktionsfaehig seit: 20. Mai 2006                                                   */
/* Letzte Bearbeitung: 20. Mai 2006                                                     */
/****************************************************************************************/

#ifndef  __PROJEKT
#define  __PROJEKT


/****************** Pragma-Anweisungen **************************************************/
#pragma chip PIC16F877                 // PICmicro Device


/****************** Externe Register  ***************************************************/
extern bank0 uns16 tmp_uebergabe_uns16;

extern bank0 uns16 sollwert;
extern bank0 uns16 istwert;


/****************** Funktionsprototypen *************************************************/
/* Initialisierung des Mikrocontroller */
extern page0 void INIT(void);

/* Unterprogramm zur Analog-Digital-Wandlung */
extern page0 void ADC(char kanal);

/* Unterprogramm zur Ist- und Sollwerteingabe */
extern page0 void Soll_Istwerte_einlesen(void);

/* Weitere Unterprogramme */
extern page0 void UNTERPROGRAMM2(void);
extern page0 char UNTERPROGRAMM3(char Parameter);

#endif
nach oben

4.2. Schritt 2: Kompilieren mit einer .BAT-Datei

Im nächsten Schritt wird nun jede C-Datei (mit Hilfe des CC5X-Compilers) in eine ASM-Datei kompiliert. Diese Aufgabe übernimmt eine BAT-Datei. Dazu geht man wie folgt vor:

  1. Im Projektordner eine neue Textdatei erzeugen. Der Name der Datei ist egal, wichtig ist nur die Endung .bat. (Also z.B. Demo2.bat). Es entsteht also eine Datei vom Typ Stapelverarbeitungsdatei für MS-DOS.
  2. Diese Datei (Demo2.bat) mit der rechten Maustaste anklicken und im Pop-Up-Menü bearbeiten auswählen. Im Editor nun die folgenden Einträge einfügen:
          C:\Programme\bknd\CC5X\CC5X.EXE Demo2_Teil1.C -IC:\Programme\bknd\CC5X\ -u -r -a -r2
          C:\Programme\bknd\CC5X\CC5X.EXE Demo2_Teil2.C -IC:\Programme\bknd\CC5X\ -u -r -a -r2
          
    Hinweise:
  3. Editor schließen (Datei natürlich vorher speichern)
  4. Batch-Datei (hier Demo2.bat) mit einem Doppelklick ausführen. Wenn in den C-Dateien alles richtig ist (also die Syntax) werden die dazugehörigen .ASM-Dateien erzeigt (hier Demo2_Teil1.ASM bzw. Demo2_Teil2.ASM). Bei einem Syntaxfehler (in der C-Datei) wird die eventuell schon vorhandene .ASM-Datei gelöscht, und die .OCC-Datei gibt Auskunft über die aufgetretenen Syntaxfehler.
nach oben

4.3. Schritt 3: Zusammenfügen der einzelnen .ASM-Dateien

Die im vorhergehenden Schritt erzeugten Assembler-Dateien müssen nun zu einem gesamten Projekt zusammengefügt werden. Und schließlich soll daraus die zum Programmieren des PIC notwendige .HEX-Datei erzeugt werden. Dazu geht man wie folgt vor:

MPLAB starten -> Project -> Project Wizard...

Taste Weiter >

PIC auswählen (hier den PIC16F877)

Taste Weiter >

Active Toolsuite: B Knudsen Data CC5x auswählen

Taste Weiter >

Den Projektordner auswählen, wo dieses Beispiel-Projekt abgelegt werden soll. Dieser Ordner muss schon existieren!

Projektname eingeben (hier: Demo2). Anmerkung: der Projektname muss nicht identisch mit dem Ordnername sein!

Taste Weiter >

Zunächst in der rechten Spalte die Linker-Datei 16f877.lkr auswählen und die Taste Add >> anklicken. Die ausgewählte Datei erscheinen nun in die rechte Spalte. Diesen Vorgang für alle Assembler-Dateien (hier also Demo2_Teil1.asm und Demo2_Teil2.asm) und die Header-Datei PROJEKT.H wiederholen.

Taste Weiter >

Taste Fertig stellen

Project -> Build

Für jede Assembler-Datei sollte nun nacheinander die Box Assembly Successful erscheinen. Diese muss jedes Mal mit der OK-Taste bestätigt werden. Wichtig ist die Meldung BUILD SUCCEEDED am Ende der Assemblierung.

nach oben


zurück zu Elektronik, Homepage

Autor: Buchgeher Stefan
Erstellt: 23. Juli 2006
Letzte Änderung: 24. Juli 2006