Programmierung von Avr-Mikrocontrollern in C. Programmierung von AVR-Mikrocontrollern in C. Was ist also ein Mikrocontroller?

Ich habe beschlossen, einen kurzen Einführungsartikel für diejenigen zu schreiben, die zum ersten Mal mit der Programmierung von Mikrocontrollern beginnen und noch nie mit der Sprache C vertraut waren. Wir werden nicht auf Details eingehen, sondern ein wenig über alles sprechen, um einen allgemeinen Überblick über die Arbeit mit CodeVisionAVR zu bekommen.

Mehr genaue Information kann auf Englisch im CodeVision-Benutzerhandbuch eingesehen werden, außerdem empfehle ich die Seite http://somecode.ru mit Video-Lektionen zu C für Mikrocontroller und das Buch „How to Program in C“ von Deitel, das ist das einzig gute Buch mit dem ich selbst angefangen habe.

Beginnen wir mit der Tatsache, dass es, egal welche Aktionen wir unternehmen, letztendlich auf die Firmware des Mikrocontrollers ankommt. Der Firmware-Prozess selbst läuft wie folgt ab: Mit einem bestimmten Programm wird eine Firmware-Datei ausgewählt, Parameter werden ausgewählt, eine Taste wird gedrückt und die Firmware wird direkt geflasht, was im Wesentlichen eine Kopie ist. Genau wie beim Kopieren von Musik oder Dokumenten von einem Computer auf ein Flash-Laufwerk ist die Physik des Vorgangs dieselbe.

Die Firmware selbst hat die Erweiterung .hex und besteht aus einer Reihe von Anweisungen in Form von Einsen und Nullen, die für den Mikrocontroller verständlich sind. Woher bekomme ich die Firmware? Sie können es von Elektronik-Websites herunterladen oder selbst schreiben. Sie können es in speziellen Programmen schreiben, die als Entwicklungsumgebung bezeichnet werden. Am bekanntesten sind mir AVR Studio, IAR, CodeVision, WinAVR ... Es ist unmöglich zu sagen, welche dieser Umgebungen besser oder schlechter ist, für jede für sich. Wir können sagen, dass sich diese Programme hauptsächlich im Komfort, in der Programmiersprache und im Preis unterscheiden. Auf dieser Website wird nur CodeVision berücksichtigt.

Wir haben die Umgebung geklärt. Schauen wir uns nun den Prozess des Firmware-Schreibens an. In CodeVision müssen Sie zunächst ein Projekt erstellen. Es kann mit dem Code-Assistenten erstellt oder leer sein. In jedem Fall müssen Sie den Typ des verwendeten Mikrocontrollers auswählen und dessen Frequenz angeben. Wenn Sie den Assistenten verwenden, werden Sie aufgefordert, Anfangseinstellungen auszuwählen und Quellcode mit den Einstellungen zu generieren. Als nächstes erscheint ein Fenster, in dem Sie diesen Code bearbeiten können. Sie können Ihren Quellcode zwar im Notepad schreiben und ihn dann in den Einstellungen an das Projekt anhängen.

Eine Quellcodedatei ist eine Reihe von Befehlen in einer Programmiersprache. Die Aufgabe von CodeVision besteht darin, diese Befehle in Binärcode zu übersetzen. Ihre Aufgabe besteht darin, diesen Quellcode zu schreiben. CodeVision versteht die Sprache C, Quellcodedateien haben die Erweiterung „.c“. Aber CodeVision verfügt über einige Konstrukte, die in C nicht verwendet werden, weshalb es vielen Programmierern nicht gefällt und die verwendete Sprache als C-like bezeichnet wird. Dies hindert Sie jedoch nicht daran, ernsthafte Projekte zu schreiben. Viele Beispiele, ein Codegenerator und eine große Auswahl an Bibliotheken verschaffen CodeVision einen großen Vorteil. Das einzig Negative ist, dass es bezahlt wird, obwohl es eine gibt kostenlose Versionen mit Code-Einschränkung.

Der Quellcode muss einen Header mit dem Typ des verwendeten Mikrocontrollers und der Hauptfunktion enthalten. Beispielsweise wird ATtiny13 verwendet

#enthalten void main(void) ( );

#enthalten void main(void) ( );

Vor der Hauptfunktion können Sie die erforderlichen Bibliotheken verbinden, globale Variablen, Konstanten und Einstellungen deklarieren. Eine Bibliothek ist eine separate Datei, normalerweise mit der Erweiterung „.h“, die bereits vorab geschriebenen Code enthält. In einigen Projekten benötigen wir diesen Code möglicherweise, in anderen jedoch nicht. Beispielsweise verwenden wir in einem Projekt LCD-Displays, in einem anderen jedoch nicht. Sie können die Bibliothek für die Arbeit mit dem LCD-Display „alcd.h“ wie folgt anschließen:

#enthalten #enthalten void main(void) ( );

#enthalten #enthalten void main(void) ( );

Variablen sind Speicherbereiche, in denen bestimmte Werte abgelegt werden können. Wenn Sie beispielsweise zwei Zahlen addieren, müssen Sie das Ergebnis irgendwo speichern, um es in Zukunft verwenden zu können. Zuerst müssen Sie die Variable deklarieren, d.h. Weisen Sie ihm Speicher zu, zum Beispiel:
int i=0;
diese. Wir haben die Variable i deklariert und den Wert 0 darin platziert. Int ist der Typ der Variablen, oder einfacher gesagt, es bedeutet die Größe des zugewiesenen Speichers. Jeder Variablentyp kann nur einen bestimmten Wertebereich speichern. Int kann beispielsweise als Zahlen von -32768 bis 32767 geschrieben werden. Wenn Sie Zahlen mit einem Bruchteil verwenden müssen, muss die Variable als Float deklariert werden; für Zeichen verwenden Sie den Typ char.

Bit, _Bit 0 oder 1 Zeichen von -128 bis 127 Zeichen ohne Vorzeichen von 0 bis 255 Ganzzahl von -32768 bis 32767 Ganzzahl ohne Vorzeichen von 0 bis 65535 Ganzzahl ohne Vorzeichen von -2147483648 bis 2147483647 Ganzzahl ohne Vorzeichen von 0 bis 4294967295 Gleitkommazahl von ±1. 17 5e - 38 bis ±3,402e38

Innerhalb der Hauptfunktion läuft das Hauptprogramm bereits. Nach der Ausführung der Funktion stoppt das Programm, sodass eine Endlosschleife erstellt wird, die das gleiche Programm ständig wiederholt.

void main(void) ( while (1) ( ); );

void main(void) ( while (1) ( ); );

Sie können in jeden Teil des Quellcodes einen Kommentar schreiben. Dies hat keinen Einfluss auf die Funktionsweise des Programms, hilft aber dabei, Notizen zum geschriebenen Code zu machen. Sie können eine Zeile mit zwei Schrägstrichen auskommentieren //danach ignoriert der Compiler die gesamte Zeile oder mehrere Zeilen /**/, zum Beispiel:

/*Grundlegende mathematische Operationen:*/ int i= 0 ; //deklariere die Variable i und weise ihr den Wert 0 zu//Addition: i = 2 + 2 ; //Subtraktion: i = 2 - 2 ; //Nach der Ausführung dieses Ausdrucks ist die Variable i gleich 0//Multiplikation: i = 2 * 2 ; //Nach der Ausführung dieses Ausdrucks ist die Variable i gleich 4//Division: i = 2 / 2 ; //Nach der Ausführung dieses Ausdrucks ist die Variable i gleich 1

/*Grundlegende mathematische Operationen:*/ int i=0; //Variable i deklarieren und ihr den Wert 0 zuweisen //Zusatz: i = 2+2; //Nach der Ausführung dieses Ausdrucks ist die Variable i gleich 4 //Subtraktion: i = 2-2; //Nach der Ausführung dieses Ausdrucks ist die Variable i gleich 0 //Multiplikation: i = 2*2; //nach der Ausführung dieses Ausdrucks ist die Variable i gleich 4 //Division: i = 2/2; //Nach der Ausführung dieses Ausdrucks ist die Variable i gleich 1

Oftmals muss ein Programm je nach Bedingungen von einem Codeteil zum anderen wechseln; hierfür gibt es bedingte if()-Operationen, zum Beispiel:

if(i>3) //wenn i größer als 3 ist, dann weise i den Wert 0 zu ( i=0; ) /*wenn i kleiner als 3 ist, dann gehe zum Code, der dem Hauptteil der Bedingung folgt, d. h. nach Klammern ()*/

Auch if kann in Verbindung mit else verwendet werden – andernfalls

wenn ich<3) //если i меньше 3, то присвоить i значение 0 { i=0; } else { i=5; //иначе, т.е. если i больше 3, присвоить значение 5 }

Es gibt auch einen Vergleichsoperator „==“, der nicht mit „=“ verwechselt werden sollte. Nehmen wir an, die umgekehrte Operation ist nicht gleich „!="

if(i==3)//wenn i 3 ist, weise i den Wert 0 zu ( i=0; ) if(i!=5) //wenn i nicht 5 ist, weise i den Wert 0 zu ( i=0; ) )

Kommen wir zu komplexeren Dingen – Funktionen. Nehmen wir an, Sie haben einen bestimmten Code, der mehrmals wiederholt wird. Darüber hinaus ist dieser Code ziemlich groß. Es ist unbequem, es jedes Mal zu schreiben. Wenn Sie beispielsweise in einem Programm, das die Variable i irgendwie ändert, die Tasten 0 und 3 von Port D drücken, wird derselbe Code ausgeführt, der abhängig vom Wert der Variablen i die Zweige von Port B einschaltet.

void main(void) ( if (PIND.0== 0 ) //Überprüfen Sie, ob die Taste auf PD0 gedrückt ist( wenn (i== 0 ) //wenn i==0 PB0 aktivieren( PORTB.0= 1 ; ) if (i== 5 ) // wenn i==5 PB1 aktivieren( PORTB.1= 1 ; ) ) … if (PIND.3== 0 ) // Machen Sie dasselbe, wenn Sie die PD3-Schaltfläche überprüfen( if (i== 0 ) ( PORTB.0= 1 ; ) if (i== 5 ) ( PORTB.1= 1 ; ) ) )

void main(void) ( if(PIND.0==0) //überprüfen, ob die Taste auf PD0 gedrückt ist ( if(i==0) //if i==0 PB0 einschalten ( PORTB.0=1; ) if( i==5) // if i==5 PB1 einschalten ( PORTB.1=1; ) ) ... if(PIND.3==0) // das Gleiche tun, wenn die PD3-Taste überprüft wird ( if(i==0 ) ( PORTB.0=1; ) if(i==5) ( PORTB.1=1; ) ) )

Im Allgemeinen ist der Code nicht sehr groß, könnte aber um ein Vielfaches größer sein, sodass es viel bequemer wäre, eine eigene Funktion zu erstellen.
Zum Beispiel:

void i_check() ( if (i== 0 ) ( PORTB.0= 1 ; ) if (i== 5 ) ( PORTB.1= 1 ; ) )

void i_check() ( if(i==0) ( PORTB.0=1; ) if(i==5) ( PORTB.1=1; ) )

void bedeutet, dass die Funktion nichts zurückgibt, mehr dazu weiter unten i_check() – das ist der Name unserer Funktion, Sie können sie nennen, wie Sie wollen, ich habe sie genau so genannt – check i. Jetzt können wir unseren Code umschreiben:

void i_check() ( if(i==0) ( PORTB.0=1; ) if(i==5) ( PORTB.1=1; ) ) void main(void) ( if(PIND.0==0 ) //überprüfen, ob die Taste auf PD0 gedrückt ist ( i_check(); ) ... if(PIND.3==0) ( i_check(); ) )

Wenn der Code die Zeile erreicht, i_check(); Dann springt es in die Funktion und führt den darin enthaltenen Code aus. Stimmen Sie zu, der Code ist kompakter und klarer, d.h. Funktionen helfen dabei, denselben Code, nur eine Zeile, zu ersetzen. Bitte beachten Sie, dass die Funktion außerhalb des Hauptcodes deklariert wird, d. h. vor der Hauptfunktion. Sie können sagen, warum brauche ich das, aber beim Studium der Lektionen werden Sie oft auf Funktionen stoßen, zum Beispiel das Löschen des LCD-Bildschirms lcd_clear() – die Funktion akzeptiert keine Parameter und gibt nichts zurück, aber sie löscht das Bildschirm. Manchmal wird diese Funktion fast in jeder zweiten Zeile verwendet, sodass die Codeeinsparungen offensichtlich sind.

Es sieht viel interessanter aus, eine Funktion zu verwenden, wenn sie Werte annimmt. Beispielsweise gibt es eine Variable c und eine Summenfunktion, die zwei Werte vom Typ int annimmt. Wenn das Hauptprogramm diese Funktion ausführt, stehen die Argumente bereits in Klammern, sodass „a“ gleich zwei und „b“ gleich 1 wird. Die Funktion wird ausgeführt und „c“ wird gleich 3 .

int c= 0 ; void sum(int a, int b) ( c= a+ b; ) void main(void ) ( sum(2 , 1 ) ; )

int c=0; void sum(int a, int b) ( c=a+b; ) void main(void) ( sum(2,1); )

Eine der gebräuchlichsten ähnlichen Funktionen besteht darin, den Cursor auf dem LCD-Display zu bewegen. lcd_gotoxy(0,0); was übrigens auch Argumente akzeptiert – x- und y-Koordinaten.

Eine weitere Option zur Verwendung einer Funktion: Wenn sie einen Wert zurückgibt, ist dieser jetzt nicht mehr ungültig. Lassen Sie uns das vorherige Beispiel einer Funktion zum Addieren zweier Zahlen verbessern:

int c= 0 ; int sum(int a, int b) ( return a+ b; ) void main(void) ( с= sum(2, 1) ; )

int c=0; int sum(int a, int b) ( return a+b; ) void main(void) ( с=sum(2,1); )

Das Ergebnis ist dasselbe wie beim letzten Mal c=3, aber beachten Sie, dass wir der Variablen „c“ den Wert einer Funktion zuweisen, die nicht mehr ungültig ist, sondern die Summe zweier Zahlen vom Typ int zurückgibt. Auf diese Weise sind wir nicht an eine bestimmte Variable „c“ gebunden, was die Flexibilität bei der Verwendung von Funktionen erhöht. Ein einfaches Beispiel für eine solche Funktion ist das Lesen von ADC-Daten. Die Funktion gibt den Messwert result=read_adc(); zurück. Lassen Sie uns mit den Funktionen abschließen.

Kommen wir nun zu den Arrays. Ein Array besteht aus verwandten Variablen. Wenn Sie beispielsweise eine Sinustabelle mit mehreren Punkten haben, erstellen Sie keine Variablen int sinus1=0; int sinus2=1; usw. Hierzu wird ein Array verwendet. Sie können beispielsweise ein Array aus drei Elementen wie folgt erstellen:
int sinus=(0,1,5);
Die Gesamtzahl der Array-Elemente wird in eckigen Klammern angegeben. Den Wert des dritten Elements können Sie der Variablen „c“ wie folgt zuweisen:
с=Sinus;
Bitte beachten Sie, dass die Nummerierung der Array-Elemente bei Null beginnt, d. h. „c“ wird gleich fünf. Dieses Array hat kein Sinuselement!!!
So können Sie einem einzelnen Element einen Wert zuweisen:
Sinus=10;

Möglicherweise ist Ihnen bereits aufgefallen, dass CodeVision keine String-Variablen hat. Diese. Sie können keine Variable string hello=“hello“ erstellen; Dazu müssen Sie ein Array aus einzelnen Zeichen erstellen.

lcd_putchar(hallo); lcd_putchar(hallo); lcd_putchar(hallo);

usw.
Es stellt sich als ziemlich umständlich heraus, hier kommen Fahrräder zum Einsatz.
Zum Beispiel while-Schleife

while(PINB.0!=0) ( )

Tun Sie nichts, bis die Taste gedrückt wird – führen Sie eine leere Schleife aus.

Eine weitere Option ist die for-Schleife

int i; für (i= 0 ; ich< 6 ; i++ ) { lcd_putchar(hello[ i] ) ; }

int i; for(i=0;i<6;i++) { lcd_putchar(hello[i]); }

Die Bedeutung ist genau die gleiche wie die von while, nur die Anfangsbedingung i=0 und die Bedingung, die in jedem Zyklus i++ ausgeführt wird, werden hinzugefügt. Der Code innerhalb der Schleife ist so vereinfacht wie möglich.

Nachdem Sie Ihr Programm geschrieben haben, wird der Quellcode kompiliert und wenn keine Fehler vorliegen, erhalten Sie die begehrte Firmware im Projektordner. Jetzt können Sie den Mikrocontroller flashen und die Bedienung des Geräts genießen.

Sie sollten nicht sofort versuchen, Schleifen, Arrays und Funktionen in Ihrer Firmware zu verwenden. Ihre Hauptaufgabe besteht darin, die Firmware zum Laufen zu bringen. Machen Sie es also so, wie es für Sie einfacher ist, und achten Sie nicht auf die Größe des Codes. Es wird die Zeit kommen, in der Sie nicht nur funktionierenden Code schreiben möchten, sondern ihn auch schön und kompakt schreiben möchten. Dann wird es möglich sein, in die Wildnis der C-Sprache einzutauchen. Wer alles beherrschen möchte, dem empfehle ich noch einmal das Buch „How to Program in C“, dort gibt es viele Beispiele und Aufgaben. Installieren Sie Visual Studio, erstellen Sie eine Win32-Konsolenanwendung und üben Sie dort nach Herzenslust.

Lektion 0.

Deshalb eröffnen wir heute eine Reihe von Lektionen zum Programmieren von Mikrocontrollern der AVR-Familie.

Heute werden folgende Fragen besprochen:

  1. Was ist ein Mikrocontroller?
  2. Wo werden Mikrocontroller eingesetzt?

Einführung.

Mikrocontroller gibt es überall. In Telefonen, Waschmaschinen, „Smart Homes“, Werkzeugmaschinen in Fabriken und auch in unzähligen anderen technischen Geräten. Ihre weit verbreitete Verwendung ermöglicht es, komplexe analoge Schaltkreise durch stärker komprimierte digitale Schaltkreise zu ersetzen.

Was ist also ein Mikrocontroller?

Mikrocontroller (Mikrocontroller-Einheit, MCU) - eine Mikroschaltung zur Steuerung elektronischer Geräte. Sie können es sich als einen einfachen Computer vorstellen, der mit externen Geräten interagieren kann. Zum Beispiel Transistoren öffnen und schließen, Daten von Temperatursensoren empfangen, Daten auf LCD-Bildschirmen anzeigen usw. Darüber hinaus kann der Mikrocontroller, genau wie Ihr Personal Computer, verschiedene Verarbeitungen von Eingabedaten durchführen.

Das heißt, Mikrocontroller bieten uns dank des Vorhandenseins von I/0-Ports (Eingangs-/Ausgangsports) sowie der Möglichkeit, diese zu programmieren, nahezu unbegrenzte Möglichkeiten zur Steuerung beliebiger Geräte.

Wo werden Mikrocontroller eingesetzt?

  1. Haushaltsgeräte (Waschmaschinen, Mikrowellenherde usw.).
  2. Mobile Technologie (Roboter, Robotersysteme, Kommunikationsgeräte usw.).
  3. Industrieausrüstung (Maschinensteuerungssysteme).
  4. Computertechnik (Motherboards, Steuerungssysteme für Peripheriegeräte).
  5. Unterhaltungsausrüstung (Kinderspielzeug, Dekorationen).
  6. Transport (Steuerungssysteme für Automotoren, Sicherheitssysteme)

Dies ist keine vollständige Liste der Anwendungen für Mikrocontroller. Aufgrund der vereinfachten Produktion und des geringeren Stromverbrauchs ist es oft sehr profitabel, einen Satz Steuerchips durch einen Mikrocontroller zu ersetzen.

Erste Schritte mit AVR

AVR- eine Familie von Mikrocontrollern von Atmel. Sie bieten ausreichend Leistung für die meisten Amateurgeräte. Sie werden auch häufig in der Industrie eingesetzt.

Das schematische Diagramm des LPT-Port-Programmierers ist in der Abbildung dargestellt. Als Bustreiber verwenden Sie die Mikroschaltung 74AC 244 oder 74HC244 (K1564AP5), 74LS244 (K555AP5) oder 74ALS244 (K1533AP5).

LED VD1 zeigt den Aufzeichnungsmodus des Mikrocontrollers an,

LED VD2 - Lesen,

LED VD3 – Stromversorgung des Stromkreises vorhanden.

Die zur Stromversorgung erforderliche Spannung bezieht die Schaltung aus dem ISP-Anschluss, d. h. vom programmierbaren Gerät. Bei diesem Schaltkreis handelt es sich um einen neu gestalteten STK200/300-Programmierschaltkreis (zur einfacheren Bedienung wurden LEDs hinzugefügt), sodass er mit allen PC-Programmierprogrammen kompatibel ist, die mit dem STK200/300-Schaltkreis arbeiten. Um mit diesem Programmierer zu arbeiten, verwenden Sie das Programm CVAVR

Der Programmierer kann auf einer Leiterplatte hergestellt und im LPT-Steckergehäuse platziert werden, wie in den Abbildungen gezeigt:




Für die Arbeit mit dem Programmierer ist es praktisch, eine LPT-Port-Erweiterung zu verwenden, die man einfach selbst herstellen kann (z. B. aus einem Centronix-Kabel für einen Drucker), Hauptsache, die Leiter für die Erde nicht verschonen (18- 25 Verbindungsbeine) oder kaufen. Das Kabel zwischen dem Programmierer und dem programmierbaren Chip sollte 20–30 cm nicht überschreiten.

Bitweise Operationen basieren auf den zuvor behandelten logischen Operationen. Sie spielen eine Schlüsselrolle bei der Programmierung von AVR und anderen Arten von Mikrocontrollern. Fast kein Programm kommt ohne den Einsatz bitweiser Operationen aus. Zuvor haben wir sie bewusst vermieden, um das Erlernen der MK-Programmierung zu erleichtern.

In allen vorherigen Artikeln haben wir nur I/O-Ports programmiert und keine zusätzlichen integrierten Komponenten verwendet, beispielsweise Timer, Analog-Digital-Wandler, Interrupts und andere interne Geräte, ohne die der MK seine gesamte Leistung verliert.

Bevor Sie mit der Beherrschung der integrierten Geräte des MK fortfahren, müssen Sie lernen, wie Sie einzelne Bits der Register des AVR MK steuern oder überprüfen. Zuvor haben wir eine Prüfung durchgeführt bzw. die Ziffern des gesamten Registers auf einmal eingestellt. Lassen Sie uns herausfinden, was der Unterschied ist, und dann weitermachen.

Bitweise Operationen

Am häufigsten haben wir es bei der Programmierung von AVR-Mikrocontrollern verwendet, da es im Vergleich zu MK-Programmierern für unerfahrene MK-Programmierer visueller ist und für sie gut verständlich ist. Beispielsweise müssen wir nur das 3. Bit von Port D setzen. Dazu können wir, wie wir bereits wissen, den folgenden Binärcode verwenden:

PORTD = 0b00001000;

Mit diesem Befehl setzen wir jedoch die 3. Ziffer auf eins und setzen alle anderen (0, 1, 2, 4, 5, 6 und 7) auf Null zurück. Stellen wir uns nun eine Situation vor, in der das 6. und 7. Bit als ADC-Eingänge verwendet werden und zu diesem Zeitpunkt ein Signal von einem Gerät an den entsprechenden MK-Pins empfangen wird, und wir verwenden den obigen Befehl, um diese Signale zurückzusetzen. Dadurch sieht der Mikrocontroller sie nicht und geht davon aus, dass die Signale nicht angekommen sind. Daher sollten wir anstelle eines solchen Befehls einen anderen verwenden, der nur das 3. Bit auf eins setzt, ohne die restlichen Bits zu beeinflussen. Dazu wird üblicherweise die folgende bitweise Operation verwendet:

PORTD |= (1<<3);

Wir werden die Syntax im Folgenden ausführlich besprechen. Und jetzt noch ein Beispiel. Nehmen wir an, wir müssen den Status der dritten Ziffer des PIND-Registers und damit den Status der Schaltfläche überprüfen. Wird dieses Bit auf Null zurückgesetzt, dann wissen wir, dass die Taste gedrückt wurde und dann wird der Befehlscode ausgeführt, der dem Zustand der gedrückten Taste entspricht. Bisher hätten wir folgende Notation verwendet:

if (PIND == 0b00000000)

(beliebiger Code)

Allerdings überprüfen wir mit seiner Hilfe nicht nur das 3. Bit, sondern alle Bits des PIND-Registers auf einmal. Selbst wenn die Taste gedrückt und das gewünschte Bit zurückgesetzt wird, zu diesem Zeitpunkt jedoch ein Signal an einem anderen Pin von Port D empfangen wird, wird der entsprechende Wert auf eins gesetzt und die Bedingung in Klammern ist falsch. Infolgedessen wird der Code in den geschweiften Klammern nicht ausgeführt, selbst wenn die Schaltfläche gedrückt wird. Um den Zustand eines einzelnen 3. Bits des PIND-Registers zu überprüfen, sollte daher eine bitweise Operation verwendet werden:

if (~PIND & (1<<3))

(beliebiger Code)

Um mit einzelnen Bits des Mikrocontrollers zu arbeiten, verfügt die Programmiersprache C über Tools, mit denen sich der Zustand eines oder mehrerer einzelner Bits gleichzeitig ändern oder überprüfen lässt.

Ein einzelnes Bit setzen

Um ein einzelnes Bit, beispielsweise Port D, zu setzen, wird eine bitweise ODER-Verknüpfung verwendet. Dies haben wir am Anfang des Artikels verwendet.

PORTD = 0b00011100; // Ursprünglicher Wert

PORTD = PORTD | (1<<0); применяем побитовую ИЛИ

PORTD |= (1<<0); // сокращенная форма записи

PORTD == 0b00011101; // Ergebnis

Dieser Befehl setzt das Nullbit und lässt den Rest unverändert.

Lassen Sie uns zum Beispiel ein weiteres 6. Bit von Port D installieren.

PORTD = 0b00011100; // Anfangsstatus des Ports

PORTD |= (1<<6); //

PORTD == 0b01011100; // Ergebnis

Um ein bis mehrere separate Bits gleichzeitig zu schreiben, zum Beispiel den Null-, den sechsten und den siebten Port B Es gilt die folgende Notation.

PORTB = 0b00011100; // Ursprünglicher Wert

PORTB |= (1<<0) | (1<<6) | (1<<7); //

PORTB == 0b1011101; // Ergebnis

Zurücksetzen (Nullsetzen) einzelner Bits

Um ein einzelnes Bit zurückzusetzen, werden drei zuvor besprochene Befehle gleichzeitig verwendet: .

Lassen Sie uns das 3. Bit des PORTC-Registers zurücksetzen und den Rest unverändert lassen.

PORTC = 0b00011100;

PORTC &= ~(1<<3);

PORTC == 0b00010100;

Führen wir ähnliche Aktionen für die 2. und 4. Ziffer durch:

PORTC = 0b00111110;

PORTC &= ~((1<<2) | (1<<4));

PORTC == 0b00101010;

Bitumschaltung

Neben dem Setzen und Rücksetzen kommt auch ein nützlicher Befehl zum Einsatz, der ein einzelnes Bit in den entgegengesetzten Zustand schaltet: Eins auf Null und umgekehrt. Diese logische Operation wird häufig zum Erstellen verschiedener Lichteffekte verwendet, beispielsweise einer Neujahrsgirlande. Schauen wir uns das Beispiel PORTA an

PORTA = 0b00011111;

PORTA ^= (1<<2);

PORTA == 0b00011011;

Lassen Sie uns den Zustand des Null-, zweiten und sechsten Bits ändern:

PORTA = 0b00011111;

PORTA ^= (1<<0) | (1<<2) | (1<<6);

PORTA == 0b01011010;

Überprüfen des Zustands eines einzelnen Bits. Ich möchte Sie daran erinnern, dass die Überprüfung (im Gegensatz zum Schreiben) eines I/O-Ports durch das Lesen von Daten aus dem PIN-Register erfolgt.

Am häufigsten wird der Test mit einer von zwei Schleifenanweisungen durchgeführt: if und while. Diese Operatoren sind uns bereits früher bekannt.

Überprüfen des Bits auf das Vorhandensein einer logischen Null (Reset) mit Wenn

if (0==(PIND & (1<<3)))

Wenn das dritte Bit von Port D gelöscht ist, wird Code1 ausgeführt. Andernfalls wird Code2 ausgeführt.

Bei dieser Form der Aufzeichnung werden ähnliche Aktionen ausgeführt:

if (~PIND & (1<<3))

Überprüfung des Bits auf das Vorhandensein einer logischen Einheit (Einstellung) mit Wenn

if (0 != (PIND & (1<<3)))

if (PIND & (1<<3))

Die beiden oben genannten Schleifen funktionieren ähnlich, können jedoch aufgrund der Flexibilität der Programmiersprache C eine andere Notationsform haben. Der Operator != bedeutet ungleich. Wenn das dritte Bit des PD-I/O-Ports gesetzt ist (eins), wird Code1 ausgeführt; andernfalls wird Code2 ausgeführt.

Warten auf das Zurücksetzen des Bits während

while (PIND & (1<<5))

Code1 wird ausgeführt, solange das 5. Bit des PIND-Registers gesetzt ist. Wenn Sie es zurücksetzen, beginnt Code2 mit der Ausführung.

Warten auf das Setzen des Bits während

Hier ermöglicht die C-Syntax das Schreiben von Code auf zwei der gängigsten Arten. In der Praxis kommen beide Aufnahmearten zum Einsatz.

Mikrocontroller (im Folgenden MK genannt) sind fest in unserem Leben verankert; im Internet finden Sie viele interessante Schaltkreise, die auf MK ausgeführt werden. Was Sie nicht an einem MK montieren können: verschiedene Anzeigegeräte, Voltmeter, Haushaltsgeräte (Schutzgeräte, Schaltgeräte, Thermometer...), Metalldetektoren, verschiedene Spielzeuge, Roboter usw. Die Liste könnte sehr lange dauern. Ich sah den ersten Schaltkreis auf einem Mikrocontroller vor fünf bis sechs Jahren in einer Radiozeitschrift und blätterte fast sofort um und dachte mir: „Ich schaffe es immer noch nicht, ihn zusammenzubauen.“ Tatsächlich waren MKs damals für mich ein sehr komplexes und missverstandenes Gerät; ich hatte keine Ahnung, wie sie funktionierten, wie man sie flashte und was man mit ihnen machen sollte, wenn die Firmware falsch war. Aber vor etwa einem Jahr habe ich zum ersten Mal meine erste Schaltung auf einem MK zusammengebaut; es war eine digitale Voltmeter-Schaltung, die auf 7-Segment-Anzeigen und einem ATmega8-Mikrocontroller basierte. Zufällig kaufte ich zufällig einen Mikrocontroller. Als ich in der Abteilung für Funkkomponenten stand, kaufte der Typ vor mir einen MK, und ich beschloss auch, ihn zu kaufen und zu versuchen, etwas zusammenzubauen. In meinen Artikeln werde ich Ihnen davon erzählen AVR-Mikrocontroller, ich werde Ihnen beibringen, wie man damit arbeitet, wir schauen uns Programme für die Firmware an, wir erstellen einen einfachen und zuverlässigen Programmierer, wir schauen uns den Firmware-Prozess an und, was am wichtigsten ist, die Probleme, die möglicherweise nicht auftreten nur für Anfänger.

Grundparameter einiger Mikrocontroller der AVR-Familie:

Mikrocontroller

Flash-Speicher

RAM-Speicher

EEPROM-Speicher

I/O-Ports

U-Leistung

Zusätzliche Parameter des AVR mega MK:

Betriebstemperatur: -55…+125*С
Lagertemperatur: -65…+150*С
Spannung am RESET-Pin relativ zu GND: max. 13V
Maximale Versorgungsspannung: 6,0 V
Maximaler I/O-Leitungsstrom: 40 mA
Maximaler Stromversorgungsstrom VCC und GND: 200 mA

Pinbelegung des ATmega 8X-Modells

Pinbelegung für die Modelle ATmega48x, 88x, 168x

Pin-Layout für ATmega8515x-Modelle

Pin-Layout für ATmega8535x-Modelle

Pin-Layout für ATmega16, 32x-Modelle

Pin-Layout für ATtiny2313-Modelle

Ein Archiv mit Datenblättern einiger Mikrocontroller ist am Ende des Artikels angehängt.

MK AVR-Installations-FUSE-Bits

Denken Sie daran, dass eine programmierte Sicherung den Wert 0 hat und eine unprogrammierte Sicherung den Wert 1. Beim Setzen von Sicherungen sollten Sie vorsichtig sein; eine falsch programmierte Sicherung kann den Mikrocontroller blockieren. Wenn Sie nicht sicher sind, welche Sicherung Sie programmieren müssen, flashen Sie den MK beim ersten Mal besser ohne Sicherungen.

Die beliebtesten Mikrocontroller unter Funkamateuren sind ATmega8, gefolgt von ATmega48, 16, 32, ATtiny2313 und anderen. Mikrocontroller werden in TQFP- und DIP-Gehäusen verkauft; für Anfänger empfehle ich den Kauf in DIP. Wenn Sie TQFP kaufen, wird es problematischer, sie zu flashen; Sie müssen die Platine kaufen oder löten, weil Ihre Beine liegen sehr nahe beieinander. Ich empfehle Ihnen, Mikrocontroller in DIP-Paketen auf speziellen Sockeln zu installieren. Dies ist bequem und praktisch. Sie müssen den MK nicht ablöten, wenn Sie ihn erneut flashen oder für ein anderes Design verwenden möchten.

Fast alle modernen MKs verfügen über die Fähigkeit zur In-Circuit-ISP-Programmierung, d. h. Wenn Ihr Mikrocontroller mit der Platine verlötet ist, müssen wir ihn zum Ändern der Firmware nicht von der Platine ablöten.

Zur Programmierung werden 6 Pins genutzt:
ZURÜCKSETZEN- Melden Sie sich bei MK an
VCC- Plus Netzteil, 3-5V, abhängig von MK
GND- Gemeinsames Kabel, Minusstrom.
MOSI- MK-Eingang (Informationssignal in MK)
MISO- MK-Ausgang (Informationssignal von MK)
SCK- MK-Eingang (Taktsignal in MK)

Manchmal verwenden sie auch die Pins XTAL 1 und an Pin PE0 und MISO an Pin PE1 angeschlossen. Beim Anschluss des Mikrocontrollers an den Programmierer sollten die Anschlussdrähte möglichst kurz sein und auch das Kabel vom Programmierer zum LPT-Port sollte nicht zu lang sein.

Die Kennzeichnung des Mikrocontrollers kann seltsame Buchstaben mit Zahlen enthalten, zum Beispiel Atmega 8L 16PU, 8 16AU, 8A PU usw. Der Buchstabe L bedeutet, dass der MK mit einer niedrigeren Spannung arbeitet als der MK ohne den Buchstaben L, normalerweise 2,7 V. Die Zahlen nach dem Bindestrich oder Leerzeichen 16PU oder 8AU geben die interne Frequenz des Generators an, der sich im MK befindet. Wenn die Sicherungen so eingestellt sind, dass sie von einem externen Quarz betrieben werden, sollte der Quarz auf eine Frequenz eingestellt werden, die das Maximum laut Datenblatt nicht überschreitet. Diese beträgt 20 MHz für ATmega48/88/168 und 16 MHz für andere Atmegas.


Spitze