Forum: Mikrocontroller und Digitale Elektronik C++ E/A für den ATmega8


von Rüdiger Knörig (Gast)


Lesenswert?

Im Rahmen eines kleinen Projekts habe ich für den ATmega8 eine Klasse 
für die serielle Ein/Ausgabe geschrieben, welche ohne großen 
Ressourcenaufwand typischen C++-Komfort anbietet:
1
#include "USARTMega8.h"
2
3
using namespace std;
4
5
int main()
6
{
7
  DDRB=0x3;
8
  PORTB=0x0;
9
  USARTMega8<9600> usart;
10
  int zahl;
11
  while(true)
12
  {
13
    usart << "Zahl eingeben: ";
14
    usart >> zahl;
15
    if(usart.warErfolgreich())
16
    {
17
      usart << endl << "Eingegebene Zahl: " << zahl << endl;
18
    }
19
    else
20
    {
21
      usart << endl << "Fehler!" << endl;
22
    }
23
    PORTB ^= 0x2;
24
  }
25
}

Die USARTMega8-Klasse baut auf dem hier im C-Tutorium gezeigten 
Quelltext auf:
1
/**
2
 * @file USARTMega8.h
3
 * @brief Deklaration der USARTMega8-Klasse.
4
 * @author Dr. Rüdiger Knörig (ruediger@knoerig.de)
5
 * @date 11.07.2013
6
 */
7
8
#ifndef USARTMEGA_H_
9
#define USARTMEGA_H_
10
11
#include <avr/io.h>
12
13
using namespace std;
14
15
const char *endl="\n\r";
16
17
/**
18
 * @brief Serielle Schnittstellenklasse für den ATMega8.
19
 * @author Dr. Rüdiger Knörig (ruediger@knoerig.de)
20
 * @date 11.07.2013
21
 * @tparam BaudRate Desired baud rate.
22
 */
23
template<unsigned long int BaudRate> class USARTMega8
24
{
25
public:
26
27
  /**
28
   * @brief Konstruktor.
29
   */
30
  USARTMega8() : erfolg(true)
31
  {
32
    uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16*BaudRate) - 1);
33
    //uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16*9600ul) - 1);
34
35
    UBRRH = (uint8_t) (ubrr>>8);
36
    UBRRL = (uint8_t) (ubrr);
37
38
    // UART Receiver und Transmitter anschalten
39
    // Data mode 8N1, asynchron
40
    UCSRB = (1 << RXEN) | (1 << TXEN);
41
    UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);
42
43
    // Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte)
44
    do
45
    {
46
      UDR;
47
    }
48
    while (UCSRA & (1 << RXC));
49
  }
50
51
  /**
52
   * @brief Destruktor.
53
   */
54
  ~USARTMega8() {}
55
56
  /**
57
   * @brief Druckt ein einzelnes Zeichen.
58
   * @param[in] zeichen Zeichen zum Drucken.
59
   */
60
  void druckeZeichen(const char zeichen)
61
  {
62
      // Warten, bis UDR bereit ist für einen neuen Wert
63
      while (!(UCSRA & (1 << UDRE)));
64
      // UDR Schreiben startet die Übertragung
65
      UDR = zeichen;
66
  }
67
68
  /**
69
   * @brief Druckt eine ganze Zeichenkette.
70
   * @param[in] zeichenKette Zeichenkette zum Drucken.
71
   */
72
  void druckeZeichenkette(const char *zeichenKette)
73
  {
74
    while(*zeichenKette) druckeZeichen(*zeichenKette++);
75
  }
76
77
  /**
78
   * @brief Liest ein einzelnes Zeichen von der seriellen Schnittstelle.
79
   * Diese Methode wartet blockierend auf einen Empfang.
80
   */
81
  uint8_t leseZeichenBlockierend()
82
  {
83
      // Warten, bis etwas empfangen wird
84
      while (!(UCSRA & (1 << RXC)));
85
86
      // Das empfangene Zeichen zurückliefern
87
      return UDR;
88
  }
89
90
  /**
91
   * @brief Liest ein einzelnes Zeichen von der seriellen Schnittstelle.
92
   * Diese Methode wartet nicht auf einen Empfang.
93
   * @param[out] zeichen Referenz auf die aufnehmende Zeichenvariable.
94
   * @return Wahr, wenn ein Zeichen gelesen wurde.
95
   */
96
  bool leseZeichenNichtBlockierend(uint8_t &zeichen)
97
  {
98
    if((UCSRA & (1 << RXC)))
99
    {
100
      zeichen=UDR;
101
      return true;
102
    }
103
    else
104
    {
105
      return false;
106
    }
107
  }
108
109
  /**
110
   * @brief Liest eine Zeichenkette von der seriellen Schnittstelle ein.
111
   * @param[out] puffer Aufnahmepuffer.
112
   * @param[in] pufferLaenge Größe des Aufnahmepuffers.
113
   */
114
  void leseZeichenkette(char *puffer,unsigned int pufferLaenge)
115
  {
116
    char *ende=puffer + pufferLaenge - 1;
117
    while(puffer < ende)
118
    {
119
      char zeichen=leseZeichenBlockierend();
120
      if((zeichen==' ') || (zeichen == '\t') || (zeichen == '\n')) break;
121
      *(puffer++)=zeichen;
122
    }
123
    *puffer=0;
124
  }
125
126
  /**
127
   * @brief Vergleicht zwei Zeichenketten.
128
   * @param[in] zk1 Erste Zeichenkette.
129
   * @param[in] zk2 Zweite Zeichenkette.
130
   * @param[in] maxLaenge Maximale Länge der Zeichenketten.
131
   * @return 0 wenn beide Zeichenketten identisch sind, -1 wenn zk1 < zk2 und 1 wenn zk1 > zk2.
132
   */
133
  int vergleicheZeichenketten(const char *zk1,const char *zk2,unsigned int maxLaenge)
134
  {
135
    for(unsigned int k=0;k<maxLaenge;k++)
136
    {
137
      char z1=zk1[k];
138
      char z2=zk2[k];
139
      if((z1==0) || (z2 == 0))
140
      {
141
        if((z1==0) && (z2 != 0)) return -1;
142
        if((z2==0) && (z1 != 0)) return 1;
143
        return 0;
144
      }
145
      else
146
      {
147
        if(z1 < z2) return -1;
148
        if(z1 > z2) return 1;
149
      }
150
    }
151
    return 0;
152
  }
153
154
  /**
155
   * @brief Liest eine Ganzzahl ein.
156
   * @param[out] zahl Referenz auf die aufnehmende Ganzzahlvariable.
157
   * @return Wahr, wenn eine Zahl ohne Probleme eingelesen werden konnte.
158
   */
159
  bool leseZahl(int &zahl)
160
  {
161
    bool ziffernGelesen=false;
162
    bool hatVorzeichen=false;
163
    bool erfolg=false;
164
    bool negativ=false;
165
    zahl=0;
166
    do{
167
      uint8_t zeichen=leseZeichenBlockierend();
168
      if((zeichen == ' ') || (zeichen == '\t') || (zeichen == '\n') || (zeichen == '\r'))
169
      {
170
        erfolg=ziffernGelesen;
171
        if((ziffernGelesen==false) && ((zeichen == ' ') || (zeichen == '\t'))) continue;
172
        else break;
173
      }
174
      else if((zeichen == '+') || (zeichen == '-'))
175
      {
176
        if(hatVorzeichen) return false;
177
        if(zeichen == '-') negativ=true;
178
        hatVorzeichen=true;
179
        druckeZeichen(zeichen);
180
      }
181
      else if((zeichen >= '0') && (zeichen <= '9'))
182
      {
183
        zahl = zahl*10+(zeichen-'0');
184
        ziffernGelesen=true;
185
        druckeZeichen(zeichen);
186
      }
187
      else
188
      {
189
        druckeZeichenkette("Falsch!\n\r");
190
        return false;
191
      }
192
    }while(true);
193
    if(negativ) zahl=(~zahl+1);
194
    return erfolg;
195
  }
196
197
  /**
198
   * @brief Druckt die gegebene Zahl auf der seriellen Konsole aus.
199
   * @param[in] zahl Auszudruckende Zahl.
200
   */
201
  void schreibeZahl(int32_t zahl)
202
  {
203
    char puffer[10];
204
    char *ptr=puffer+10;
205
    char *endPtr=ptr;
206
207
    if(zahl < 0)
208
    {
209
      druckeZeichen('-');
210
      zahl = (~zahl) + 1; // 2er-Komplementär invertieren
211
    }
212
    do
213
    {
214
      char ziffer='0'+(zahl % 10);
215
      *(--ptr)=ziffer;
216
      zahl /= 10;
217
    }while(zahl > 0);
218
    for(;ptr < endPtr;ptr++) druckeZeichen(*ptr);
219
  }
220
221
  /**
222
   * @brief Inspektor für den Erfolg der letzten Strom-Eingabe.
223
   * @return Wahr, wenn die letzte Stromeingabe erfolgreich war.
224
   */
225
  bool warErfolgreich() { return erfolg; }
226
227
  /**
228
   * @brief Strom-Ausgabeoperator für Zeichenketten.
229
   * @param[in] zeichenkette Auszugebende Zeichenkette.
230
   * @return Referenz auf das USART-Objekt zwecks Verkettung.
231
   */
232
  USARTMega8 &operator<<(const char *zeichenkette)
233
  {
234
    druckeZeichenkette(zeichenkette);
235
    return *this;
236
  }
237
238
  /**
239
   * @brief Strom-Ausgabeoperator für Zahlen.
240
   * @param[in] zahl Auszugebende Zahl
241
   * @return Referenz auf das USART-Objekt zwecks Verkettung.
242
   */
243
  USARTMega8 &operator<<(int zahl)
244
  {
245
    schreibeZahl(zahl);
246
    return *this;
247
  }
248
249
  /**
250
   * @brief Strom-Eingabeoperator für Zahlen.
251
   * @param[out] Zahl Referenz auf die einzulesende Zahl.
252
   * @return Referenz auf das USART-Objekt zwecks Verkettung.
253
   */
254
  USARTMega8 &operator>>(int &zahl)
255
  {
256
    erfolg=leseZahl(zahl);
257
    return *this;
258
  }
259
260
protected:
261
  bool erfolg; /**< Indiziert einen Erfolg/Mißerfolg bei der letzten Strom-Eingabe. */
262
};
263
264
#endif

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.