Tipps und Tricks
Diese Seite ist lediglich eine Sammlung von Befehlen, Codeschnipseln sowie Bauteilen bzw. Schaltungen, die ich häufiger verwende. Eine weitaus umfangreiche Sammlung gibt es zum Beispiel auf mikrocontroller.net.
Hardware
AVR Controllertypen
Typ | Flash | EEPROM | SRAM | Anzahl I/O | maximale Taktfrequenz |
---|---|---|---|---|---|
AT90S2323 | 2 kB | 128 B | 128 B | 3 | 10 MHz |
AT90S2343 | 2 kB | 128 B | 128 B | 5 | 10 MHz |
ATtiny26 | 2 kB | 128 B | 128 B | 15 | 16 MHz |
ATmega8 | 8 kB | 512 B | 1 kB | 22 | 16 MHz |
ATmega16 | 16 kB | 512 B | 1 kB | 32 | 16 MHz |
1-Wire Temperatursensoren
Typ | Temperaturbereich | Genauigkeit | Auflösung |
---|---|---|---|
DS1820 | -55°C bis +125°C | ±0.5°C | 9 Bit |
DS18S20 | -55°C bis +125°C | ±0.5°C | 9 Bit |
DS18B20 | -55°C bis +125°C | ±0.5°C | 9/12 Bit |
DS1822 | -55°C bis +125°C | ±2.0°C | 9/12 Bit |
APPLICATION NOTE 4377 - Comparison of the DS18B20 and DS18S20 1-Wire Digital Thermometers
Standard-Transistoren
Typ | Umax | Imax | NPN/PNP |
---|---|---|---|
BC 548 | 30 V | 100 mA | NPN |
BC 337-25 | 45 V | 800 mA | NPN |
BC 327-25 | 45 V | 800 mA | PNP |
Standard-MOSFETs (N-Channel)
Typ | Umax | Imax | Rds(on) | Vgs(max) | Vgs(th) |
---|---|---|---|---|---|
BUZ11 | 50 V | 30 A | 40 mΩ | ±20 V | ∼3 V |
IRF540N | 100 V | 33 A | 44 mΩ | ±20 V | ∼3 V |
Transistor als Schalter
Software
IO-Ports konfigurieren
DDRx = Datenrichtungsregister für Portx.
PORTx = Datenregister für Portx.
DDRx=0 | DDRx=1 | |
---|---|---|
PORTx=0 | Eingang | Ausgang Low |
PORTx=1 | Eingang (Pull-Up) | Ausgang High |
// PB7,PB6,PB5,PB4=Ausgang(Low), PB3,PB2,PB1,PB0=Eingang(Pull-Up) DDRB = 0xF0; // 1111 0000 PORTB= 0x0F; // 0000 1111
Digitale Eingänge
Prüfen ob Pin7 an PortB auf HIGH gesetzt ist:
if ( PINB & (1<<PB7) ) { // do something }
Prüfen ob Pin7 an PortB auf LOW gesetzt ist:
if ( !(PINB & (1<<PB7)) ) { // do something }
Warten bis Pin7 an PortB auf HIGH gesetzt wurde:
while ( !(PINB & (1<<PB7)) ); // busy waiting
Warten bis Pin7 an PortB auf LOW gesetzt wurde:
while ( PINB & (1<<PB7) ); // busy waiting
Digitale Ausgänge
Pin4 und Pin5 an PortB auf HIGH setzen:
PORTB |= (1<<PB4) | (1<<PB5);
Pin4 und Pin5 an PortB auf LOW setzen:
PORTB &= ~((1<<PB4) | (1<<PB5));
Pin4 an PortB invertieren:
PORTB ^= (1<<PB4);
Timer Interrupt
In diesem Beispiel wird der Timer0 des Mikrocontrollers dazu benutzt, um jede Millisekunde einen Interrupt auszulösen. Beim Timer0 handelt es sich um einen 8-bit Timer, der immer genau dann einen Interrupt auslöst, wenn das 8-bit Zählregister (TCNT0) überläuft. Würde man das Zählregister des Timers synchron zum Prozessortakt (in diesem Fall 8 MHz) hochzählen, dann würde alle 32 µS ein Interrupt ausgelöst werden. Um diese Rate zu verringern gibt es den sogenannten "Prescaler", mit dem man den Prozessortakt um einen bestimmten Faktor teilen kann. Stellt man den Prescaler beispielsweise auf 8, so wird Zählregister des Timers nur bei jedem achten Impuls vom Prozessortakt um 1 erhöht.
Mögliche Werte für den Prescaler von Timer0:
CS02 | CS01 | CS00 | |
---|---|---|---|
0 | 0 | 0 | STOP (Timer stopped) |
0 | 0 | 1 | CLK/0 (No prescaling) |
0 | 1 | 0 | CLK/8 (From prescaler) |
0 | 1 | 1 | CLK/64 (From prescaler) |
1 | 0 | 0 | CLK/256 (From prescaler) |
1 | 0 | 1 | CLK/1024 (From prescaler) |
Taktfrequenz | CLK / 0 | CLK / 8 | CLK / 64 | CLK / 256 | CLK / 1024 |
---|---|---|---|---|---|
1 MHz | 1000000.00 | 125000.00 | 15625.00 | 3906.25 | 976.56 |
Overflows/Sek | 3906.25 | 488.28 | 61.04 | 15.26 | 3.81 |
2 MHz | 2000000.00 | 250000.00 | 31250.00 | 7812.50 | 1953.13 |
Overflows/Sek | 7812.50 | 976.56 | 122.07 | 30.52 | 7.63 |
4 MHz | 4000000.00 | 500000.00 | 62500.00 | 15625.00 | 3906.25 |
Overflows/Sek | 15625.00 | 1953.13 | 244.14 | 61.04 | 15.26 |
8 MHz | 8000000.00 | 1000000.00 | 125000.00 | 31250.00 | 7812.50 |
Overflows/Sek | 31250.00 | 3906.25 | 488.28 | 122.07 | 30.52 |
10 MHz | 10000000.00 | 1250000.00 | 156250.00 | 39062.50 | 9765.63 |
Overflows/Sek | 39062.50 | 4882.81 | 610.35 | 152.59 | 38.15 |
16 MHz | 16000000.00 | 2000000.00 | 250000.00 | 62500.00 | 15625.00 |
Overflows/Sek | 62500.00 | 7812.50 | 976.56 | 244.14 | 61.04 |
Für den Timer Interrupt muss also zunächst ein passender Prescaler festgelegt werden. In diesem Beispiel soll jede Millisekunde ein Interrupt ausgelöst werden, was einer Frequenz von 1000 Hz entspricht. Die Anzahl der notwendigen Inkrementierungen, um einen Timer Overflow Interrupt auszulösen muss kleiner oder gleich dem höchsten Wert des Zählregister sein.
Bei einem Prozessortakt von 8 MHz ergeben sich folgende Werte für die Anzahl der notwendigen Inkrementierungen:
Prescaler | Timer-Takt | Timer-Takt / 1000 Hz (1 ms) | Bemerkung |
---|---|---|---|
CLK/0 | 8.000.000,0 Hz | 8.000 | nicht geeignet, da > 256 |
CLK/8 | 1.000.000,0 Hz | 1.000 | nicht geeignet, da > 256 |
CLK/64 | 125.000,0 Hz | 125 | geeigneter Wert für den Prescaler |
CLK/256 | 31.250,0 Hz | 31,25 | nicht geeignet, da nicht ganzzahlig |
CLK/1024 | 7.812,5 Hz | 7,8125 | nicht geeignet, da nicht ganzzahlig |
Anhand der Tabelle ist ersichtlich, dass in dem Fall nur ein Prescaler von 64 geeignet ist. Damit der Timer Overflow Interrupt nach genau einer Millisekunde ausgelöst wird, muss das Zählregister in diesem Fall noch mit dem Wert 131 (256-125) vorgeladen werden.
#include <avr/interrupt.h> volatile uint32_t millis = 0; ISR (TIMER0_OVF0_vect) { millis++; TCNT0 = 131; } int main (void) { TIMSK |= (1<<TOIE0); // enable Timer 0 Overflow Interrupt TCCR0 |= (1<<CS01) | (1<<CS00); // set prescaler to 64 TCNT0 = 131; // set preload value sei(); // enable interrupts while(1) { // do something } return 0; }
Weiterführende Links zum Thema Timer:
heise Developer: Timer, Counter und Interrupts
Prescaler - Berechnung für AVR - Timer
PWM (Pulse Width Modulation)
In diesem Beispiel wird der Timer1 des Mikrocontrollers dazu benutzt, um ein PWM-Signal mit variablem Tastverhältnis zu erzeugen. Die resultierende PWM-Frequenz ist abhängig vom Prozessortakt, dem Prescaler und der Auflösung der PWM. Der Prescaler für den Timer sollte dabei so hoch wie möglich gewählt werden, um die Prozessorlast durch die Interrupt-Routine (Timer Overflow) so gering wie möglich zu halten.
Die Formel zur Berechnung der PWM-Frequenz lautet:
PWM-Frequenz = Prozessortakt / Prescaler / Schritte bis Timer-Overflow / PWM-Schritte
Prozessortakt | Prescaler | Auflösung/Schritte | PWM-Frequenz |
---|---|---|---|
8.000.000 Hz | 1 | 0-255 (8-bit) | 122.07 Hz |
8.000.000 Hz | 1 | 0-127 (7-bit) | 244.14 Hz |
8.000.000 Hz | 1 | 0-63 (6-bit) | 488.28 Hz |
8.000.000 Hz | 1 | 0-31 (5-bit) | 976.56 Hz |
8.000.000 Hz | 2 | 0-255 (8-bit) | 61.03 Hz |
8.000.000 Hz | 2 | 0-127 (7-bit) | 122.07 Hz |
8.000.000 Hz | 2 | 0-63 (6-bit) | 244.14 Hz |
8.000.000 Hz | 2 | 0-31 (5-bit) | 488.28 Hz |
8.000.000 Hz | 4 | 0-255 (8-bit) | 30.51 Hz |
8.000.000 Hz | 4 | 0-127 (7-bit) | 61.03 Hz |
8.000.000 Hz | 4 | 0-63 (6-bit) | 122.07 Hz |
8.000.000 Hz | 4 | 0-31 (5-bit) | 244.14 Hz |
#include <avr/interrupt.h> #define PWM_MAX 100 volatile uint8_t pwmCounter = 0; uint8_t pwmValue = 0; ISR (TIMER1_OVF1_vect) { if (++pwmCounter > PWM_MAX) { pwmCounter = 0; } if ( (pwmCounter == 0) && (pwmValue > 0) ) { // set output high } else if ( (pwmCounter == pwmValue) && (pwmValue < PWM_MAX) ) { // set output low } } int main (void) { TIMSK |= (1<<TOIE1); // enable Timer 1 Overflow Interrupt TCCR1B |= (1<<CS10); // set prescaler to 1 sei(); // enable interrupts while(1) { // do something (e.g. set pwmValue) } return 0; }