Entwicklung einer mobilen Kleinstroboterplattform für die Anwendung in der Lehre und Forschung



Ähnliche Dokumente
Entwicklung einer mobilen Kleinstroboterplattform für die Anwendung in der Lehre und Forschung

Makros sind Textersetzungen, welche vom Präprozessor aufgelöst werden. Dies Passiert bevor der Compiler die Datein verarbeitet.

Mikrocontroller - Schnelleinstieg

Microcontroller Kurs Microcontroller Kurs/Johannes Fuchs 1

1 Vom Problem zum Programm

Hex Datei mit Atmel Studio 6 erstellen

Anleitung zur Daten zur Datensicherung und Datenrücksicherung. Datensicherung

GeoPilot (Android) die App

Wie in der Skizze zu sehen ist, bleibt die Periodendauer / Frequenz konstant und nur die Pulsweite ändert sich.

Einführung in die Welt der Microcontroller

Urlaubsregel in David

ZfP-Sonderpreis der DGZfP beim Regionalwettbewerb Jugend forscht BREMERHAVEN. Der Zauberwürfel-Roboter. Paul Giese. Schule: Wilhelm-Raabe-Schule

PicKit 3. Programmierung mit dem USB-Programmer PICkit3 (Microchip) AB

Bilder zum Upload verkleinern

CU-R-CONTROL. Beschreibung zur Schaltung ATMega16-32+ISP MC-Controller Steuerung auf Basis ATMEL Mega16/32. Autor: Christian Ulrich

AVR Net-IO. Der originale von Pollin vertriebene Bausatz hat folgende Eckdaten:

easyident Türöffner easyident Türöffner Art. Nr. FS-0007 FS Fertigungsservice

schnell und portofrei erhältlich bei beck-shop.de DIE FACHBUCHHANDLUNG mitp/bhv

Leitfaden zur ersten Nutzung der R FOM Portable-Version für Windows (Version 1.0)

Handbuch B4000+ Preset Manager

Wir wünschen Ihnen viel Freude und Erfolg mit Ihrem neuen X-PRO-USB-Interface. Ihr Hacker-Team

Stepperfocuser 2.0 mit Bootloader

Installation und Inbetriebnahme von Microsoft Visual C Express

Der Kalender im ipad

Interrupt-Programmierung

Serie 8: Microcontroller 17./

Installation OMNIKEY 3121 USB

Projekt 2HEA 2005/06 Formelzettel Elektrotechnik

Einstellungen im Internet-Explorer (IE) (Stand 11/2013) für die Arbeit mit IOS2000 und DIALOG

Diese Ansicht erhalten Sie nach der erfolgreichen Anmeldung bei Wordpress.

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

-Konten für Studierende und Zugriffswege auf die Mail-Systeme der Hochschule Rhein-Waal

Mikrocontroller Grundlagen. Markus Koch April 2011

plus Flickerfeld bewegt sich nicht

Baubericht für den AX81-GKR Einleitung

Überprüfung der digital signierten E-Rechnung

Informatik Kurs Simulation. Hilfe für den Consideo Modeler

Wichtige Hinweise zu den neuen Orientierungshilfen der Architekten-/Objektplanerverträge

Windows 7 Winbuilder USB Stick

Anwendungsbeispiele. Neuerungen in den s. Webling ist ein Produkt der Firma:

The ToolChain.com. Grafisches Debugging mit der QtCreator Entwicklungsumgebung

TeamSpeak3 Einrichten

S/W mit PhotoLine. Inhaltsverzeichnis. PhotoLine

Anleitung TempCW 2011

CNC-Fräse für die Schule BLL im Schuljahr 2008/2009

Local Control Network Technische Dokumentation

DOKUMENTATION VOGELZUCHT 2015 PLUS

Aufbau und Bestückung der UHU-Servocontrollerplatine

Programmierung Tiny45 für DCC Lokdecoder

Stellen Sie bitte den Cursor in die Spalte B2 und rufen die Funktion Sverweis auf. Es öffnet sich folgendes Dialogfenster

Tevalo Handbuch v 1.1 vom

ACHTUNG: Es können gpx-dateien und mit dem GP7 aufgezeichnete trc-dateien umgewandelt werden.

Lizenzen auschecken. Was ist zu tun?

Pascal-Compiler für den Attiny

Simulation LIF5000. Abbildung 1

Es sollte die MS-DOS Eingabeaufforderung starten. Geben Sie nun den Befehl javac ein.

Eigenen Farbverlauf erstellen

Fingerpulsoximeter. A. Wie führt man einen Echtzeitdatentransfer vom PULOX PO-300 zum Computer durch und speichert diese Messdaten auf dem PC?

Sie werden sehen, dass Sie für uns nur noch den direkten PDF-Export benötigen. Warum?

Kurzanleitung. MEYTON Aufbau einer Internetverbindung. 1 Von 11

Local Control Network

VB.net Programmierung und Beispielprogramm für GSV

Was ist PDF? Portable Document Format, von Adobe Systems entwickelt Multiplattformfähigkeit,

Wie halte ich Ordnung auf meiner Festplatte?

Die Dateiablage Der Weg zur Dateiablage

Ihre Interessentendatensätze bei inobroker. 1. Interessentendatensätze

M a i l C r e d i t. \\Burt\user\Soutschek\FP\Technik\Frankiermaschinen\00_PC Software\MailCredit\Anleitung MailCredit Installation.

Einfache Computersteuerung für Modellbahnen

Enigmail Konfiguration

Updateanleitung für SFirm 3.1

WORKSHOP VEEAM ENDPOINT BACKUP FREE

Produktinformationen. Basis Set Atmel Atmega8 & ISP Programmer. Lieferumfang :

Refresh vom Vortag. Kommunikation zur SPS (2) Hardwaretest Variablenfenster

Kommunikations-Management

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Parallel-IO. Ports am ATmega128

Lieber SPAMRobin -Kunde!

infach Geld FBV Ihr Weg zum finanzellen Erfolg Florian Mock

Tutorial -

Ablaufbeschreibung für das neu Aufsetzen von Firebird und Interbase Datenbanken mit der IBOConsole

Anleitung über den Umgang mit Schildern

Steganos Secure Schritt für Schritt-Anleitung für den Gastzugang SCHRITT 1: AKTIVIERUNG IHRES GASTZUGANGS

tensiolink USB Konverter INFIELD 7

Folgeanleitung für Fachlehrer

Informationen zur Verwendung von Visual Studio und cmake

Das große ElterngeldPlus 1x1. Alles über das ElterngeldPlus. Wer kann ElterngeldPlus beantragen? ElterngeldPlus verstehen ein paar einleitende Fakten

Der einfache Weg zum CFX-Demokonto

Matrix42. Use Case - Sicherung und Rücksicherung persönlicher Einstellungen über Personal Backup. Version September

Duonix Service Software Bedienungsanleitung. Bitte beachten Sie folgende Hinweise vor der Inbetriebnahmen der Service Software.

1. Einführung. 2. Archivierung alter Datensätze

Erstellen von x-y-diagrammen in OpenOffice.calc

Erstellen einer Collage. Zuerst ein leeres Dokument erzeugen, auf dem alle anderen Bilder zusammengefügt werden sollen (über [Datei] > [Neu])

Umwandelung einer Physikalischen Größe in eine Elektrische

Autoradio On Off Schaltung

Zunächst empfehlen wir Ihnen die bestehenden Daten Ihres Gerätes auf USB oder im internen Speicher des Gerätes zu sichern.

Beschreibung Regeln z.b. Abwesenheitsmeldung und Weiterleitung

Anbindung an easybill.de

Seite 1 von 14. Cookie-Einstellungen verschiedener Browser

MetaQuotes Empfehlungen zum Gebrauch von

Animationen erstellen

Transkript:

Entwicklung einer mobilen Kleinstroboterplattform für die Anwendung in der Lehre und Forschung Stefan Boneberg Bachelorabschlussarbeit im Wintersemester 2012/2013

Studiengang Verfasser Elektrotechnik Physik Plus Stefan Boneberg Matrikel-Nr. 020495 Geburtsdatum 16. Mai 1984 Betreuer Hochschule Betreuer Hochschule Prof. Dr.-Ing. Konrad Wöllhaf Dipl.-Ing. (FH) Joachim Fessler Abgabetermin 24. September 2012 Stefan Boneberg Seite 2 von 65

Erklärung Die vorliegende Bachelorarbeit wurde von mir selbst verfasst und nur mit den angegebenen Quellen und Hilfsmittel angefertigt. Weingarten im September 2012 Stefan Boneberg Stefan Boneberg Seite 3 von 65

Danksagung Diese Bachelorarbeit wurde in der Zeit vom 03.07.2012 bis 24.09.2012 an der Hochschule Ravensburg-Weingarten angefertigt. Für die Aufgabenstellung und die Bereitstellung des Arbeitsplatzes möchte ich mich bei der HS-Weingarten bedanken. Ein besonderer Dank gilt meinem Betreuer Herrn Prof. Dr.-Ing Konrad Wöllhaf für seine Unterstützung (insbesondere bei der Erstellung der Simulation). Ebenso möchte ich mich bei meinem Betreuer Herrn Dipl.-Ing. Joachim Fessler, der mich während dieser Zeit unterstützt hat bedanken. Weingarten im September 2012 Stefan Boneberg Stefan Boneberg Seite 4 von 65

Inhaltsverzeichnis 1. Aufgabenstellung und Ziel der Bachelorarbeit... 7 2. Einleitung... 8 3. Der Korsel mit einem ATtiny26L und einer Reflektionslichtschranke... 9 3.1 Benötigte Bauteile und Kosten ATtiny26... 10 3.2 Wirkungsweise der Bauteile, kurzer Überblick:... 11 3.3 Schaltplan Korsel mit ATtiny26... 12 3.4 Platine des Korsels... 13 3.5 Installation des AVR Studios (Programmieren des Mikrocontrollers)... 14 3.5.1 RN CONTROL-Board oder andere Hardware... 14 3.6 Das Programm des ATtiny26L... 15 3.6.1 C Programm... 15 3.7 Konfiguration der Ein- und Ausgänge... 18 3.8 Konfiguration der Analog-Digital-Wandlung (AD Wandler)... 19 3.8.1 Die Einstellung des Registers ADMUX... 19 3.8.2 Die Einstellung des Registers ADCSR... 20 3.9 Konfiguration der Puls Weitenmodulation der Motoren... 20 3.9.1 Die Einstellung des Registers TCCR1A... 22 3.9.2 Die Einstellungen des Registers TCCR1B... 22 3.9.3 Die Register OCR1A und OCR1B... 23 3.10 Vor- und Nachteile eines Korsels mit einer Reflektionslichtschranke und einem ATtiny26L... 24 4. Der Korsel mit einem ATmega32 und drei Reflektionslichtschranken... 25 4.1 Benötigte Bauteile und Kosten ATmega32... 26 4.2 Schaltplan Korsel mit ATmega32... 27 4.3 Platine des Korsels mit ATmega32... 28 4.4 Programmieren mit einem JTAGICE mkii Programmer... 29 4.4.1 Einstellungen im AVR-Studio um mit JTAGICE zu debuggen... 30 4.5 Die Fuses des Mikrocontrollers... 33 4.6 Das Programm des ATmega 32 mit drei Reflektionslichtschranken... 34 4.6.1 Implementieren der Bibliotheken... 34 4.6.2 Initialisieren der Variablen... 34 4.6.3 IO-Ports initialisieren... 35 Stefan Boneberg Seite 5 von 65

4.6.4 ADC-Wandler initialisieren... 36 4.6.5 PWM initialisieren... 36 4.6.6 Hauptprogramm (MAIN)... 37 4.7 Die Sensoren des Korsels... 43 4.7.1 Grundlegende Funktionsweise unsere Sensoren... 45 4.8 Einstellungen des Analog-/Digital-Wandlers (ATmega32)... 46 4.8.1 Die Einstellung des Registers ADMUX... 46 4.8.2 Die Einstellung des Registers ADCSRA... 47 4.8. 3 Die Einstellung des Registers SFIOR... 47 4.9 Batterie Spannungs-Berechnung... 48 4.10 Einstellungen der PWM (ATmeaga32)... 49 4.10.1 Die Einstellung des Registers TCCR1A... 49 4.10.2 Die Einstellungen des Registers TCCR1B... 50 4.11 Grundlegende Funktion der Bauteile, Korsel mit ATmega32 (drei Sensoren)... 51 4.12 Vor- und Nachteile eines Korsels mit einem ATmega 32... 52 5. Simulation des Korsels... 53 5.1 Vorgehensweise um die Simulation zu starten... 53 5.2 Plausibilität der Simulation... 55 6. Das digitale Regelsystem (Abtastregelung)... 56 7. Erreichte und angepasste Ziele... 59 8. Verbesserungsvorschläge und Ausblick... 60 9. Inhalt der Daten-CD... 62 10. Literaturverzeichnis... 64 11. Abbildungsverzeichnis... 65 Stefan Boneberg Seite 6 von 65

1. Aufgabenstellung und Ziel der Bachelorarbeit Ziel der Bachelorarbeit ist die Entwicklung einer mobilen Kleinstroboterplattform für Anwendungen in der Lehre und Forschung. Die Plattform soll die Möglichkeit bieten, verschiedene Aufgaben aus der Lehre und Forschung an einer robusten und kostengünstigen Hardware zu behandeln. Wobei die Aufgaben thematisch wie auch in der Komplexität unterschiedlich sein können. So soll diese Plattform von Schulen wie auch von Hochschulen - je nach Aufgabenstellung und Wissensstand - für Übungen oder Forschungen verwendet werden können. Hierbei gibt es drei Hauptschwerpunkte: Hardware: Arbeiten mit Schaltplan- und Layoutprogrammen Auswahl und Positionierung von Sensorik Bestücken und Löten von Hardware sowie Auswahl der Hardware-Komponenten Software: Erstellen eines Programms für einen Mikrocontroller Programmieren eines Mikrocontrollers über verschiedene Schnittstellen (ISP, JTAG) Regelungstechnik / Simulation: Simulation der Hardware in Matlab Auslegung der Regelparameter Die Plattform wird so entworfen, dass die Hard- und Software an neue Aufgabenstellungen und Anwendungsfälle angepasst werden kann. In der Grundausführung besteht die Hardware aus einer Leiterplatte, die gleichzeitig das Chassis ist. Angetrieben wird die Plattform durch zwei DC-Motoren. Die Sensorik besteht aus Reflektionslichtschranken, die die Farbe des Untergrunds erkennen. Die Software beinhaltet die Ansteuerung der Motoren via PWM, das Einlesen der Sensoren sowie die Verarbeitung der dadurch gewonnenen Daten. In der Simulation wird das Modell der Hardware dargestellt. Stefan Boneberg Seite 7 von 65

2. Einleitung Es gibt jetzt schon eine Vielzahl mobiler Kleinstroboter wie z.b. den AREXX ASURO (Abb.1). Die Kosten betragen allerdings ca. 50, auch ist der Aufbau mit diskreten Bauteilen realisiert. Der Zusammenbau und auch die Fehlersuche gestalten sich daher eher schwierig. Abbildung 1 Asuro Abbildung 2 POB BOT Auch gibt es Roboter wie den Lego MINDSTORM (200 ), der allerdings eher für Kinder gedacht ist. Des weiteren gibt es Roboter wie den POB BOT, die Kosten liegen bei 500 US$. Jetzt zum KORSEL Der Korsel (Name des mobilen Kleinstroboters) konnte über eine Reflexionslichtschranke nur den schwarzen oder den weißen Untergrund unterscheiden und gab diesen Wert dann an den Mikrocontroller in Form einer 1 oder 0 weiter. Dadurch konnte der Korsel seine Motoren nur ein- und ausschalten. Die Folge davon war, dass der Korsel sehr holprig seiner Bahn folgte. Da die Bauteile sehr günstig sind, ist es nicht verwunderlich, dass die Motorleistungen stark schwanken - dies hatte zur Folge, dass jeder Korsel der gebaut wurde, ein eigenes Programm benötigte, welches von Hand eingestellt werden musste. Die Mechanik des Korsel war schon sehr gut und benötigte nur noch geringfügige Änderungen. Stefan Boneberg Seite 8 von 65

3. Der Korsel mit einem ATtiny26L und einer Reflektionslichtschranke Abbildung 3Korsel ATtiny26 Abbildung 4 Korsel ATtiny 26 Stefan Boneberg Seite 9 von 65

3.1 Benötigte Bauteile und Kosten ATtiny26 Anzahl Name Bezeichnung Bestellnummer und Lieferant Kosten 2 Motor IGARASHI DC Kleinstmotor 2025-02 Conrad Bestell-Nr: 244414 - V3 3,45 2 NPN Transistor BC 817-50 in SMD Bauform Reichelt Bestell-Nr: BC 817-40 SMD 0,04 1 Mikrocontroller ATtiny26L Reichelt ATTINY 26L8 SO20 2,10 2 Taster Typ Kurzhubtaster Reichelt Bestell-Nr: TASTER 3301 0,11 1 Reflektionslichtschranke Typ CNY 70 Reichelt Bestell-Nr: CNY 70 0,70 2 Freilauf-Diode Typ 4148 Reichelt Bestell-Nr: SMD 1N 4148 0,02 1 Batterieclip Batterieclip für 9-Volt-Block Reichelt Bestell-Nr: CLIP HQ9V-T 0,24 1 Spannungsregler Schaltregler ST Microelectronics L 78 L 05 Conrad Bestell-Nr.: 156058-62 0,23 1 Schalter Schiebeschalter 1 x Ein/Ein 50 V 0,5 A Conrad Best.-Nr.: 708054-62 0,49 1 SMD-Widerstände Baugröße 1206 SMD 4,7k Ohm 0,10 2 SMD-Widerstände Baugröße 1206 SMD 8,2k Ohm 0,10 1 SMD-Widerstände Baugröße 1206 SMD 330 Ohm 0,10 1 SMD-Widerstände Baugröße 1206 SMD 12k Ohm 0,10 1 SMD-Widerstände Baugröße 1206 SMD 4,7k Ohm 0,10 1 SMD-Widerstände Baugröße 1206 SMD 5,6k Ohm 0,10 2 Kondensatoren Baugröße 1206 SMD 100nF 0,45 1 Entstör Kondensatoren AX 100/16 100uF 16V Reichelt B36-630 0,15 1 Entstör Kondensatoren AX 220/16 220uF 16V Reichelt B36-541 0,16 2 LED LED 5mm Reichelt Artikel-Nr.: LED 5MM GN 0,06 1 Stiftleiste Stiftleisten 2,54 mm, 2X02, gerade Reichelt MPE 087-2-004 0,10 1 9V Block energy Alkaline 9 V Block-Batterie Conrad Best.-Nr.: 658014-62 3,50 3 Messpunkte Lötnägel 1mm, versilbert Reichelt RTM 1-100 0,01 0,25 Grundplatine Bungard Platinen-Basismaterial Cu-Auflage Conrad Best.-Nr.: 523798-62 5,19 Reifen O-Ring: Innendurchmesser 20mm Dicke: 4 2mm BB-608-A500-10-ES (Kunststofflager Räder Kugellager 2 von IGUS) 1 Achse z.b. 8mm-Alu-Rohr aus dem Baumarkt Isolierte Drähte für den 4 Anschluss der Motoren Gesamt: 17,96 Stefan Boneberg Seite 10 von 65

3.2 Wirkungsweise der Bauteile, kurzer Überblick: Der ATtiny26L ist ein 8bit Mikrocontroller aus der Atmelreihe. Er hat einen 2k Bytes Flasch Speicher und was hier sehr wichtig war - einen internen Analog-Digital-Wandler. Programmiert wird er über eine ISP-Schnittstelle. Um sicher zu arbeiten, benötigt er eine Spannung von 2,7 V bis 5,5 V. Das L steht für diesen Spannungsbereich. Seine maximale Taktfrequenz beträgt 8 MHz. Die Energieversorgung wird über einen günstigen Nickel-Metall-Hydrid-Akkumulator mit einer Spannung von 8,4 V realisiert. Die ATtiny26L steuert zwei Transistoren, welche dann die Motoren an- und abschalten. Für die Energieversorgung der Motoren wird der 9-V-Block direkt angeschlossen, zur Stabilisierung und Entstörung der Spannung ist ein Kondensator mit 220 uf vorgesehen. Zum Entstören ist zusätzlich noch ein 100 nf Kondensator verbaut. Die Spannung für die Reflektionslichtschranke sowie für den Mikrocontroller wird über den L78L05 (Festspannungsregler) bereitgestellt. Er liefert eine konstante Ausgangspannung von 5 V und einen Strom von 0,1 A. Der Kondensator mit 100 uf und der Kondensator mit 100 nf glätten diese und sorgen dafür, dass die Spannung auch beim Einkoppeln von Störsignalen durch die Motoren konstant bleibt und der Mikrocontroller sicher arbeiten kann. Am Heck des Korsel s ist ein Schalter montiert, mit dem man ihn komplett spannungslos schalten kann. Eine LED, die links daneben angebracht ist, zeigt an ob der Korsel Spannung hat oder nicht. Da die Motoren über eine PWM (Puls Weiten Modulation) angesteuert werden, benötigen sie auch sogenannte Freilaufdioden - diese übernehmen in den Pausenphasen der PWM den Strom der Motoren. Würden diese Dioden falsch oder gar nicht eingebaut, könnten große Spannungsspitzen entstehen, die andere Bauteile zerstören. Der Kurzhubtaster sowie die zweite LED ist für diverse Abänderungen in der Zukunft gedacht. Programmiert wird der ATtiny26 über einen AVR Atmel-Programmer (AVRISP mkii) - dies ist ein sehr günstiges Programmiergerät (unter 40 ). Auch ist es einfach zu bedienen (sehr gut für die ersten Schritte geeignet). Der große Nachteil des AVRISP mkii ist, dass es kein Debugging unterstützt. Stefan Boneberg Seite 11 von 65

3.3 Schaltplan Korsel mit ATtiny26 Stefan Boneberg Seite 12 von 65

3.4 Platine des Korsels Stefan Boneberg Seite 13 von 65

3.5 Installation des AVR Studios (Programmieren des Mikrocontrollers) Mit der Software AVR-Studio, dem AVRISP USB - Programmer kann man eine große Anzahl von Mikrocontroller-Derivaten der Firma Atmel programmieren (brennen / flashen ). Weiter bietet AVR- Studio eine IDE (Integrierte Entwicklungsumgebung) mit Assembler. Einen passenden C-Compiler erhält man durch die Installation der Software WINAVR. Das Software-Paket WINAVR ist eine IDE mit C-Compiler. Wenn AVR-Studio und WINAVR auf einem PC installiert sind, erkennt AVR-Studio den Compiler von WINAVR automatisch. Als Entwicklungsumgebung steht dann AVR-Studio mit folgenden Features zur Verfügung: IDE, Assembler, C-Compiler und Programmier- / Brennsoftware Folgender Weg für die Installation von AVR-Studio mit WINAVR und für das Anlegen eines Projekts hat sich als praktikabel erwiesen: 1. AVR Studio installieren (hierbei immer die neueste Version verwenden / www.atmel.com). 2. Programmiergeräte anschließen: Anschluss AVRISP-USB: Programmer via USB anschliessen. Schwarzer Con-Button ( ) in der oberen Menüleiste klicken und den Programmer AVRISP mkii auswählen. Eventuell verlangt AVR Studio ein Firmwareupdate für den USB-Programmer. Hierzu einfach den Anweisungen auf dem Bildschirm folgen. Test: Schwarzer Con-Button ( AVRISP auswählen. ) in der oberen Menüleiste klicken und Abbildung 5 AVR Programmer 3. WINAVR installieren (http://winavr.sourceforge.net). Nach der WINAVR Installation erkennt AVR-Studio nun automatisch den gcc-compiler von WINAVR und verwendet diesen. 4. Im Windows-Explorer ein Projektverzeichnis für ein neues Projekt anlegen. 5. Im AVR-Studio neues Projekt anlegen (angelegtes Projektverzeichnis wählen). 6. Make-File in das Projektverzeichnis kopieren (im Unterverzeichnis sample einer WinAVR Installation findet man eine sehr brauchbare Vorlage). Make-File ggf. anpassen. Bei WINAVR gibt es auch das nützliche Tool Mfile. ( Fessler Joachim & Feucht Achim) 3.5.1 RN CONTROL-Board oder andere Hardware Es besteht auch die Möglichkeit zur Programmierung eines ATMega-Controller die ISP-Schnittstelle zu verwenden. Diese kann über ein Programmierdongel an den Parallel-Port des PC s angeschlossen werden. Hierbei kann AVR-Studio nicht mehr zum Flashen verwendet werden. Alternativen: AVRDUDE Bestandteil von WINAVR. Programmierung über Konsole Pony Prog mit grafischer Oberfläche. Zu finden unter www.lancos.de Weitere Infos sind zu finden unter http://www.kreatives-chaos.com/index.php?seite=avrgcc ( Fessler Joachim & Feucht Achim) Stefan Boneberg Seite 14 von 65

3.6 Das Programm des ATtiny26L Abbildung 6 Korsel mit Programmer 3.6.1 C Programm //************************************************************************************ //einbinden der Bibliotheken //************************************************************************************ #include <io.h> #define F_CPU 1000000UL #include <util/delay.h> #include <stdint.h> //************************************************************************************ //Definition der Variablen //************************************************************************************ uint16_t x = 0; //Analogwert zur Berechnung der Motoren PWM (Wert der Analog Digitalwandlung, halbiert) uint16_t y = 0; //Analogwert zur Berechnung der Motoren PWM (Spiegelung das ADC Werts) uint16_t r = 0; //Analogwert zur Berechnung der Motoren PWM (Motor rechts) uint16_t l = 0; //Analogwert zur Berechnung der Motoren PWM (Motor links) #define Motor_links #define Motor_rechts OCR1A //OCR1A heißt jetzt Motor_links OCR1B //OCR1B heißt jetzt Motor_rechts Stefan Boneberg Seite 15 von 65

//************************************************************************************ //IO-Ports initialisieren //************************************************************************************ void init_io(void) { //Motor links DDRB = 0xFF; //Port B als Ausgang PORTB &= ~(1 << PB1); //PB1 auf low PORTB &= ~(1 << PB3); PORTB = (1 << PB6); //Motor rechts //PB5 auf low //PB6 auf high PORTA = (1 << PA2); //PA7 als Eingang mit Pull-up (Taster) PORTA = (1 << PA7); //PA7 als Eingang mit Pull-up (Reflektionslichtschranke) DDRA &= ~(1 << PA2); //PA7 als Eingang (Taster) DDRA &= ~(1 << PA7); //PA7 als Eingang (Reflektionslichtschranke) DDRA =(1 << PA6); PORTA &= ~(1 << PA6); //PA6 als Ausgang (LED) //PA6 auf low (LED) //************************************************************************************ //Einstellen der ADC Wandlung //************************************************************************************ void ADC_Init(void) { //Einstellen des AD Wandlers ADMUX = 0b00000110; //Verwenden der internen Referenzspannung Datenblatt S.8 //und Einstellen des ADC s 6 Port 7 ADCSR = 0b11100110; //Einstellen des Freilaufs und Aktivierung des ADC s //Freilauf bedeutet ununterbrochene Konvertierung (muss nicht extra gestartet werden) //************************************************************************************ //PWM initialisieren //************************************************************************************ void pwm (void) { DDRB = (1<<PB1); // Einstellen welcher Ausgang über PWM angesteuert werden soll DDRB = (1<<PB3); // Einstellen welcher Ausgang über PWM angesteuert werden soll TCCR1A = 0b01010011; TCCR1B = 0b00000011; // Einstellen der PWM A und B mit Modusauswahl // Teiler von 4 einstellen jetzt (CK/4) OCR1C = 255; // oberstes PWM Limit setzen (wichtig beim ATtiny 26) OCR1B = 200; OCR1A = 200; PLLCSR = (1<<PLLE); // Asynchrones PLL benutzen, 64MHz Taktquelle Stefan Boneberg Seite 16 von 65

1.6.1.1 Hauptprogramm (MAIN) //************************* MAIN ************************* int main (void) { init_io(); ADC_Init(); pwm(); //IOs Konfigurieren //Analog-Digitalwandler konfigurieren //Ausgänge für die Motoren als PWM initialisieren while (1) { // Start der Endlosschleife x = ADC/2; // der Wert der Analogdigitalwandlung beträgt maximal 1023 (10Bit)(nur ein theoretischer Wert, der nie erreicht wird) y = 500-x; // Spiegelung des halbierten ADC Wertes if(x>250){ // wenn die AD-Wandlung einen größeren Wert als 500 liefert, befindet sich der Sensor des Korsels eher auf schwarzem Untergrund l = 255; // schwarzer Untergrund bedeutet linker Motor volle Leistung (wenn in dem Register OCR1A 255 steht, findet keine PWM mehr statt) r = 20+y; // rechter Motor drosseln (20 ist ein Offset um den Motor ruhiger laufen zu lassen) if(x<250){ // wenn die AD-Wandlung einen kleineren Wert als 500 liefert, befindet sich der Sensor des Korsels eher auf weißem Untergrund r = 255; //rechter Motor volle Leistung l = 20+x; //linker Motor drosseln (20 ist ein Offset um den Motor ruhiger laufen zu lassen) if ((r>255) ) { r=255; if ((l>255) ) { l=255; //die PWM der Motoren darf keinen größeren Wert als 255 (8Bit)bekommen //die PWM der Motoren darf keinen größeren Wert als 255 (8Bit)bekommen if ((r<0) ) { r=0; //die PWM der Motoren darf keinen kleineren wert als 0 bekommen if ((l<0) ) { l=0; //die PWM der Motoren darf keinen kleineren wert als 0 bekommen Motor_links = l/10*5; //da auf dem ATtiny nur einfache Programme zum Einsatz kommen können, müssen wir hier die Motoren noch einmal etwas verlangsamen Motor_rechts = r/10*5; //Ende der Endlosschleife return (0); Stefan Boneberg Seite 17 von 65

3.7 Konfiguration der Ein- und Ausgänge Ein ausführliches Tutoriell finden sie auf der Seite http://www.mikrocontroller.net/articles/avr-gcc- Tutorial#Zugriff_auf_IO-Ports Grundsätzlich ist es so, dass ein Mikrocontroller erst einmal wissen muss, ob seine Pins Eingänge oder Ausgänge sind. Dafür sind die Register DDRX da. In diesem Programm werden beispielsweise alle Bits des Registers DDRB auf 1 gesetzt. Um dies zu erreichen gibt es mehrere Möglichkeiten. Hier wird eine hex Zahl in das Registers geschrieben (DDRB = 0xFF). Eine andere Möglichkeit ist einzelne Bits einzustellen. Auch dies wurde in diesem C Programm gemacht. Möchte man beispielsweise den Ausgang PB1 auf Low setzen, so kann man dafür folgenden Befehl benutzen: Negation PB1 = 1 (wir könnten statt PB1 auch eine 1 schreiben, für den Compiler ist das gleichbedeutend) PORTB &= ~(1 << PB1); Bitweise UND Verknüpfung Das ist ein Schiebebefehl, d.h. schiebe eine 1 um eins nach links Der gesamte Befehl lautet daher: Schiebe eine 1 um eins nach links, negiere diese 1, mache eine Bitweise und Verknüpfung mit PORTB, schreibe das Ergebnis in PORTB. An der Stelle 1 des Registers PORTB wurde jetzt eine 0 geschrieben. Die anderen Bits des Registers PORTB wurden nicht verändert. Ähnlich kann man es auch machen, wenn man eine 1 in das Register schreiben will. Dies würde dann so aussehen: PORTB = (1 << PB1). Mit diesem Befehl kann man an die Stelle von PB1 eine 1 in das Register PORTB schreiben. Diese Schreibweisen bedeutet zwar einen etwas höheren Arbeitsaufwand, aber auch mehr Transparenz und Übersichtlichkeit. Stefan Boneberg Seite 18 von 65

3.8 Konfiguration der Analog-Digital-Wandlung (AD Wandler) Abbildung 7 AD-Wandler Funktion (Wirth, 2011) Die grundlegende Funktion des AD-Wandlers ist, zu einem bestimmten Zeitpunkt (Ta) einen bestimmten Wert der analogen Messgröße einem Binärwert zuzuordnen - wie in Abbildung 5 ersichtlich. Bei diesem ATtiny 26 kann man die Abtastzeit (Ta) verändern, indem man das Register ADCSR verändert. An sich ist ein schnelles Abtasten immer besser, aber es kostet Rechenzeit und man muss mit den konvertierten Werten auch etwas anfangen können. Der ATtiny 26 besitzt einen echten AD Wandler, der auf verschiedene Eingänge geschaltet werden kann. Grundlegende Formel zum Berechnen des ADC Wertes: Unsere Schaltung hat also eine Auflösung von, was mehr als ausreichend ist. 3.8.1 Die Einstellung des Registers ADMUX = 0b00000110 (ATMEL, Datenblatt ATtiny26) 00 = an der Stelle 7 und 6 (REFS1, REFS0) steht eine 00. Hiermit kann man die Vergleichsquelle einstellen, hier wurde als Referenzspannung AVCC gewählt. Um einen genaueren Wert zu bekommen, muss an diesen Pin ein 100nF-Kondensator angeschlossen werden. AVCC ist an 5 V angeschlossen, das ist jetzt unsere Obergrenze, d.h. 5 V = 1024 (10Bit Konvertierung). 0 = an der Stelle 5 (ADLAR) ist eine 0. Das bedeutet, das lsb ist bei dem Register ADC (im ADC- Register steht das Ergebnis der AD-Umwandlung) auf der rechten Seite. Stefan Boneberg Seite 19 von 65

00110 = an den Stellen 0,1,2,3 und 4 (MUX0 bis MUX4) ist eine 00110. Hier kann man den zu konvertierenden Eingang festlegen. In diesem Programm ist das der Eingang ADC 6 (PA7) 3.8.2 Die Einstellung des Registers ADCSR =0b11100001 (ATMEL, Datenblatt ATtiny26) 1 = an der Stelle 7 (ADEN) steht eine 1. Hiermit aktiviert man den AD-Wandler. 1 = an der Stelle 6 (ADSC) steht eine 1. Da dieser AD-Wandler im Free running Mode laufen gelassen wird, muss hier eine 1 stehen um die erste Konvertierung zu starten. 1 = an der Stelle 5 (ADFR) steht eine 1. Hier wird der Free running Mode eingestellt. 0 = an der Stelle 4 (ADIF) steht eine 0. Hier könnte man Interrupts abfragen, immer wenn eine Konvertierung vollständig ist wird ADIF auf 1 gesetzt (in unserem Programm ohne Bedeutung). 0 = an der Stelle 3 (ADIE) steht eine 0. Hier könnte man die Interrupt-Funktion einschalten. 001 = an den Stellen 0,1,2 (ADPS2, ADPS1, ADPS0) steht eine 001. Hiermit könnte man die Geschwindigkeit des AD-Wandlers einstellen. Hier ist ein Teiler von 2 eingestellt, d.h. Mit diesen Einstellungen hat man jetzt einen AD-Wandler der ununterbrochen die Spannung am Pin PA7 mit 5 V vergleicht und daraus eine Zahl zwischen 0 und 1024 generiert. Dieses Ergebnis wird in die Register ADCH und ADCL geschrieben. Man kann diese beiden Register auch mit ADC auslesen, da das Register ADC, ADCH und ADCL also 16 Bit enthält. 3.9 Konfiguration der Puls Weitenmodulation der Motoren Im folgenden Abschnitt wird die grundsätzliche Funktionsweise der PWM von der I-Net Seite Robonetz beschrieben: Die Pulsweitenmodulation (oft mit PWM abgekürzt) wird vornehmlich zum Ansteuern größerer Lasten, wie z.b. Motoren verwendet. Mikrocontroller haben daher oft bereits spezielle PWM-Ausgänge integriert. Bei der Pulsweitenmodulation werden Impulse mit voller Spannung aber variabler Breite an die Last gesendet. Ein Rechtecksignal mit konstanter Frequenz wird also mit einem bestimmten Tastverhältnis moduliert. Eine PWM ist also charakterisiert durch ihre Frequenz und ihr Tastverhältnis (duty cycle). Vorteil dieser Ansteuerung ist, dass weniger Leistung verbraucht wird, da nicht permanent eine Eingangsspannung anliegt, die von einer Elektronik auf die gewünschte Motorspannung heruntergeregelt wird, sondern der Motor durch die Breite der Schaltimpulse gesteuert wird. Stefan Boneberg Seite 20 von 65

Diese drei Skizzen demonstrieren, wie ein Motor mit unterschiedlicher Pulsweite in drei verschiedenen Geschwindigkeiten geregelt wird. In der Praxis ist die Pulsweite oft in 255 Schritten (8 Bit) und mehr regelbar. Gut zu erkennen ist in der Skizze, dass die eigentliche Grundfrequenz bei der Pulsweitenmodulation nicht verändert wird, sondern lediglich das Verhältnis der Ein- und Ausschaltzeit pro Welle (Ton und Toff). Die Modulationsfrequenz kann dabei variieren. (RoboterNETZ, 2012) Der ATtiny 26 kann über die Timer (Timer_Counter_0 und Timer_Counter_1) zwei interne PWM- Signale erzeugen. Von Atmel wird empfohlen, auch diese beiden Timer für die Erzeugung eines PWM-Signals zu nutzen (ein PWM Signal kann auch an jedem anderen Ausgang über ein entsprechendes Programm realisiert werden). Man verwendet den Timer_Counter_1. Um ein PWM-Signal erzeugen zu lassen, muss man als erstes die Register TCCR1A und TCCR1B einstellen. In den beiden Registern wird die Arbeitsweise des Timers festgelegt. Stefan Boneberg Seite 21 von 65

3.9.1 Die Einstellung des Registers TCCR1A = 0b01010011; (ATMEL) 0b = die Abkürzung steht für eine binäre Zahlenfolge 01 = an der Stelle 7 und 6 (COM1A1, COM1A0) steht eine 01. Dies bedeutet, er soll bei dem Registerwert von OC1A schalten. 01 = an der Stelle 5 und 4 (COM1B1, COM1B0) steht eine 01. Dies bedeutet, er soll bei dem Registerwert von OC1B schalten. 00 = an der Stelle 3 und 2 (FOC1A, FOC1B) steht eine 00. Durch das Einstellen auf den PWM-Modus haben diese beiden Nullen keine Bedeutung. 11 = an der Stelle 1 und 0 (PWM1A, PWM1B) steht eine 11. Hier wird die PWM des Timers1 A und B eingeschaltet. 3.9.2 Die Einstellungen des Registers TCCR1B = 0b00000011 (ATMEL) 0 = an der Stelle 7 (CTC1) steht eine 0. Dies bedeutet, dass der Timer beim Vergleich von OCR1A und OCR1B mit OCR1C nicht auf 0 zurückgesetzt wird. 0 = an der Stelle 6 (PSR1) steht eine 0. Hier kann man den Teiler des Timers zurücksetzen wenn man eine 1 in das Register schreibt hier im PWM-Modus ohne Effekt. 0011 = an den Stellen 0,1,2 und 3 (CS10, CS11, CS12, CS13) kann man den Teiler der PWM einstellen, d.h. CK / Teiler = Frequenz der PWM. Hier wurde ein Teiler von 4 eingestellt, dadurch erhält man eine PWM mit einer Frequenz von 2 khz. Die richtige Auswahl der PWM -Frequenz hängt maßgeblich vom verwendeten Motor ab. Der Vorteil einer hohen Frequenz, ca. 15 khz bis 18 khz, ist ein ruhiger (glatter) Lauf der Motoren. Außerdem ist man schon fast im nicht mehr hörbaren Bereich (menschliches Gehör maximal bis 20 khz). Der Motor kommt dem Menschen leiser vor. Die Nachteile von hohen Frequenzen sind höhere Schaltverluste in den Bauteilen, höhere Ummagnetisierungsverluste in den Motoren sowie mehr Störungen auf der Platine. Da man hier sehr günstige Motoren verwenden, die sowieso schon Störungen auf andere Bauteile einkoppeln, möchte man keine derart hohen Frequenzen. Auch ist die etwas größere Geräuschentwicklung bei den kleinen Motoren vernachlässigbar. Bei diesem Korsel ist eine PWM- Frequenz von 0,5 khz bis 5 khz zielführend. Stefan Boneberg Seite 22 von 65

3.9.3 Die Register OCR1A und OCR1B Der Wert der Register OCR1A und OCR1B beeinflusst die Pulslänge der PWM: Abbildung 8 PWM Register OCR1A Abbildung 9 PWM Register OCR1B Wie man an den Grafiken (Abb. 8,9) erkennen kann, kann man durch Erhöhen der Registerwerte OCR1A und OCR1B die Einschaltdauer erhöhen und dadurch den Mittelwert der Spannung ebenfalls erhöhen. Stefan Boneberg Seite 23 von 65

3.10 Vor- und Nachteile eines Korsels mit einer Reflektionslichtschranke und einem ATtiny26L Vorteile: - Einfacher und robuster Aufbau - Geringe motorische Fähigkeiten beim Löten erforderlich - Geringe Anzahl an verschiedenen Bauelementen - Einfach zu programmieren - Geringe Gesamtkosten des Projekts (ohne Programmer ca. 20 pro Korsel) - Lange Laufzeit 2,5 h (Akku mit 8,4 V und 200 ma) - Klein, leicht und wendig - Durch das sehr kleine und einfache Programm braucht der ATtiny26 nur 0,5ms um das gesamte Programm einmal abzuarbeiten - Die PWM arbeitet mit einer Frequenz von 2 khz (damit ist es zwar im hörbaren Bereich, aber sie koppelt nicht so viele Störungen ein wie eine schnellere PWM), d.h. er ist robuster Nachteile: - Da der interne Speicher recht klein ist, ist es nicht möglich größere Programme laufen zu lassen - Wegen des begrenzten Speichers ist es nicht möglich einen Differential-Regler zu implementieren und dadurch den I-Anteil des Systems zu kompensieren - Da der ATtiny keine JATAG-Schnittstelle besitzt, ist ein on-chip-debugging nicht möglich (kein Auslesen der Sensorenwerte, d.h. keine exakten Berechnungen möglich) - Mit nur einer Reflektionslichtschranke sind nur kleine Regelabweichungen erkennbar - Die Spannung der günstigen Akkumulatoren schwankt stark (je nach Ladezustand), deshalb schwankt auch die Motorleistung stark. Eine Lösung ist das Schreiben eines Programmes, welches die Spannungsschwankungen der Batterie kompensiert. Leider hat der ATtiny dafür zu wenig Speicher. Auch die Rechenzeit würde sich durch eine zusätzliche AD-Wandlung erhöhen - Zusätzliche Schiebeschalter, mit denen man z. B. verschiedene Programme abrufen kann, sind auch nicht möglich oder sinnvoll (zu geringer Speicher) Fazit: Der Korsel mit einem ATtiny 26 ist sehr gut für Schüler geeignet, stößt aber schnell an seine Grenzen. Deshalb hat man sich hier dazu entschieden einen weiteren Korsel zu bauen - dieser sollte mehr Schnittstellen haben (ISP, UART, JTAG). Mit JTAG kann auch ein Debugging realisiert werden. Außerdem sollte er mehr Sensoren bekommen und auch einige Schiebeschaler enthalten. Der Korsel mit einem ATtiny26 ist bereits im Stande einer Linie zu folgen. Allerdings ist seine Geschwindigkeit nicht sehr hoch, sobald die Geschwindigkeit erhöht wir hat er Probleme seiner Bahn zu folgen, das soll auch eines der Ziele für den nächsten Korsel darstellen. Stefan Boneberg Seite 24 von 65

4. Der Korsel mit einem ATmega32 und drei Reflektionslichtschranken ISP-Schnittstelle JATAG-Schnittstelle Taster (für folgende Erweiterungen) Schiebeschalter (Abruf von verschiedenen Programmen) UART-Schnittstelle ATmega 32 LED um den Status (ein/aus) anzuzeigen LED s um verschiedene Zustände anzuzeigen Stefan Boneberg Seite 25 von 65

4.1 Benötigte Bauteile und Kosten ATmega32 Anzahl Name Bezeichnung Bestellnummer und Liferant Kosten 2 Motor IGARASHI DC Kleinstmotor 2025-02 Conrad Bestell-Nr.: 244414 - V3 3,45 1 H - Brücke 4-Ch-Driver mit Diode, SO-20 SMD Reichelt L 293 DD 2,75 1 Micro-Controller ATmega32 Reichelt ATMEGA32-16PU 3,90 2 Taster Typ Kurzhubtaster Reichelt Bestell-Nr: TASTER 3301 0,11 3 Reflektionslichtschranke Typ CNY 70 Reichelt Bestell-Nr: CNY 70 0,70 1 Diode Typ 4148 Reichelt Bestell-Nr: SMD 1N 4148 0,02 1 Batterieclip Batterieclip für 9-Volt-Block Reichelt Bestell-Nr: CLIP HQ9V-T 0,24 Schaltregler ST Microelectronics L 78 L Spannungsregler Conrad Bestell-Nr.: 156058-62 1 05 0,23 1 Schalter Dip-Schalter, stehend, 4-polig Reichelt NT 04 0,24 1 Schalter Schiebeschalter 1 x Ein/Ein 50 V 0,5 A Conrad Best.-Nr.: 708054-62 0,49 1 SMD-Widerstände Baugröße 1206 SMD 470 Ohm 0,10 2 SMD-Widerstände Baugröße 1206 SMD 8,2k Ohm 0,10 3 SMD-Widerstände Baugröße 1206 SMD 330 Ohm 0,10 1 SMD-Widerstände Baugröße 1206 SMD 4,7k Ohm 0,10 2 SMD-Widerstände Baugröße 1206 SMD 220 Ohm 0,10 2 Kondensatoren Baugröße 1206 SMD 100uF 0,45 1 Entstörkondensatoren AX 100/16 100uF 16V Reichelt B36-630 0,15 1 Entstörkondensatoren AX 220/16 220uF 16V Reichelt B36-541 0,16 3 LED LED 5mm Reichelt Artikel-Nr.: LED 5MM GN 0,06 1 Stiftleiste Stiftleisten 2,54 mm, 2X02, gerade Reichelt MPE 087-2-004 0,10 1 9V Block energy Alkaline 9 V Block-Batterie Conrad Best.-Nr.: 658014-62 3,50 4 Messpunkte Lötnägel 1mm, versilbert Reihelt RTM 1-100 0,01 Bungard Platinen-Basismaterial Cu- Grundplatine Conrad Best.-Nr.: 523798-62 0,25 Auflage 5,19 O-Ring: Innendurchmesser 20mm Dicke: Reifen 4 2mm BB-608-A500-10-ES (Kunststofflager Räder Kugellager 2 von IGUS) 1 Achse z.b. 8mm-Alu-Rohr aus dem Baumarkt Isolierte Drähte für den 4 Anschluss der Motoren Gesamt: 24,32 Stefan Boneberg Seite 26 von 65

4.2 Schaltplan Korsel mit ATmega32 Stefan Boneberg Seite 27 von 65

4.3 Platine des Korsels mit ATmega32 Stefan Boneberg Seite 28 von 65

4.4 Programmieren mit einem JTAGICE mkii Programmer Der AVR JATAGICE mkii Programmer kostet ca. 300 und ist damit ca. 6 mal so teuer wie der ISP Programmer von AVR. Diese Kosten sind allerdings gerechtfertigt - mit ihm hat man die Option direkt in den Microcontroller hineinzuschauen. Man kann den Mikrocontroller anhalten und alle Variablen auslesen und hat dadurch die Möglichkeit ein umfangreiches Debugging durchzuführen. Dazu benötigt der Mikrocontroller allerdings auch eine JTAG-Schnittstelle. Einen JTAG-Anschluss haben z. B. ATmega128, 64, 323, 32, 16, 162 und noch viele weitere. Auch kann man breakpionts setzen und dadurch gezielt bestimmte Teile eines Programms beobachten. Abbildung 10 JTAGICE mkii Mit diesem schon bekannten AVR-Studio mit WINAVR kann man auch über den JTAG- Programmer programmieren. Zusätzlich kann man Debugging betreiben und dadurch Entwicklungszeit sparen. JTAGICE mkii Programmer JATG-Schnittstelle USB-Anschluss (reicht um zu programmieren und zu debuggen) Abbildung 11 JTAG Programmiergerät Stefan Boneberg Seite 29 von 65

4.4.1 Einstellungen im AVR-Studio um mit JTAGICE zu debuggen Abbildung 12 Debug Als erstes kann man über Debug -> Select Platform and Device unseren JTAG-Programmer und den Mikrocontroller auswählen. Abbildung 13 JTAG platform Standardmäßig ist der AVR-Simulator ausgewählt, dieser führt eine Simulation durch, liefert aber nicht die echten Werte des Mikrocontrollers. Stefan Boneberg Seite 30 von 65

Als nächstes kann man den Compiler richtig einstellen - das können wir über Project -> Konfiguration Options machen. Abbildung 14 Configuration Options Zur Auswahl gibt es im AVR-Studio 4 Optimierungsstufen und zwar O0, -O1, -O2, -O3, -Os. Die Stufe Os ist standardmäßig eingestellt. Der Compiler berücksichtigt hierbei den Aufbau des verwendeten Mikrocontrollers und erstellt danach ein darauf optimiertes Programm. Die Optimierungsstufe löscht hierbei alle Befehle, die nicht mit einem Ein- oder Ausgang direkt oder indirekt zusammenhängen und kann dadurch ein Programm erstellen das ca. 5 mal kleiner ist als ein Programm ohne Optimierungsstufe. Leider kann man diese Optimierungsstufe für den Debugmodus nicht benützen, da der Debugger die Variablen nicht mehr findet und immer eine 0 anzeigt. Man muss die Einstellung O0 verwenden. Der Compiler übersetzt das C-Programm jetzt quasi 1 zu 1. Abbildung 15 Compiler Optimierung Stefan Boneberg Seite 31 von 65

Nach diesen Einstellungen können wir den Mikrocontroller flaschen. Beim ISP-Programmer hat man dies durchgeführt, indem man das.hex File auf den Mikrocontroller geladen hat. Meistens funktioniert das beim JTAG-Programmer auch. Manchmal zeigt er aber mit dem.hex File nicht alle Variablen an. ATMEL sagt deshalb, dass es besser ist das.elf File zu flaschen - es enthält mehr Informationen über die Variablen. Abbildung 16.elf File Wenn man das Programm auf den Mikrocontroller geschrieben hat, schließt man das Fenster und kann über den Play( ) Button das Debugging starten. Im jetzigen Zustand ist der Mikrocontroller gestoppt. Man kann ihn über den Run( )Button starten. Wenn man jetzt den Pause( ) Button betätigt, kann man die Variablen anzeigen lassen. Abbildung 17 Variablen Stefan Boneberg Seite 32 von 65

4.5 Die Fuses des Mikrocontrollers Über die Fuses kann man die Geschwindigkeit des Mikrocontrollers einstellen. Aber Achtung, stellt man auf einen externen CK, dann benötigt man auch einen externen CK. Hat man keinen, kann der Mikrocontroller auch nicht mehr zurückgesetzt werden - d.h. er ist nicht mehr funktionsfähig! Außerdem kann man hier JTAGEN ein- und ausschalten. Um neue Einstellungen vorzunehmen, gehen wir auf den Button AVR und dann auf Fuses. Der Mikrocontroller muss angeschlossen sein. Jetzt auf Read um den momentanen Zustand abzufragen. JTAGEN muss aktiviert sein Einstellen der Prozessor-Geschwindigkeit (int.) Abbildung 18 Fuses ATmega32 Stefan Boneberg Seite 33 von 65

4.6 Das Programm des ATmega 32 mit drei Reflektionslichtschranken 4.6.1 Implementieren der Bibliotheken //**************************Implementieren der Bibliotheken******************* #include <avr/io.h> #define F_CPU 4000000UL #include <stdint.h> 4.6.2 Initialisieren der Variablen //**************************************************************************** //Initialisieren der Variablen //**************************************************************************** int Sensor_rechts_1 = 0; // Analogwert int Sensor_mitte_2 = 0; // Analogwert int Sensor_links_3 = 0; // Analogwert int Sensoren = 0; // Analogwert int Batterie_Spannung = 0; // Berechnet über einen Spannungsteiler die Batteriespannung int Batterie_PWM1 = 0; // Wird vom PWM Signal abgezogen Motor links int Batterie_PWM2 = 0; // Wird vom PWM Signal abgezogen Motor rechts int motorr = 0; // Endgültiger Wert der auf Motor_rechts geschrieben wird int motorl = 0; // Endgültiger Wert der auf Motor_links geschrieben wird int x = 0; int y = 0; int r = 0; int l = 0; int KP = 0; int KI = 0; int KD = 0; int e = 0; int esum = 0; int a = 0; int ealt = 0; // Motor PWM Berechnung // Motor PWM Berechnung // Motor PWM Berechnung // Motor PWM Berechnung // Proportionaler Wert der Regelung (P Anteil) // Integralwert der Regelung (I Anteil) // Differentialwert der Regelung (D Anteil) // Regeldifferenz // auf Summation der Regelabweichung // Regelabweichung // Letzter berechneter Wert #define Motor_links OCR1B // OCR1B heißt jetzt Motor_links #define Motor_rechts OCR1A // OCR1A heißt jetzt Motor_rechts Stefan Boneberg Seite 34 von 65

4.6.3 IO-Ports initialisieren //************************************************************************* // IO-Ports initialisieren //************************************************************************* void init_io(void) { DDRD = 0x00; PORTD = 0xFF; // Port D als Eingang (hex. Schreibweise geht auch) // Port D als pull-up (hex. Schreibweise geht auch) PORTC = (1 << PC6); PORTB = (1 << PB4); DDRC &= ~(1 << PC6); DDRB &= ~(1 << PB4); DDRB =(1 << PB1); DDRB =(1 << PB2); DDRB =(1 << PB0); // PC6 als Eingang mit pull-up // PB4 als Eingang mit pull-up // PC6 als Eingang // PB4 als Eingang // PB1 als Ausgang // PB2 als Ausgang // PB0 als Ausgang DDRA &= ~(1 << PA0); PORTA = (1 << PA3); DDRA &= ~(1 << PA3); PORTA = (1 << PA4); DDRA &= ~(1 << PA4); PORTA = (1 << PA5); DDRA &= ~(1 << PA5); // PA0 als Eingang für AD Messung (ADC0 Spannungsteiler Batteriespannung) // PA3 als Eingang mit pull-up für AD-Messung (ADC3 Sensor in Fahrtrichtung rechts) // PA3 als Eingang // PA4 als Eingang mit pull-up für AD-Messung (ADC4, Sensormitte) // PA4 als Eingang // PA5 als Eingang mit pull-up für AD-Messung (ADC5, Sensor in Fahrtrichtung links) // PA5 als Eingang PORTB &= ~(1 << PB1); PORTB &= ~(1 << PB2); PORTB =(1 << PB0); // auf low LED ausschalten // auf low LED ausschalten // Sensoren LED s einschalten //*****************************Ansteuerung H-Brücke*********************************** DDRB =(1 << PA1); DDRB =(1 << PA2); DDRB =(1 << PA6); DDRB =(1 << PA7); PORTA &= ~(1 << PA2); PORTA &= ~(1 << PA7); PORTA =(1 << PA1); PORTA =(1 << PA6); // PA1 als Ausgang // PA2 als Ausgang // PA6 als Ausgang // PA7 als Ausgang // auf low (für Vorwärtsfahrt als Starteinstellung) // auf low (für Vorwärtsfahrt als Starteinstellung) // auf high (für Vorwärtsfahrt als Starteinstellung) // auf high (für Vorwärtsfahrt als Starteinstellung) Stefan Boneberg Seite 35 von 65

4.6.4 ADC-Wandler initialisieren //************************************************************************************ // ADC-Wandler einstellen //************************************************************************************ void ADC_Init(void) { ADMUX = 0b01000000; // Verwenden der internen Referenzspannung mit externem Kondensator Datenblatt S.212 // genauer ist eine externe Referenzspannung (ist hier aber nicht so wichtig) ADCSRA = 0b10000001; // Einstellen der ADC-Wandlung Teilungsfaktor 2 (höchste Geschwindigkeit der AD-Wandlung) SFIOR = 0b00000000; // Single Conversion mode (führt nur dann eine Konvertierung aus, wenn ADSC auf 1 gesetzt wird) ADCSRA =(1 << ADSC); while (!ADCSRA & (1<<ADSC)) { Sensor_links_3 = ADC; // Starten einer Konvertierung // auf Abschluss der Konvertierung warten // beim Auslesen von ADC wird das Bit ADSC wieder auf null gesetzt, deshalb hier auslesen um den Wert zu löschen 4.6.5 PWM initialisieren //************************************************************************************ // PWM initialisieren //************************************************************************************ void pwm (void) { DDRD = (1<<PD4); DDRD = (1<<PD5); PORTD &= ~(1 << PA4); PORTD &= ~(1 << PA5); // auf Ausgang setzen für PWM // auf Ausgang setzen für PWM // auf low // auf low TCCR1A = 0b10100001; TCCR1B = 0b00001010; TCNT1 = 255; // Einstellen der PWM A und B mit Modusauswahl // Teiler von 8 einstellen, zu kleiner Teiler bringt zu viele HF Störungen auf die restliche Elektronik // Anfangswert setzten (dort beginnt er beim ersten Mal zu zählen) OCR1A = 100; OCR1B = 100; // Register für den Vergleichswert (dieses Register wird später von der eigentlichen Regelung immer überschrieben) // Register für den Vergleichswert (dieses Register wird später von der eigentlichen Regelung immer überschrieben) Stefan Boneberg Seite 36 von 65

4.6.6 Hauptprogramm (MAIN) //************************* MAIN ***************************************************** int main (void) { init_io(); ADC_Init(); pwm(); // IOs konfigurieren // Analog-Digitalwandler konfigurieren // PWM initialisieren while (1) // Start Endlosschleife { 4.6.6.1 Sensoren auslesen //************************************************************************************ // Sensoren auslesen //************************************************************************************ //*********************** Sensor 1 *************************************************** while (ADMUX!=67) { // Abfrage auf port ADC3 ADMUX = 0b01000011; // Warten bis ADMUX eingerastet ist ADCSRA =(1 << ADSC); // Starten einer Konvertierung while (ADCSRA & (1<<ADSC)) { // auf Abschluss der Konvertierung warten Sensor_rechts_1 = ADC; // Wert von ADC in den Speicher Sensor_mitte_2 schreiben //********************** Sensor 2 **************************************************** while (ADMUX!=68) { // Abfrage auf port ADC4 ADMUX = 0b01000100; // Warten bis ADMUX eingerastet ist ADCSRA =(1 << ADSC); // Starten einer Konvertierung while (ADCSRA & (1<<ADSC)) { // auf Abschluss der Konvertierung warten Sensor_mitte_2 = ADC; // Wert von ADC in den Speicher Sensor_mitte_2 schreiben //********************* Sensor 3 **************************************************** while (ADMUX!=69) { // Abfrage auf port ADC5 ADMUX = 0b01000101; // Warten bis ADMUX eingerastet ist ADCSRA =(1 << ADSC); // Starten einer Konvertierung while (ADCSRA & (1<<ADSC)) { // auf Abschluss der Konvertierung warten Sensor_links_3 = ADC; // Wert von ADC in den Speicher Sensor_mitte_2 schreiben Sensoren = Sensor_rechts_1+Sensor_mitte_2+Sensor_links_3; // Gesamtwert der Sensoren berechnen Stefan Boneberg Seite 37 von 65

if ((Sensoren>3069) ) { Sensoren=3069; // die Sensorwerte dürfen nie einen größeren Wert als 3069 haben if ((Sensoren<0) ) { Sensoren=0; // die Sensorwerte dürfen keinen kleineren Wert als 0 haben 4.6.6.2 An gleich der Batteriespannung //************************************************************************************ // Abfrage der Batteriespannung //************************************************************************************ while (ADMUX!=64) { // Abfrage auf port ADC0 ADMUX = 0b01000000; // Warten bis ADMUX eingerastet ist ADCSRA =(1 << ADSC); // Starten einer Konvertierung while (ADCSRA & (1<<ADSC)) { // auf Abschluss der Konvertierung warten Batterie_Spannung = ADC; // den Wert von ADC in Batteriespannung speichern // Da die Abnahme der Batteriespannung nicht linear ist, ist es einfacher den Verlauf der Batteriespannung über mehrere if-bedingungen zu realisieren. Die Werte wurden durch Messungen mit verschiedenen Batterien und Motoren ermittelt if(batterie_spannung<=585){ Batterie_PWM1=0; Batterie_PWM2=0; PORTB =(1 << PB1); else{ //Batterie ist fast leer PORTB &= ~(1 << PB1); if((batterie_spannung>585)&&(batterie_spannung<590)){ Batterie_PWM1=0; Batterie_PWM2=0; if((batterie_spannung>=590)&&(batterie_spannung<695)){ Batterie_PWM1=2; Batterie_PWM2=2; if((batterie_spannung>=595)&&(batterie_spannung<600)){ Batterie_PWM1=3; Batterie_PWM2=3; if((batterie_spannung>=600)&&(batterie_spannung<605)){ Batterie_PWM1=5; Batterie_PWM2=5; if((batterie_spannung>=605)&&(batterie_spannung<610)){ Batterie_PWM1=7; Batterie_PWM2=7; if((batterie_spannung>=610)&&(batterie_spannung<615)){ // PB1 auf high = LED an (zeigt an wenn die Batterie fast leer ist) // PB1 auf low = LED aus Stefan Boneberg Seite 38 von 65

Stefan Boneberg Seite 39 von 65 Batterie_PWM1=10; Batterie_PWM2=10; if((batterie_spannung>=615)&&(batterie_spannung<620)){ Batterie_PWM1=14; Batterie_PWM2=14; if((batterie_spannung>=620)&&(batterie_spannung<625)){ Batterie_PWM1=18; Batterie_PWM2=18; if((batterie_spannung>=625)&&(batterie_spannung<635)){ Batterie_PWM1=25; Batterie_PWM2=25; if((batterie_spannung>=635)&&(batterie_spannung<640)){ Batterie_PWM1=31; Batterie_PWM2=31; if((batterie_spannung>=640)&&(batterie_spannung<650)){ Batterie_PWM1=36; Batterie_PWM2=36; if((batterie_spannung>=650)&&(batterie_spannung<660)){ Batterie_PWM1=39; Batterie_PWM2=39; if((batterie_spannung>=660)&&(batterie_spannung<670)){ Batterie_PWM1=42; Batterie_PWM2=42; if((batterie_spannung>=670)&&(batterie_spannung<680)){ Batterie_PWM1=47; Batterie_PWM2=47; if((batterie_spannung>=680)&&(batterie_spannung<690)){ Batterie_PWM1=52; Batterie_PWM2=52; if((batterie_spannung>=690)&&(batterie_spannung<700)){ Batterie_PWM1=62; Batterie_PWM2=62; if((batterie_spannung>=700)&&(batterie_spannung<710)){ Batterie_PWM1=70; Batterie_PWM2=70; if((batterie_spannung>=710)&&(batterie_spannung<720)){ Batterie_PWM1=75; Batterie_PWM2=75; if((batterie_spannung>=720)&&(batterie_spannung<730)){ Batterie_PWM1=81; Batterie_PWM2=81; if((batterie_spannung>=730)&&(batterie_spannung<740)){ Batterie_PWM1=85; Batterie_PWM2=85; if((batterie_spannung>=740)){ Batterie_PWM1=90; Batterie_PWM2=90;

4.6.6.3 Einstellen des Differentialanteils //************************************Einstellen des D-Anteils************************ if ((PIND & 0b11001000) == 0b11001000) { // wenn (PDIND3 = 1 und PIND6 = 1 und PIND7 = 1) dann gehe in if KD=0; if ((PIND & 0b11001000) == 0b11000000) { // wenn (PDIND3 = 0 und PIND6 = 1 und PIND7 = 1) dann gehe in if KD=30; if ((PIND & 0b11001000) == 0b01001000) { // wenn (PDIND3 = 1 und PIND6 = 1 und PIND7 = 0) dann gehe in if KD=60; if ((PIND & 0b11001000) == 0b01000000) { // wenn (PDIND3 = 0 und PIND6 = 1 und PIND7 = 0) dann gehe in if KD=90; if ((PIND & 0b11001000) == 0b10001000) { // wenn (PDIND3 = 1 und PIND6 = 0 und PIND7 = 1) dann gehe in if KD=120; if ((PIND & 0b11001000) == 0b10000000) { // wenn (PDIND3 = 0 und PIND6 = 0 und PIND7 = 1) dann gehe in if KD=150; if ((PIND & 0b11001000) == 0b00001000) { // wenn (PDIND3 = 1 und PIND6 = 0 und PIND7 = 0) dann gehe in if KD=180; if ((PIND & 0b11001000) == 0b00000000) { // wenn (PDIND3 = 0 und PIND6 = 0 und PIND7 = 0) dann gehe in if KD=250; // Mit dem Schiebeschalter an PIND kann man jetzt den Wert von KD verändern 4.6.6.4 Der PID Regler //******************************Regler mit PID**************************************** KP = 2; KI = 0; // Die Strecke an sich hat bereits einen I-Anteil, d.h. mit zusätzlichem I ist sie instabil, KD wird über die Schiebeschalter eingestellt x = Sensoren; y = 3000-x; // x+y=3000 d.h. wenn x kleiner wird, wird y größer, wir benötigen x und y für die Fahrt nach rechts und nach links if(x>1500){ // Korsel Bewegung nach rechts (hier y) l = 255; // Linker Motor volle Leistung e = 1500-y; esum = esum + e; // Regeldifferenz // Integration I-Anteil a=(kp*e)+(ki*1*esum)+((kd/1)*(e-ealt)); //Regler ealt = e; // Differential D-Anteil Stefan Boneberg Seite 40 von 65

r=255-(a/6); // Berechnen der Motor-PWM des rechten Motors if(r<0){ PORTA &= ~(1 << PA1); PORTA =(1 << PA2); PORTB =(1 << PB2); // auf high (für Rückwärtsfahrt) Motor rechts // auf low (für Rückwärtsfahrt) Motor rechts // PA6 auf high = LED an else{ r=r*(-1); PORTA &= ~(1 << PA2); PORTA =(1 << PA1); PORTB &= ~(1 << PB2); // PWM kann nur positive Werte verarbeiten // auf low (für Vorwärtsfahrt) Motor rechts // auf high (für Vorwärtsfahrt) Motor rechts // PA6 auf low = LED aus if(x<=1500){ // Korsel Bewegung nach links (hier x) r = 255; // Motor rechts volle Leistung e = 1500-x; esum = esum + e; // Regeldifferenz // Integration I-Anteil a=(kp*e)+(ki*1*esum)+((kd/1)*(e-ealt)); //Regler ealt = e; l=255-(a/6); // Differential D-Anteil // Berechnen der Motor-PWM des linken Motors if(l<0){ PORTA &= ~(1 << PA6); PORTA =(1 << PA7); PORTB =(1 << PB2); // auf high (für Rückwärtsfahrt) Motor links // auf low (für Rückwärtsfahrt) Motor links // PA6 auf high = LED an else{ l = l * (-1); // PWM kann nur positive Werte verarbeiten PORTA &= ~(1 << PA7); // auf low (für Vorwärtsfahrt) Motor links PORTA =(1 << PA6); // auf high (für Vorwärtsfahrt) Motor links PORTB &= ~(1 << PB2); // PA6 auf low = LED aus if ((r>255) ) { r=255; // die PWM der Motoren darf keinen größeren Wert als 255 bekommen if ((l>255) ) { l=255; // die PWM der Motoren darf keinen größeren Wert als 255 bekommen Stefan Boneberg Seite 41 von 65

if(pind & (1 << PIND2)){ // mit Einbeziehung der Batteriespannung Schiebeschalter 1 eingeschaltet motorl = l-batterie_pwm1; motorr = r-batterie_pwm2; else{ // hier fährt der Korsel immer mit voller Leistung (ohne eine Abschwächung durch die Batteriespannung) motorl = l; motorr = r; if ((motorr<0) ) { motorr=0; if ((motorl<0) ) { motorl=0; // die PWM der Motoren darf keinen kleineren Wert als 0 bekommen // die PWM der Motoren darf keinen kleineren Wert als 0 bekommen Motor_links = motorl; // hier wird der endgültige Wert der PWM in das Register OCR1B geschrieben Motor_rechts = motorr; // hier wird der endgültige Wert der PWM in das Register OCR1A geschrieben // while_ende return (0); Stefan Boneberg Seite 42 von 65

4.7 Die Sensoren des Korsels Hier wird eine Reflektionslichtschranke (CNY70) mit einem Transistorausgang verwendet. Funktionsweise: Abbildung 19 Funktionsweise Sensor (VISHAY) Eine LED strahlt infrarotes Licht aus. Je nach der Farbe des bestrahlten Mediums wird mehr (weiß) oder weniger (schwarz) reflektiert. Dadurch schaltet der Transistor mehr oder weniger durch und man kann diese Spannung mit unserem AD-Wandler messen. Abbildung 20 Sensoren Kegel LED In der Abbildung Sensoren Kegel LED ist die Streuung des infraroten Lichts erkennbar. Dieses Licht ist für das menschliche Auge nicht sichtbar, wir können es aber mit Hilfe einer Digitalkamera sichtbar machen. Stefan Boneberg Seite 43 von 65

Der Abstand der Sensoren zum Untergrund beträgt 3,5 mm. Abbildung 21 Abstand Sensoren Man hat also einen Kollektorstrom von ca. 2,8 ma (dieser Wert an sich bringt keine große Aussage, da es immer noch sehr auf das bestrahlte Medium ankommt, aber man weiß, dass der Sensor in diesem Bereich gut arbeiten kann). Der Abstand zwischen den Sensoren beträgt 9 mm. Abbildung 22 CNY 70 (VISHAY) Abbildung 23 Abstand Sensoren zueinander 3,5 mm links und rechts der Sensoren beginnen die Sensoren mit dem Erkennen eines schwarzen / weißen Untergrunds, ca. 2 mm also 9 mm-(2*3,5 mm) ist eine tote Zone - in diesem Bereich erkennt der Korsel keine Änderungen. Stefan Boneberg Seite 44 von 65

4.7.1 Grundlegende Funktionsweise unsere Sensoren Auf weißem Untergrund wird der Transistor durchgesteuert und zieht den Eingang (pull-up) des Mikrocontrollers von 5 V auf ca. 0,2 V herunter. Unsere Analog- / Digitalwandlung liefert daher einen Wert von. Kommt man mit dem Sensor auf schwarzen Untergrund, wird der Transistor nur sehr gering durchgesteuert und die Spannung geht auf ca. 4,5 V. Über die Analog- / Digitalwandlung erhält man einen Wert von. Dies sind nur sehr ungenaue Werte, da die verwendeten Reflektionslichtschranken eine große Fertigungstoleranz haben (hat auf diese Steuerung keine große Einwirkung). Über das Programm des Mikrocontrollers werden die Werte der drei Reflektionslichtschranken zusammenaddiert und man erhält einen Wert von ca. 3000 für schwarzen Untergrund und ca. 160 für weißen Untergrund. Mit den drei Reflektionslichtschranken hat man über eine Strecke von ca. 43 mm (was ungefähr der Bahnbreite entspricht) einen relativ kontinuierlichen Wert. Stefan Boneberg Seite 45 von 65

4.8 Einstellungen des Analog-/Digital-Wandlers (ATmega32) Allgemeines zum AD-Wandler siehe Kapitel Konfiguration der Analog- / Digitalwandlung (AD Wandler) Auch der ATmega32 hat einen echten AD-Wandler, den man jetzt in diesem Programm auf die verschiedenen Eingänge (drei Sensoren und Batteriespannungsmessung) schalten muss. 4.8.1 Die Einstellung des Registers ADMUX = 0b01000000 (ATMEL, Datenbalatt ATmega32) 01 = an der Stelle 7 und 6 (REFS1, REFS0) steht eine 01. Hiermit kann man die Vergleichsquelle einstellen. Hier wurde als Referenzspannung AVCC gewählt. Um einen genaueren Wert zu bekommen muss an diesen Pin ein 100nF-Kondensator angeschlossen werden. AVCC ist an 5 V angeschlossen, das ist jetzt die Obergrenze, d.h. 5 V = 1024 (10Bit Konvertierung). 0 = an der Stelle 5 (ADLAR) steht eine 0, das bedeutet, dass lsb ist bei dem Register ADC (im ADC Register steht das Ergebnis der AD-Umwandlung) auf der rechten Seite. 00000 = an den Stellen 0,1,2,3 und 4 (MUX0 bis MUX4) ist eine 00000, hier kann man den zu konvertierenden Eingang festlegen. In diesem Programm wird der zu konvertierende Eingang vor jeder AD- Wandlung neu eingestellt. Stefan Boneberg Seite 46 von 65

4.8.2 Die Einstellung des Registers ADCSRA = 0b10000001 (ATMEL, Datenbalatt ATmega32) 1 = an der Stelle 7 (ADEN) steht eine 1, hiermit aktivieren wir den AD-Wandler. 0 = an der Stelle 6 (ADSC) steht eine 0. Da der AD-Wandler im Single Conversion mode arbeitet, kann man ihn starten, indem man hier eine 1 hineinschreibt. 0 = an der Stelle 5 (ADATE) steht eine 0. Hier kann man die Auto Triggerungsfunktion ausschalten. Indem man eine 0 an diese Stelle schreiben ist sie eingeschaltet. 0 = an der Stelle 4 (ADIF) steht eine 0. Hier kann man Interrupts abfragen. Immer wenn eine Konvertierung vollständig ist, wird ADIF auf 1 gesetzt (in diesem Programm ohne Bedeutung). 0 = an der Stelle 3 (ADIE) steht eine 0. Hier kann man die Interrupt-Funktion einschalten. In diesem Fall ist die Interrupt-Funktion ausgeschaltet. 001 = an den Stellen 0,1,2 (ADPS2, ADPS1, ADPS0) steht eine 001. Hiermit kann man die Geschwindigkeit des AD-Wandlers einstellen. Hier ein Teiler von 2, d.h.. Hier wurde die maximale Geschwindigkeit gewählt, da dieses Programm immer darauf wartet dass eine Konvertierung abgeschlossen ist. Man würden es also stark verlangsamen wenn man einen höheren Teilungsfaktor einstellen würde. 4.8. 3 Die Einstellung des Registers SFIOR = 0b00000000 000 = an den Stellen 7,6,5 (ADTS2, ADTS1,ADTS0) steht eine 000. Hier kann man die Trigger-Quelle einstellen (hier Free running Mode), in diesem Programm ohne Bedeutung. 00000 = an den Stellen 4,3,2,1,0 (-, ACME, PUD, PSR2, PSR10) steht eine 00000. Diese sind für dieses Programm ohne Bedeutung, ATMEL empfiehlt aber hier 0 in das Register zu schreiben, damit das Programm für spätere Mikrocontroller kompatibel bleibt. Stefan Boneberg Seite 47 von 65

Mit dem Einstellen der Register ADMUX (ADC Multiplexer Selection Register), ADCSRA (ADC Control and Status Register A), SFIOR (Special Function I/O Register) hat man einen AD-Wandler, der jedes Mal wenn man eine 1 in das Bit ADCS geschrieben habt eine sehr schnelle Konvertierung des analogen Wertes in einen digitalen Wert startet. Außerdem kann man mit ADMUX einen Eingang auswählen, der konvertiert werden soll. Der AD-Wandler vergleicht unseren Wert immer mit 5 V und führt folgende Rechnung aus: 4.9 Batterie Spannungs-Berechnung Um einen Wert der Batteriespannung zu erhalten, muss man einen kleinen Trick anwenden. Die Batteriespannung schwankt zwischen 6,5 V und 9,8 V. Der maximal Wert von diesem AD-Wandler ist aber 5 V. Man benötigt also einen Spannungsteiler. [ ] Abbildung 24 Batteriespannung Man hat sich für einen gesamten Widerstand von 13,8 kohm entschieden - der Strom beträgt dann. Dieser Strom ist groß genug, um Störungen, die durch HF ein Kopplungen entstehen, zu vernachlässigen und klein genug, um die Batterie nicht zusätzlich zu entladen. Auf den 9 V der Batteriespannung sind durch die Motoren viele Störsignale und es ist für den Mikrocontroller sehr schwierig eine AD-Wandlung durchzuführen. Der Mikrocontroller benötigt eine kurze Zeit, in der die Spannung während der AD-Wandlung konstant ist (sampel und hold Schaltung), dafür hat er einen internen Kondensator. Wenn die Spannung aber zu sehr schwankt, reicht der interne Kondensator nicht mehr und man muss einen externen dazuschalten, der die Schwankungen etwas glättet. Dies wurde hier mit dem Kondensator C6 realisiert. Jetzt kann man über die Spannungsteiler-Formel: die Spannung am Pin6 ausrechnen, z.b. für Ubatt = 9 V, U an Pin6 = 3,65 V. Unser AD-Wandler berechnet dann einen Wert von. So kann man dann die Bedingungen für die if-anweisungen festlegen. Stefan Boneberg Seite 48 von 65

4.10 Einstellungen der PWM (ATmeaga32) Die grundsätzliche Funktionsweise der PWM ist in dem Kapitel Konfiguration der PWM der Motoren nachzulesen. Bei diesem Mikrocontroller (ATmega32) hat man sich für den 16 Bit Timer/Zähler 1 entschieden. So wie bereits beim ATtiny26 kann man mit diesem beide PWM-Ausgänge der Motoren ansteuern. 4.10.1 Die Einstellung des Registers TCCR1A =0b10100001 (ATMEL, Datenbalatt ATmega32) 10 = an den Stellen 7 und 6 (COM1A1, COM1A0) steht eine 10. Diese Einstellung bewirkt, dass die Ausgänge OC1A/OC1B bei den Werten von den Registern OCR1A/OCR1B auf low geschaltet werden. 10 = an den Stellen 5 und 4 (COM1B1, COM1B0) steht eine 10. Diese Einstellung bewirkt, dass die Ausgänge am Ende des Zählregisters (255) wieder auf high geschaltet werden. 00 = an den Stellen 3 und 2 (FOC1A, FOC1B) steht eine 00. Diese Bits sind im PWM-Modus ohne Bedeutung 01 = an den Stellen 1 und 0 (WGM11, WGM10) steht eine 01. Hier kann man einstellen, ob die PWM mit 8, 9 oder 10 Bit arbeitet. Die Einstellung hier ist 8 Bit. (Für diese PWM sind 255 Schritte mehr als ausreichend.) Stefan Boneberg Seite 49 von 65

4.10.2 Die Einstellungen des Registers TCCR1B =0b00001010 (ATMEL, Datenbalatt ATmega32) 0 = an der Stelle 7 (ICNC1) steht eine 0. Hier kann man eine Filterung einbauen. Für diesen Modus ohne Bedeutung. 0 = an der Stelle 6 (ICES1) steht eine 0. Hier kann eingestellt werden, wann der Zähler zählen soll (bei steigender oder fallender Flanke). Die Einstellung hier zählt bei einer negativen Flanke. 01 = an den Stellen 4 und 3 (WGM13, WGM12) steht eine 01. Hier kann man die Arbeitsweise des Timers einstellen. Die Einstellung hier ist fast PWM. 010 = an den Stellen 2, 1 und 0 (CS12, CS11, CS10) steht eine 010. Hier kann man den Teilungsfaktor einstellen, d.h. mit welcher Frequenz die PWM arbeiten soll. Die Einstellung hier hat einen Teilungsfaktor von 8, d.h.. Man erhält eine PWM mit einer Frequenz von 0,5 khz. Durch diese Einstellungen hat man einen PWM, der kontinuierlich arbeitet. Über die Register OCR1A und OCR1B kann man die Einschalt- und Pausendauer festlegen. Die Arbeitsweise der Register OCR1A und OCR1B, sowie die Gründe für die Auswahl der PWM- Frequenz ist in dem Kapitel Konfiguration der PWM der Motoren nachzulesen. Stefan Boneberg Seite 50 von 65

4.11 Grundlegende Funktion der Bauteile, Korsel mit ATmega32 (drei Sensoren) Der ATmega32 ist ein 8bit Microcontroller aus der Atmelreihe. Er hat einen 32k Bytes Flash-Speicher und was hier sehr wichtig war, eine JTAG-Schnittstelle. Man kann ihn über ISP oder JTAG programmieren. Ein Debugging ist mit einem JTAGICE mkii Programmer auch möglich. Um sicher zu arbeiten benötigt er eine Spannung von 4,5 V bis 5,5 V. Seine maximale Taktfrequenz beträgt 16 MHz. Man betreibt ihn mit 1 MHz. Die Energieversorgung wird über einen günstigen Nickel-Metall-Hydrid-Akkumulator mit einer Spannung von 8,4 V realisiert. Dir ATmega32 steuert zwei H-Brücken (L 293 DD, in diesem Bauteil sind beide H-Brücken enthalten), welche dann die Motoren an- und abschalten. Über die H-Brücke kann man die Motoren vorwärts und rückwärts laufen lassen sowie bei leichtem Rückwärtslauf auch abbremsen. Die Freilaufdioden sind in der H-Brücke schon enthalten. Für die Energieversorgung der Motoren wird der 9 V-Block direkt angeschlossen. Zur Stabilisierung und Entstörung der Spannung ist ein Kondensator mit 220 uf vorgesehen. Zum Entstören ist zusätzlich noch ein 100 nf-kondensator verbaut. Die Diode, welche in der Nähe der Anschlussdrähte des Akkumulators angebracht ist, erfüllt zwei Aufgaben, zum einen den Verpolungsschutz und zum anderen eine Art Sicherung. Der Maximaldauerstrom beträgt 150 ma. Bei einem Kurzschluss ist die Diode das Bauelement, welches als erstes zerstört wird. Da die Diode sehr günstig ist (0,02 ), ist das auch gut so. Auch das Auswechseln der Diode geht sehr schnell. Die Spannung für die Reflektionslichtschranken sowie für den Mikrocontroller wird über den L78L05 (Festspannungsregler) bereitgestellt - er liefert eine konstante Ausgangsspannung von 5 V und einen Strom von 0,1 A. Der Kondensator mit 100 uf und der Kondensator mit 100 nf glätten diese und sorgen dafür, dass die Spannung auch beim Einkoppeln von Störsignalen durch die Motoren konstant bleibt und der Mikrocontroller sicher arbeiten kann. Am Heck des Korsels ist ein Schalter montiert, mit dem man ihn komplett spannungslos schalten kann. Eine LED, die links daneben angebracht ist, zeigt an ob der Korsel Spannung hat oder nicht. Die Kurzhubtaster sind für diverse Abänderungen in der Zukunft gedacht. Über die Dip-Schalter können wir den Differentialanteil der Regelung einstellen. Die linke LED zeigt an, wenn der Akkumulator fast leer ist (sie leuchtet dann auf). Die rechte LED leuchtet wenn einer der Motoren abgebremst wird. Stefan Boneberg Seite 51 von 65

4.12 Vor- und Nachteile eines Korsels mit einem ATmega 32 Nachteile: - Der Aufbau ist etwas komplizierter (mehr Bauteile), mit etwas Übung jedoch gut machbar - Etwas schwieriger zu programmieren - Etwas höhere Kosten des Projekts (ohne Programmer ca. 25 pro Korsel) - Kürzere Laufzeit von ca. 0,5 h (Akku mit 8,4 V und 200 ma) - Das größere Programm benötigt länger um alle Befehle abzuarbeiten. Ein Programmdurchlauf benötigt 2,5 ms, mit einer maximalen Geschwindigkeit von 1,2 m/s fährt der Korsel ca. 3 mm, bevor er die nächste Messung mit Umwandlung und die damit verbundene Änderung der PWM durchführt. Vorteile: Fazit: - Mit dem großen internen Speicher können auch etwas aufwendigere Programme geschrieben werden. - Mit dem größeren Programmspeicher kann ein Differentialregler implementiert werden, der den Integralanteil kompensiert und dadurch ein genaueres Fahren ermöglicht - Der ATmega32 ermöglicht mit seiner JTAG-Schnittstelle ein on chip debugging. Daher kann man jetzt die Sensorwerte exakt auslesen und die Entwicklungszeit verkürzt sich stark. - Mit den drei Reflektionslichtschranken kann man größere Regelabweichungen erkennen und dadurch besser regeln - Die Spannung der günstigen Akkumulatoren schwankt stark (je nach Ladezustand), deshalb schwankt auch die Motorleistung stark. Eine Lösung ist das Schreiben eines Programmes, welches die Spannungsschwankungen der Batterie kompensiert. Dies ist jetzt mit dem ATmega32 möglich und wurde auch realisiert. - Durch die Mehrzahl an Ein- / Ausgängen kann man zusätzliche DIP-Schalter anbringen und so bestimmte Programme ein- und ausschalten. In diesem Modell kann der Differentialanteil verändert werden. - Für weitere Erweiterungen besitzt er eine UART Schnittstelle. Der Korsel mit einem ATmega32 und drei Reflektionslichtschranken ermöglicht ein schnelleres und exakteres Fahren auf der Kante des vorgegebenen Pfades. Mit der UART-Schnittstelle ist er leicht erweiterbar und für diverse wissenschaftliche Zwecke gut einsetzbar. Für Schüler ist er wegen des komplexen Aufbaues eher weniger geeignet. Stefan Boneberg Seite 52 von 65

5. Simulation des Korsels Eine Simulation des mechanischen Models des Korsels wurde mit Hilfe von Matlab erstellt. In dieser Simulation kann man einen Weg vorgeben, den der Korsel abfährt. Man kann durch das Verändern der Parameter feststellen, ob die Regelabweichung geringer oder größer wird. Diese Simulation wurde von Herrn Prof. Dr.-Ing. Konrad Wöllhaf erstellt, an diese Stelle möchte ich mich nochmals dafür bedanken. 5.1 Vorgehensweise um die Simulation zu starten Um die Simulation auszuführen benötigt man folgende Dateien: - simmod2d1.mdl (Simulik Model) - compute_signal.m (MATLAB M-file) - drow_robot.m (MATLAB M-file) - gen_path.m (MATLAB M-file) - init_sim.m (MATLAB M-file) - next_path.m (MATLAB M-file) - norm_angel.m (MATLAB M-file) - run_pol1.m (MATLAB M-file) - run_pol2.m (MATLAB M-file) - show_result_diff2.m (MATLAB M-file) Als erstes wird die Datei gen_path.m aufgerufen, mit dieser kann man einen Weg festlegen, den der Korsel später abfahren soll. Mit dem Butten Run ( ) kann man das M-file ausführen. Durch Klicken innerhalb des Bereichs +32, -32 (Y-Achse) und +42, -42 (x-achse) wird Schritt für Schritt ein Weg generiert. Durch einen Mausklick außerhalb des Bereichs wird das Programm beendet. Abbildung 25 path Stefan Boneberg Seite 53 von 65

Als nächstes kann man show_result_diff2.m starten. Dieses M-file ruft init_sim.m und simmod2.mdl auf, simmod2.mdl ruft dann compute_signal.m und next_path.m auf. Mit einem Klick auf Run ( show_result.m zeigt das Programm das mit diesen Einstellungen verbundene Ergebnis. ) in Im Graph wird nochmal der gezeichnete Weg dargestellt. Abbildung 26 Graph Abbildung 27 Graph1 Im Graph1 wird der berechnete Weg des Korsels dargestellt. Abbildung 28 Figure 1 In der Abbildung Figur 1 wird der Korsel dargestellt und wie er versucht der Linie zu folgen. In dem M-file show_result gibt es die Variaben kp, kd und v_robot. Mit kp kann man den proportionalen Anteil der Regelung einstellen. Mit kd kann man den Differentialteil der Regelung einstellen. Mit v_robot kann man die Geschwindigkeit des Korsels einstellen. Stefan Boneberg Seite 54 von 65

5.2 Plausibilität der Simulation Abbildung 29 Übertragungsfunktion Die Übertragungsfunktion wurde mit Hilfe des Simulationsmodels erstellt. Bei y2 ist zu erkennen, dass ein s unter dem Bruchstrich steht, daher hat die Strecke in der Simulation ein integrierendes Verhalten. Das trifft schon mal auf die Praxis zu wenn man in diesem Korsel einen reinen P-Regler programmieren, ist dieser stationär genau und das ist nur möglich, wenn die Strecke an sich schon ein I Verhalten mitbringt. Um die Simulation weiter zu testen, hat man die Geschwindigkeit des Korsels Schritt für Schritt erhöht, bis dieser seiner Bahn nicht mehr folgen konnte. Danach wurde ein Differentialanteil in die Regelstrecke implementiert und der Simulationskorsel konnte der Bahn wieder folgen. Dies konnte man auch in der Praxis feststellen - der Differentialanteil stabilisiert den Korsel, die Regelabweichung wird kleiner, die Geschwindigkeit höher und man kann ihn schneller fahren lassen. Auch in der Regelungstechnik ist dies zu erkennen - wird ein Einheitssprung auf eine PI- Übertragungsfunktion gegeben, so benötigt diese länger als ein PID-Glied um den Endwert zu erreichen. Aber Achtung, zu viel D-Anteil (Differentialanteil) führt zu einem Aufschwingen und das System wird instabil. Stefan Boneberg Seite 55 von 65

6. Das digitale Regelsystem (Abtastregelung) Die prinzipielle Arbeitsweise von diesem digitalen Regler: Als erstes muss man feststellen, wie hoch die Regelabweichung ist. Bei diesem Modell wird diese Regelabweichung über die Sensoren erfasst. Jeder Sensor kann einen Wert von 0 bis 1024 ausgeben, da wir drei Sensoren haben ist der theoretisch maximale Wert bei 3072. In der Praxis kann man auch 3000 annehmen. Ist der Sensor auf weiß hat er einen Wert von 0, ist er auf schwarz hat er einen Wert von 1024. Abbildung 30 Sensoren Wert Sensoren = 1200 Wert Sensoren = 1500 Wert Sensoren = 1800 Falls der Sensorenwert unter 1500 liegt, gilt folgende Formel zur Berechnung der Regelabweichung: Regelabweichung = 1500 (Sollwert) Wert der Sensoren Der I-Anteil (den man in diesem Modell nicht benötigt, da die Strecke (der Korsel selbst) bereits einen I-Anteil enthält und ein zusätzlicher Integralanteil das System nur instabil machen würde) kann man folgendermaßen berechnen: Summe der Regelabweichung = Summe der Regelabweichung + Regelabweichung (Aufsummation der Regelabweichung) Die Reglergleichung: Y = Wert der die PWM der Motoren steuert Y = Einstellbarer Wert * Regelabweichung + Einstellbarer Wert * Summe der Regelabweichung + Einstellbarer Wert * (Regelabweichung - Regelabweichung alt) (P) (I) (D) Um den D (Differential)-Anteil zu berechnen, müssen wir die letzte Messung der Regelabweichung mit der jetzigen vergleichen. Das Programm muss also irgendwo diesen letzten Wert der Regelabweichung speichern. Regelabweichung alt = Regelabweichung Stefan Boneberg Seite 56 von 65