R8C Codebeispiele

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche
R8c hello world led.gif

Hello World ;-)

Das typische hello world Programm für einen Mikrocontroller ist wohl eine blinkende LED.

Mit so einem sehr einfachen Beispiel kann man grundlegend die Installation und Funktionsfähigkeit der Entwicklungstools und der Hardware testen.

Beim folgenden Beispiel wird davon ausgegangen, dass eine LED mit der Anode (+) an Port 1.0 angeschlossen ist und über einen 1 KOhm Widerstand von Kathode (-) zu GND (Vss).

/* Definitionen der SFR (special funktion register) einbinden */
#include "sfr_r813.h"

void main(void)
{
   /* Port Direction Register 1.0 */
   /* = Pin 0 an Port 1 auf Ausgabe (Output) schalten */
   pd1 |= 0b00000001;   

   /* für immer und ewig... */
   while(1)
   {
      unsigned long i;
   
      /* Port 1.0 zwischen HIGH und LOW umschalten */
      p1_0 ^= 1;

      /* etwas warten... */
      for (i = 0; i < 123456UL; i++)
         ;
   }
}

Vorschläge fürs weitere Experimentieren?

Dieses Beispiel läuft mit dem CPU Takt, den der R8C nach einem RESET besitzt. Das sind 1/8-tel Taktfrequenz des low speed oscillator, d. h. 125/8 KHz.

  • Wie ändert sich die Blinkfrequenz, wenn eine externe Taktquelle benutzt wird?
  • Wie kann man im Programmcode beide Varianten berücksichtigen?

Studieren geht über Probieren!

  • Wenn man pdx und px_y im Programm anpasst, ist es dann egal, an welchen Output-Pin die LED angeschlossen wird?
  • Wieviele LEDs kann man anschliessen und betreiben?

Externen Haupttakt einschalten

Der Haupttakt (main clock) des R8C kann von internem Oszillator (on-chip oscillator) auf einen externen Oszillator (0-20 MHz) umgestellt werden. Das Verfahren dazu ist im R8C Hardware Manual Kapitel 6 beschrieben.

Es muss natürlich externe Taktquelle (z. B. Quarz) funktionsfähig angeschlossen sein. Es folgt ein Beispiel für den R8C/13, so wie er inklusive 20 MHz Quarz auf der Prozessorplatine von Glyn/Elektor zu finden ist:

/* Definitionen der SFR (special funktion register) einbinden */
#include "sfr_r813.h"

void Init_Takt_Extern(void)
{
   prc0 = 1;   /* 1 = Schreibschutz für wichtige SFR aufheben */

   /* Anschluss festlegen */
   cm13 = 1;   /* 1 = 'main clock' ist an XIN-XOUT Pins angeschlossen */
   cm15 = 1;   /* 1 = 'XIN-XOUT drive capacity' HIGH */
   cm05 = 0;   /* 0 = 'main clock stop bit' (XIN-XOUT) ON */
               /*      d.h. Pins XIN-XOUT nicht abschalten */

   /* Taktrate festlegen */
   cm16 = 0; 
   cm17 = 0;
   cm06 = 0;   /* 0 = 'CPU clock division' durch cm16 und cm17 bestimmt */
               /* cm16=0 und cm17=0 => kein Teilung des Taktes */

   /* kurz warten bis externe Taktquelle stabil läuft */
   asm("nop"); 
   asm("nop");
   asm("nop");
   asm("nop");

   /* CPU Takt auf gerade festgelegte externe Taktquelle umschalten */
   ocd2 = 0;   /* 0 = 'main clock' als CPU clock auswählen */

   prc0 = 0;   /* Schreibschutz für wichtige SFR wieder einschalten */
}

Vorschläge fürs weitere Experimentieren?

Diese Funktion schaltet nur die externe Taktquelle ein und zwar mit full speed.

  • Wie kann man auf einen der beiden internen Oszillatoren (high speed 8 MHz / low speed 125 KHz ) zurückschalten?
  • Wie kann man feststellen, mit welchem Takt gearbeitet wird?

Studieren geht über Probieren!

  • Was passiert beim Ausfall des externen Oszillators?


Serielle Datenübertragung (Polling-Verfahren)

Im folgenden Codebeispiel wird die Initialisierung der seriellen Schnittstelle des R8C/13 und das Empfangen/Senden einzelner Zeichen gezeigt.

Als serielle Schnittstelle des R8C/13 wird UART0 benutzt, da UART1 z. B. auf dem Elektor-Applikationsboard bereits durch den Debugger belegt ist.

Die Übertragung wird bei 19200 Baud, 8 Datenbits, 1 Startbit (unveränderlich), 1 Stopbit und keine Parität und kein Handshake durchgeführt. Das Terminalprogramm auf dem PC muss entsprechend eingestellt sein.

Beim Polling-Verfahren wird die serielle Schnittstelle im Anwendungsprogramm von Hand zu Fuß? bedient.

/* Definitionen der SFR (special funktion register) einbinden */
#include "sfr_r813.h"

#define F_OSC      20000000UL
#define BITRATE      19200UL

/* Implementierung siehe R8C Codebeispiel */
extern void Init_Takt_Extern(void);

void uart0_willkommen(unsigned char *stext);

void main(void)
{
   /* Auf extern 20 MHz umschalten */
   Init_Takt_Extern();   

   /* 
   ** UART0 initialisieren 
   ** Clock Asynchrous Serial I/O (UART) Mode
   ** s. a. Hardware Manual Kap. 13 Serial Interface
   **
   ** Anm.: UART1 ist vom Debugger belegt.
   */

   /* 
   ** 'UART0 bit rate generator' setzen abhängig
   ** von (externem) Takt und gewünschter Bitrate 
   ** Hardware Manual Kap. 12.2.3
   */
   u0brg = (unsigned char) (((F_OSC) / ((BITRATE) * 16)) - 1);

   /*
   ** Übertragungsformat einstellen
   */

   /* 8 Datenbits einstellen */
   smd0_u0mr    = 1;
   smd1_u0mr    = 0;
   smd2_u0mr    = 1;
   /* Internal (!) Takt auswählen */
   ckdir_u0mr = 0; 
   /* 1 Stopbit auswählen */
   stps_u0mr = 0;
   /* Parity disable (none) */
   prye_u0mr = 0; 

   /*
   ** Übertragung erlauben
   */

   /* Enable Transmission */
   te_u0c1 = 1;
   /* Enable Reception */
   re_u0c1 = 1;

   /* 
   ** Terminal löschen 
   ** FORMFEED hex. 0x0C oct. 014
   ** + Begrüssungstext
   */
   uart0_willkommen("\014R8C/13 UART0 Codebeispiel\n\r");

   /* Für immer... */
   while(1)
   {
      unsigned char zeichen = '#';
      unsigned char RXError = 0;

      /* Zeichen am Empfang (RX) abholen */
      /* Warten bis Empfangspuffer voll */
      while (!ri_u0c1)
         ;
      /* Empfangspuffer auslesen */
      zeichen = u0rbl;
      RXError = u0rbh;   /* löscht gleichzeitig ri_u0c1 ! */
      
      /* hier ggf. Fehlerbehandlung */

      /* Etwas mit dem Zeichen machen ;-) */
      if (zeichen >= 'a' && zeichen <= 'z')
         zeichen = zeichen - 'a' + 'A';
      else if (zeichen >= 'A' && zeichen <= 'Z')
         zeichen = zeichen - 'A' + 'a';

      /* LED Anzeige ;-) */
      pd1 |= 0b00000001;   
      if (zeichen == '0')
         p1_0 = 0;
      if (zeichen == '1')
         p1_0 = 1;
      
      /* Zeichen beim Sender (TX) abgeben */
      /* Warten bis Sendepuffer frei */
      while (!txept_u0c0 || !ti_u0c1)
         ;
      /* Sendepuffer beschreiben */
      u0tbl = zeichen;

   } /* end while(1) */
}

void uart0_willkommen(unsigned char *stext)
{
   while(*stext)
   {
      /* Zeichen beim Sender (TX) abgeben */
      /* Warten bis Sendepuffer frei */
      while (!txept_u0c0 || !ti_u0c1)
         ;
      /* Sendepuffer beschreiben */
      u0tbl = *stext++;
   }
}

Vorschläge fürs weitere Experimentieren?

  • Wie kann man die Sende- und Empfangsanweisungen in sinnvolle Funktionen packen?
  • Wie könnte man grössere Texte empfangen oder senden, ohne dass Zeichen verloren gehen?
  • Wie kann man UART 1 statt UART 0 verwenden, damit man über ein und dieselbe PC-Verbindung Programme flashen und nach Programmstart kommunizieren kann ?

Studieren geht über Probieren!

  • Welche anderen Verfahren gibt es statt Polling und welche Vorteile haben diese Verfahren?

Siehe auch