Skip to content

Instantly share code, notes, and snippets.

@pboehm
Created August 7, 2012 21:30
Show Gist options
  • Save pboehm/3289562 to your computer and use it in GitHub Desktop.
Save pboehm/3289562 to your computer and use it in GitHub Desktop.
Lösungen für Aufgaben im Assemblerpraktikum
/******************************************************************************
* Projekt Template für einen Versuch im Assemblerpraktikum *
* *
* Versuch-Nr.: 1 (Digital-Voltmeter) *
* Gruppen-Nr.: *
* *
* Mitglieder der Gruppe:
* - Philipp Böhm
* - Mathias Perlet
*
* Zusammenfassung:
* Dieses Programm nutzt den Analog-Digital-Wandler des Boards um den am
* Potentiometer eingestellten Wert als Spannungswert zwischen 0 und 3,30V
* auf dem Display auszugeben
*
******************************************************************************/
#include "praktikum.h"
///////////////////////////////////////////////////////////////////////////////
//
// main
//
// Die Routine 'main' wird innerhalb der Versuchsanordnung durch den
// Startup-Code angesprungen. Sie ist somit die erste Methode in der Sie
// eigenen Quelltext einfügen können.
//
// Achten Sie darauf, dass 'main' niemals endet.
//
///////////////////////////////////////////////////////////////////////////////
RSEG CODE32:CODE:NOROOT(2)
PUBLIC main
main:
// Initialisiert spezifische Teile des Praktikums. Bitte belassen Sie
// diesen Aufruf aus eigenem Interesse am Beginn der Methode main
RCALL praktikum_init
//////////////////////////////////////////////////
// Display initialisieren - Cursor in zweite Zeile
RCALL lcd_init
RCALL lcd_hide_cursor
MOV R12, 1
MOV R11, 2
RCALL lcd_set_cursor_position
//////////////////////////////////////////////
// Start-Button auslesen, ob er gedrückt wurde
// Wenn der Button gedrückt wurde, soll der
// Programmfluss weiterlaufen.
MOV R12, LWRD(hint)
RCALL lcd_write_string
// Eingabe vom Taster aktivieren
MOV R0, LWRD(AVR32_GPIO_ADDRESS | AVR32_GPIO_PORT_2)
ORH R0, HWRD(AVR32_GPIO_ADDRESS | AVR32_GPIO_PORT_2)
//Bit 24 ist der Taster PB0
MOV R1, 0
SBR R1, 24
ST.W R0[AVR32_GPIO_GPERS], R1
//Taster abfragen
nochma: LD.W R6, R0[AVR32_GPIO_PVR]
BLD R6, 24
BREQ nochma
////////////////////////////////////////////////
// Cursor für Spannungswertausgabe positionieren
// und Display clearen
RCALL lcd_clear_display
MOV R12, 4
MOV R11, 2
RCALL lcd_set_cursor_position
////////////////////////////////////////////////////////////
// GPIO Port 0 aktivieren, weil das Potentiometer dort hängt
MOV R0, LWRD(AVR32_GPIO_ADDRESS | AVR32_GPIO_PORT_0)
ORH R0, HWRD(AVR32_GPIO_ADDRESS | AVR32_GPIO_PORT_0)
// Potentiometer an Port 0 aktivieren (22. Bit für Poti)
MOV R1, 0 // R1-Register auf 0 setzen
SBR R1, 22 // Bit für Poti setzen
ST.W R0[AVR32_GPIO_GPERS], R1 // Aktvieren des Potentiometers
CBR R1, 22 // Clear Bit in Register (22.Bit von R1)
///////////////////////////////////////
// MUX auf Modus für AD-Wandler stellen
ST.W R0[AVR32_GPIO_PMR0S], R1
ST.W R0[AVR32_GPIO_PMR1S], R1
////////////////////
// ADC konfigurieren
// Startup und Sample-Holdtime auf MAX setzen sowie den ADC zurücksetzen
// um ein sauberen Ausgangszustand zu haben
MOV R1, LWRD(AVR32_ADC_ADDRESS)
ORH R1, HWRD(AVR32_ADC_ADDRESS)
//AD-Wandler reseten
MOV R2, 0
SBR R2, 0 //Reset-Bit 1 setzen
ST.W R1[AVR32_ADC_CR], R2
// Start-UP und Sample-and-Hold-Time im ADC Mode Register setzen
MOV R3, LWRD(0xF1F0000)
ORH R3, HWRD(0xF1F0000)
ST.W R1[AVR32_ADC_MR], R3 //ADC-Modus einstellen
LD.W R4, R1[AVR32_ADC_MR]
//Channel enable register vom ADC auf Channel 1 setzen
MOV R3, 0
SBR R3, 1
ST.W R1[AVR32_ADC_CHER], R3
MOV R3, 0 //Reset-Bit 0 setzen
SBR R3, 1 //Start-Bit auf 1 setzen
ST.W R1[AVR32_ADC_CR], R3 // ADC ist ab hoer aktiviert
/////////////////////////////////////////////////////////////////
// Den ADC aktivieren, sodass er einen neuen Wert konvertiert.
// Solange nachschauen, ob ein neuer Wert konvertiert wurde bis
// einer bereitsteht.
//
// Den Wert vom ADC aus dem LCDR-Register holen, umrechnen und
// dann auf dem Display ausgeben
/////////////////////////////////////////////////////////////////
loop:
// ADC dazu bringen, einen neuen Wert zu konvertieren
MOV R3, 0
SBR R3, 1
ST.W R1[AVR32_ADC_CR], R3 // Wandlungsvorgang starten
novalue:
// Statusregister des ADC laden und das DRDY Bit laden
LD.W R4, R1[AVR32_ADC_SR]
BLD R4, 16 // Das 16. Bit ist das DRDY (Data ready) Bit
BRNE novalue
// aktuellen Wert aus ADC laden
LD.W R10, R1[AVR32_ADC_LCDR]
// Wert umrechnen und ausgeben
RCALL calc_value
RCALL display_value
RJMP loop
///////////////////////////////////////////////////////////////////////////////
// Dieses Unterprogramm holt sich den aktuellen Wert aus dem
// Last Converted Data Register (LCDR) und berechnet die notwendigen
// STellen zur Azeige und schreibt diese in spezielle Register
//
// VKT -> R8
// 1.NKT -> R9
// 2.NKT -> R10
///////////////////////////////////////////////////////////////////////////////
calc_value:
PUSHM LR
// Konstanten laden
MOV R6, 1023 // maximale Auflösung des ADC
MOV R8, 3300 // maximaler Spannungswert (3,3 V * 100)
MOV R5, 48 // ASCII-Offset
// Spannungswert ohne Komma berechnen (nicht in ASCII)
MUL R8, R10
DIVU R8, R8, R6
// Vorkommateil berechnen durch restlose Division durch 1000
MOV R6, 1000
DIVU R8, R8, R6 // WICHTIG R9 enthält den Rest der Division
ADD R8, R5 // ASCII-Offset aufaddieren
// Wert für VKT auf Stack sichern
MOV R10, R8 // weil man R8 nicht einzeln pushen kann
PUSHM R10
// 1. Nachkommateil berechnen
MOV R6, 100 // 1. Nachkommastelle
MOV R10, R9 // Nachkommawert aus erster Division laden
DIVU R10, R10, R6 // Division durch 100, Rest in R11
ADD R10, R5 // ASCII-Offset aufaddieren
PUSHM R10 // Sichern des Wertes auf dem Stack
// 2. Nachkommateil (analog zu 1. NKT)
MOV R6, 10 // Division durch 10 für 2. NKT
MOV R10, R11
DIVU R10, R10, R6
ADD R10, R5
PUSHM R10 // Sichern des Wertes auf dem Stack
// berechnete Werte vom Stack holen und in die Register R8-R10
// schreiben um sie dann an display_value weiterzugeben
POPM R8-R10
POPM LR
RET 0
///////////////////////////////////////////////////////////////////////////////
// Ausgeben des aktuellen Spannungswertes, welcher vorher berechnet wurde.
// Die jeweiligen Register R8-R10 müssen mit den Werten gefüllt sein.
//
// R8 = VKT
// R9 = 1. NKT
// R10 = 2. NKT
///////////////////////////////////////////////////////////////////////////////
display_value:
PUSHM LR
// Cursor positionieren (2. Zeile fünfte Spalte)
MOV R11, 2
MOV R12, 5
RCALL lcd_set_cursor_position
// VKT ausgeben
MOV R12, R8
RCALL lcd_write_data
// Komma ausgeben
MOV R12, LWRD(comma)
RCALL lcd_write_string
// 1.NKT ausgeben
MOV R12, R9
RCALL lcd_write_data
// 2.NKT ausgeben
MOV R12, R10
RCALL lcd_write_data
// Einheit ausgeben
MOV R12, LWRD(unit)
RCALL lcd_write_string
POPM LR
RET 0
///////////////////////////////////////////////////////////////////////////////
//
// Das Segment DATA32_C dient Ihnen zur Festlegung eigener Constanten, d. h.
// der permanenten Speicherung von Daten. Ein Beispiel, das den Wert '200' unter
// dem Namen 'constant' im Speicher konstant (unveränderbar) ablegt, ist Ihnen
// gegeben.
//
///////////////////////////////////////////////////////////////////////////////
RSEG DATA32_C:CONST:REORDER:NOROOT(2)
comma:
DC8 ","
unit:
DC8 "V"
hint:
DC8 "Press button PB0 ;-)"
///////////////////////////////////////////////////////////////////////////////
//
// Das Segment DATA32_Z dient Ihnen zur Festlegung von Speicherbereichen für
// Ihre Variablen. Ein Beispiel, dass 16 Byte Platz unter dem Namen 'variable'
// reserviert, ist Ihnen gegeben.
//
///////////////////////////////////////////////////////////////////////////////
RSEG DATA32_Z:DATA:REORDER:NOROOT(2)
variable:
DS8 16
END
/******************************************************************************
* Projekt Template für einen Versuch im Assemblerpraktikum *
* *
* Versuch-Nr.: 2 *
* Gruppen-Nr.: *
* *
* Mitglieder der Gruppe:
* Philipp Böhm
* Mathias Perlet
* *
* Zusammenfassung:
* Implementation einer Wetterstation, welche die Helligkeit sowie
* die Temperatur entsprechend auf dem Display anzeigt.
* *
******************************************************************************/
#include "praktikum.h"
///////////////////////////////////////////////////////////////////////////////
//
// main
//
// Die Routine 'main' wird innerhalb der Versuchsanordnung durch den
// Startup-Code angesprungen. Sie ist somit die erste Methode in der Sie
// eigenen Quelltext einfügen können.
//
// Achten Sie darauf, dass 'main' niemals endet.
//
///////////////////////////////////////////////////////////////////////////////
RSEG CODE32:CODE:NOROOT(2)
PUBLIC main
main:
// Initialisiert spezifische Teile des Praktikums. Bitte belassen Sie
// diesen Aufruf aus eigenem Interesse am Beginn der Methode main
RCALL praktikum_init
//////////////////////////////////////////////////
// Display initialisieren - Cursor in erste Zeile
RCALL lcd_init
RCALL lcd_hide_cursor
MOV R12, 1
MOV R11, 1
RCALL lcd_set_cursor_position
MOV R12, LWRD(welcome)
RCALL lcd_write_string
MOV R12, 1
MOV R11, 3
RCALL lcd_set_cursor_position
MOV R12, LWRD(press_button)
RCALL lcd_write_string
////////////////////////////////////////////////////////
// GPIO Port 2 aktivieren, weil dort Taster hängen
MOV R0, LWRD(AVR32_GPIO_ADDRESS | AVR32_GPIO_PORT_2)
ORH R0, HWRD(AVR32_GPIO_ADDRESS | AVR32_GPIO_PORT_2)
MOV R1, 0
SBR R1, 24
SBR R1, 21
SBR R1, 18
ST.W R0[AVR32_GPIO_GPERS], R1
// Start-Taster abfragen und nur wenn gedrückt fortfahren
nochma: LD.W R6, R0[AVR32_GPIO_PVR]
BLD R6, 24
BREQ nochma
RCALL lcd_clear_display
////////////////////////////////////////////////////////
// GPIO Port 0 aktivieren, weil dort LDR und Temp hängen
MOV R0, LWRD(AVR32_GPIO_ADDRESS | AVR32_GPIO_PORT_0)
ORH R0, HWRD(AVR32_GPIO_ADDRESS | AVR32_GPIO_PORT_0)
// LDR (23. Bit) und Temp (21. Bit)
MOV R1, 0 // R1-Register auf 0 setzen
SBR R1, 23 // Bit für LDR setzen
SBR R1, 21 // Bit für Temp setzen
ST.W R0[AVR32_GPIO_GPERS], R1 // Aktvieren der Komponenten
CBR R1, 23 // Clear Bit in Register (23.Bit von R1)
///////////////////////////////////////
// MUX auf Modus für AD-Wandler stellen
ST.W R0[AVR32_GPIO_PMR0S], R1
ST.W R0[AVR32_GPIO_PMR1S], R1
////////////////////
// ADC konfigurieren
// Startup und Sample-Holdtime auf MAX setzen sowie den ADC zurücksetzen
// um ein sauberen Ausgangszustand zu haben
MOV R1, LWRD(AVR32_ADC_ADDRESS)
ORH R1, HWRD(AVR32_ADC_ADDRESS)
//AD-Wandler reseten
MOV R2, 0
SBR R2, 0 //Reset-Bit 1 setzen
ST.W R1[AVR32_ADC_CR], R2
// Start-UP und Sample-and-Hold-Time im ADC Mode Register setzen
MOV R3, LWRD(0xF1F0000)
ORH R3, HWRD(0xF1F0000)
ST.W R1[AVR32_ADC_MR], R3 //ADC-Modus einstellen
LD.W R4, R1[AVR32_ADC_MR]
///////////////////////////////////////////
// Standardfunktion einstellen Bit 0 = Helligkeit
MOV R5, 0
MOV R6, LWRD(mode)
ORH R6, HWRD(mode)
ST.W R6, R5
/////////////////////////////////////////////////////////////////
// Nachfolgend befindet sich die Schleife, wo die jeweiligen
// Funktionen ausgeführt werden und mittels Button Druck
// der Mode umgeschaltet werden kann
/////////////////////////////////////////////////////////////////
loop:
// Taster auslesen und mode toggeln
MOV R5, LWRD(AVR32_GPIO_ADDRESS | AVR32_GPIO_PORT_2)
ORH R5, HWRD(AVR32_GPIO_ADDRESS | AVR32_GPIO_PORT_2)
// Taster abfragen
LD.W R6, R5[AVR32_GPIO_PVR]
BLD R6, 24
BREQ no_toggle
// aktuelen Modus umschalten
RCALL toggle_mode
// hier einmal das Display löschen
RCALL lcd_clear_display
// ADC reseten
MOV R1, LWRD(AVR32_ADC_ADDRESS)
ORH R1, HWRD(AVR32_ADC_ADDRESS)
MOV R2, 0
SBR R2, 0 //Reset-Bit 1 setzen
ST.W R1[AVR32_ADC_CR], R2
// eine Sekunde warten um das Doppeltoggeln zu unterbinden
MOV R10, LWRD(2500000)
ORH R10, HWRD(2500000)
RCALL wait
no_toggle:
// Mode auslesen und entsprechend handeln
//
// wenn das Mode-Bit den Wert 0 hat dann wird die
// Temperatur ausgegeben, bei 1 die Helligkeit
MOV R5, LWRD(mode)
ORH R5, HWRD(mode)
LD.W R6, R5
BLD R6, 0
BREQ temp // Mode = 1
// Helligkeit
RCALL light
RJMP loop
// Temperatur
temp: RCALL temperature
RJMP loop
///////////////////////////////////////////////////////////////////////////////
// Temperatursensor verarbeiten
//
//////////////////////////////////////////////////////////////////////////////
temperature:
PUSHM LR
// Funktion ausgeben
MOV R12, 1
MOV R11, 1
RCALL lcd_set_cursor_position
MOV R12, LWRD(temp_hint)
RCALL lcd_write_string
// ADC Channel auf den für den Temperatursensor stellen
// Channel enable register vom ADC auf Channel 0 setzen
MOV R3, 0
SBR R3, 0
ST.W R1[AVR32_ADC_CHER], R3
// nächsten Wert holen -> R10
RCALL get_next_adc_value
///////////////////////////////////////////////////////////////////////
// Berechnung des Temperaturwertes und Umwandlung in ASCII, sowie
// die Ausgabe in Prozent
///////////////////////////////////////////////////////////////////////
// Konstanten laden
MOV R5, 48 // ASCII-Offset
MOV R6, 1023 // maximale Auflösung des ADC
MOV R8, 3300
// aktuellen Wert (nicht in ASCII) berechnen
MUL R8, R10
DIVU R8, R8, R6
// Gradwert = (258900 - R8 * 100) / 3766
MOV R4, 100
MUL R8, R4
MOV R4, 258900
SUB R8, R4, R8
MOV R4, 3766
DIVU R8, R8, R4
// Zehnerstelle berechnen ( /10)
MOV R6, 10
DIVU R8, R8, R6 // WICHTIG R9 enthält den Rest der Division
// Wert für Schwellwert-Betrachtung in Variable speichern
MOV R10, LWRD(temp_level)
ORH R10, HWRD(temp_level)
ST.W R10, R8
ADD R8, R5 // ASCII-Offset aufaddieren
// Wert ausgeben
MOV R12, R8
RCALL lcd_write_data
// Einerstelle in ASCII umwandeln und ausgeben
ADD R9, R5
MOV R12, R9
RCALL lcd_write_data
// °C ausgeben
MOV R12, 0x80
RCALL lcd_write_data
MOV R12, 0x43
RCALL lcd_write_data
// Unterprogramm zur Ausgabe des Levels aufrufen
RCALL output_advice
// entsprechend lange warten um das Flackern etwas zu reduzieren
// komplett wird es nie gehen
MOV R10, 350000
RCALL wait
POPM LR
RET 0
//////////////////////////////////////////////////////////////////////////////
// LDR verarbeiten
//
//////////////////////////////////////////////////////////////////////////////
light:
PUSHM LR
////////////////////
// Funktion anzeigen
MOV R12, 1
MOV R11, 1
RCALL lcd_set_cursor_position
MOV R12, LWRD(light_hint)
RCALL lcd_write_string
// ADC Channel auf den für den LDR stellen
// Channel enable register vom ADC auf Channel 2 setzen
MOV R3, 0
SBR R3, 2
ST.W R1[AVR32_ADC_CHER], R3
// nächsten Wert holen -> R10
RCALL get_next_adc_value
///////////////////////////////////////////////////////////////////////
// Berechnung des Helligkeitswerts und Umwandlung in ASCII, sowie
// die Ausgabe in Prozent
///////////////////////////////////////////////////////////////////////
// Konstanten laden
MOV R6, 1023 // maximale Auflösung des ADC
MOV R8, 100
MOV R5, 48 // ASCII-Offset
// aktuellen Wert (nicht in ASCII) berechnen
MUL R8, R10
DIVU R8, R8, R6
// Zehnerstelle berechnen ( /10)
MOV R6, 10
DIVU R8, R8, R6 // WICHTIG R9 enthält den Rest der Division
ADD R8, R5 // ASCII-Offset aufaddieren
// Wert ausgeben
MOV R12, R8
RCALL lcd_write_data
// Einerstelle in ASCII umwandeln und ausgeben
ADD R9, R5
MOV R12, R9
RCALL lcd_write_data
// Prozentzeichen ausgeben
MOV R12, 0x25
RCALL lcd_write_data
// entsprechend lange warten um das Flackern etwas zu reduzieren
// komplett wird es nie gehen
MOV R10, 350000
RCALL wait
POPM LR
RET 0
///////////////////////////////////////////////////////////////////////////////
// nächsten gewandelten Wert holen
//
// konvertierter Wert --> R10
///////////////////////////////////////////////////////////////////////////////
get_next_adc_value:
PUSHM LR
// ADC dazu bringen, einen neuen Wert zu konvertieren
MOV R3, 0
SBR R3, 1
ST.W R1[AVR32_ADC_CR], R3 // Wandlungsvorgang starten
novalue:
// Statusregister des ADC laden und das DRDY Bit laden
LD.W R4, R1[AVR32_ADC_SR]
BLD R4, 16 // Das 16. Bit ist das DRDY (Data ready) Bit
BRNE novalue
// aktuellen Wert aus ADC laden
LD.W R10, R1[AVR32_ADC_LCDR]
POPM LR
RET 0
///////////////////////////////////////////////////////////////////////////////
// mode umschalten
///////////////////////////////////////////////////////////////////////////////
toggle_mode:
PUSHM LR
MOV R5, LWRD(mode)
ORH R5, HWRD(mode)
LD.W R6, R5
COM R6
ST.W R5, R6
POPM LR
RET 0
///////////////////////////////////////////////////////////////////////////////
// Hinweis für die Länge der Hose ausgeben
// < 20 Lange Hose
// < 30 && >= 20 Kurze Hose
// >= 30 Keine Hose
///////////////////////////////////////////////////////////////////////////////
output_advice:
PUSHM LR
// Aktuellen Schwellenwert (Zehnerstelle) für die Temperatur laden
MOV R4, LWRD(temp_level)
ORH R4, HWRD(temp_level)
LD.W R5, R4
CP.W R5, 2
BRCC greaterthan20
// wenn kleiner 20
MOV R10, LWRD(weather_long)
RJMP output
greaterthan20:
CP.W R5, 3
BRCC greaterthan30
// kleiner als 30 und größer gleich 20
MOV R10, LWRD(weather_short)
RJMP output
greaterthan30:
// größer gleich 30
MOV R10, LWRD(weather_no)
output:
// Cursor positionieren und Wert in R10 ausgeben
MOV R12, 1
MOV R11, 4
RCALL lcd_set_cursor_position
MOV R12, R10
RCALL lcd_write_string
POPM LR
RET 0
///////////////////////////////////////////////////////////////////////////////
// Zeit Schleife - ca 1sek
//
// R10 muss die Länge der Zeitschöeife enthalten
///////////////////////////////////////////////////////////////////////////////
wait:
PUSHM LR
MOV R8, R10
subi: SUB R8, 0x1
BRNE subi
POPM LR
RET 0
///////////////////////////////////////////////////////////////////////////////
//
// Das Segment DATA32_C dient Ihnen zur Festlegung eigener Constanten, d. h.
// der permanenten Speicherung von Daten. Ein Beispiel, das den Wert '200' unter
// dem Namen 'constant' im Speicher konstant (unveränderbar) ablegt, ist Ihnen
// gegeben.
//
///////////////////////////////////////////////////////////////////////////////
RSEG DATA32_C:CONST:REORDER:NOROOT(2)
constant:
DC8 200
welcome:
DC8 "Und nun das Wetter"
press_button:
DC8 "Press Button PB0"
temp_hint:
DC8 "Temperatur: "
light_hint:
DC8 "Helligkeit: "
percent:
DC8 "%"
weather_long:
DC8 "Lange Hosen Wetter"
weather_short:
DC8 "Kurze Hosen Wetter"
weather_no:
DC8 "Keine Hosen Wetter"
///////////////////////////////////////////////////////////////////////////////
//
// Das Segment DATA32_Z dient Ihnen zur Festlegung von Speicherbereichen für
// Ihre Variablen. Ein Beispiel, dass 16 Byte Platz unter dem Namen 'variable'
// reserviert, ist Ihnen gegeben.
//
///////////////////////////////////////////////////////////////////////////////
RSEG DATA32_Z:DATA:REORDER:NOROOT(2)
// Da 0. Bit entscheidet welche Funktion ausgeführt wird
// 0 -> Helligkeit
// 1 -> Temperatur
mode:
DS32 1
temp_level:
DS8 0
END
/******************************************************************************
* Projekt Template für einen Versuch im Assemblerpraktikum *
* *
* Versuch-Nr.: 3 *
* Gruppen-Nr.: *
* *
* Mitglieder der Gruppe: *
* - Philipp Böhm
* - Mathias Perlet
* Zusammenfassung:
* Mittels integrierten Timer und Interrupts soll eine Stoppuhr
* entwickelt werden, welche eine Auflösung im Millisekunden-Bereich
* besitzen soll. Mittels Taster soll das Umschalten sowie das Zurücksetzen
* möglich sein.
* *
******************************************************************************/
#include "praktikum.h"
///////////////////////////////////////////////////////////////////////////////
//
// main
//
// Die Routine 'main' wird innerhalb der Versuchsanordnung durch den
// Startup-Code angesprungen. Sie ist somit die erste Methode in der Sie
// eigenen Quelltext einfügen können.
//
// Achten Sie darauf, dass 'main' niemals endet.
//
///////////////////////////////////////////////////////////////////////////////
RSEG CODE32:CODE:NOROOT(2)
PUBLIC main
main:
// Initialisiert spezifische Teile des Praktikums. Bitte belassen Sie
// diesen Aufruf aus eigenem Interesse am Beginn der Methode main
RCALL praktikum_init
/////////////////////
// LEDs konfigurieren
MOV R0, LWRD(AVR32_GPIO_ADDRESS | AVR32_GPIO_PORT_1)
ORH R0, HWRD(AVR32_GPIO_ADDRESS | AVR32_GPIO_PORT_1)
MOV R1, 0
SBR R1, 27
SBR R1, 28
SBR R1, 29
SBR R1, 30
SBR R1, 19
SBR R1, 20
ST.W R0[AVR32_GPIO_GPERS], R1
ST.W R0[AVR32_GPIO_ODER], R1
// LC-Display initialisieren und Cursor abschalten
RCALL lcd_init
RCALL lcd_hide_cursor
// Initialisierung Tasten-Interrupt an Port2 über PB2 des EVK1100
// Autovector für GPIO-Controller setzen, IntLevel = 0
// bei gleichem IntLevel gewinnt höchste Gruppennummer
// also sollte der TimerInt(14) vor dem GPIO-TastenInt(2) sein
// Interrupts aktivieren
CSRF AVR32_SR_GM
MOV R0, LWRD(AVR32_INTC_ADDRESS)
ORH R0, HWRD(AVR32_INTC_ADDRESS)
////////////////////
// ISRs registrieren
// Button (Gruppe 2) ISR an Adresse 0x204 registrieren
MOV R1, 0x204
ST.W R0[AVR32_INTC_IPR + 2*4], R1 // Gruppe 2 (IPR2)
// Timer (Gruppe 14) ISR an Adresse 0x208 registrieren
MOV R1, 0x208
ST.W R0[AVR32_INTC_IPR + 14*4], R1 // Gruppe 14 (IPR14)
// Laden der Basisadresse des GPIO-Controllers in Register R0
MOV R0, LWRD(AVR32_GPIO_ADDRESS)
ORH R0, HWRD(AVR32_GPIO_ADDRESS)
MOV R1, 0
SBR R1, 21
SBR R1, 24
// PB 0 und PB 1 aktivieren (Pin 21 und 24)
ST.W R0[AVR32_GPIO_PORT_2 + AVR32_GPIO_GPERS], R1
// PB0/1 von GPIO2 Interrupt enable
ST.W R0[AVR32_GPIO_PORT_2 + AVR32_GPIO_IERS], R1
// Interrupt Mode Register IMR1 und IMR0
// 00 - Pin Change, 01 - Rising Edge, 10 - Falling Edge
// 11 - Reserved
ST.W R0[AVR32_GPIO_PORT_2 + AVR32_GPIO_IMR0S], R1
// Rising Edge
ST.W R0[AVR32_GPIO_PORT_2 + AVR32_GPIO_IMR1C], R1
// Glitch Filter Enable Register, GFER enabled für PIN 18
// GFER nach RESET auf 1, d.h. Glitch Filter aktiviert
ST.W R0[AVR32_GPIO_PORT_2 + AVR32_GPIO_GFERS], R1
//////////////////////////////////////////////////////////////////////
// Timer-Konfiguration ///////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// R4 als Basis für den Timer
MOV R4, LWRD(AVR32_TC_ADDRESS)
ORH R4, HWRD(AVR32_TC_ADDRESS)
// R5 als Basis für Interruptcontroller
MOV R5, LWRD(AVR32_INTC_ADDRESS)
ORH R5, HWRD(AVR32_INTC_ADDRESS)
// Timer Modi konfigurieren
MOV R1, 0
SBR R1, 15 // Setze WAVE-Mode
SBR R1, 14 // Zählen bis zu einem bestimmten Wert dann Interrupt
CBR R1, 13 // ----
SBR R1, 1 // Timer Quelle auf Clock4 setzen
SBR R1, 0 // ----
ST.W R4[AVR32_TC_CMR0], R1
// Autovektor
MOV R1, 0
SBR R1, 4 // Interrupt wenn Vergleich mit Register
ST.W R4[AVR32_TC_IER0], R1
MOV R1, 0
// Dezimalen Zählerwert eintragen, ab dem der Timer einen
// Interrupt auslöst. Um alle 1ms einen Intzerrupt zu bekommen
// ist dies bei einem 12 MHz Oszillator und Clock4 = 375
MOV R6, LWRD(375)
ORH R6, HWRD(375)
ST.W R4[AVR32_TC_RC0], R6
// Timer-Counter initial auf 0 setzen
MOV R5, LWRD(timer_count)
ORH R5, HWRD(timer_count)
MOV R6, 0
ST.W R5, R6
// Clock aktivieren und starten im Channel Control Register
//
// Bit 0 ist CLKEN welches die Clock zuschaltet aber nicht startet
// Bit 2 ist SWTRG welches die Clock startet, nachdem der
// Timer zurückgesetzt wurde
MOV R6, 0
SBR R6, 0
SBR R6, 2
ST.W R4[AVR32_TC_CCR0], R6
// Timer ist standardmäßig aus timer_active=0
MOV R5, 0
MOV R6, LWRD(timer_active)
ORH R6, HWRD(timer_active)
ST.W R6, R5
// 00:00:00:00 ausgeben
MOV R12, 2
MOV R11, 2
RCALL lcd_set_cursor_position
MOV R12, LWRD(initial)
ORH R12, HWRD(initial)
RCALL lcd_write_string
// Register clearen
MOV R5, 0
MOV R10, 0
MOV R7, 0
MOV R6, 0
RJMP $
///////////////////////////////////////////////////////////////////////
// Toggle LEDs ////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
LedToggle:
PUSHM LR
PUSHM R0-R3
MOV R0, LWRD(AVR32_GPIO_ADDRESS | AVR32_GPIO_PORT_1)
ORH R0, HWRD(AVR32_GPIO_ADDRESS | AVR32_GPIO_PORT_1)
// Anwählen der zu toggelnden LEDs
MOV R1, 0
SBR R1, 27
SBR R1, 28
SBR R1, 29
SBR R1, 30
SBR R1, 19
SBR R1, 20
// Hier geschieht das eigentliche Toggeln
ST.W R0[AVR32_GPIO_OVRT], R1
POPM R0-R3
POPM LR
RET 0
////////////////////////////////////////////////////////////////////////
// Timer Interrupt Service Routine /////////////////////////////////////
////////////////////////////////////////////////////////////////////////
TimerInt:
PUSHM R0-R3
// Statusregister lesen um es zu leeren
MOV R1, LWRD(AVR32_TC_ADDRESS)
ORH R1, HWRD(AVR32_TC_ADDRESS)
LD.W R0, R1[AVR32_TC_SR0]
///////////////////////////////////////////////////////////////
// Testen ob Timer zurzeit aktiv ist sonst nicht inkrementieren
MOV R7, LWRD(timer_active)
ORH R7, HWRD(timer_active)
LD.W R8, R7
BLD R8, 0
BRNE timer_ende
// Initialiserung
MOV R0, 1
ADD R7, R0
MOV R12, 2
MOV R11, 2
RCALL lcd_set_cursor_position
////////////////////////////
// Timer Wert inkrementieren
MOV R4, 1
MOV R5, LWRD(timer_count)
ORH R5, HWRD(timer_count)
LD.W R6, R5
ADD R6, R4
ST.W R5, R6
//////////////////////////////////////
// Aktuellen Wert umrechnen und darstellen
//
// R6 enthält den aktuellen Timer-Wert
// R0 -> ist aktueller Teilerwert
// R1 -> ASCII Offset
MOV R1, 48 // ASCII Offset
// Stunde Zehner (36 000 000 ms)
MOV R0, LWRD(36000000)
ORH R0, HWRD(36000000)
DIVU R6, R6, R0 // R7 rest
ADD R6, R1
MOV R12, R6
RCALL lcd_write_data
MOV R6, R7
// Stunde Einer (3 600 000 ms)
MOV R0, LWRD(3600000)
ORH R0, HWRD(3600000)
DIVU R6, R6, R0 // R7 rest
ADD R6, R1
MOV R12, R6
RCALL lcd_write_data
MOV R6, R7
// Doppelpunkt
MOV R12, LWRD(colon)
ORH R12, HWRD(colon)
RCALL lcd_write_string
// Minute Zehner (600 000 ms)
MOV R0, 600000
DIVU R6, R6, R0 // R7 rest
ADD R6, R1
MOV R12, R6
RCALL lcd_write_data
MOV R6, R7
// Minute Einer (60 000 ms)
MOV R0, 60000
DIVU R6, R6, R0 // R7 rest
ADD R6, R1
MOV R12, R6
RCALL lcd_write_data
MOV R6, R7
// Doppelpunkt
MOV R12, LWRD(colon)
ORH R12, HWRD(colon)
RCALL lcd_write_string
// Sekunde Zehner (10 000 ms)
MOV R0, 10000
DIVU R6, R6, R0 // R7 rest
ADD R6, R1
MOV R12, R6
RCALL lcd_write_data
MOV R6, R7
// Sekunde Einer (1000 ms)
MOV R0, 1000
DIVU R6, R6, R0 // R7 rest
ADD R6, R1
MOV R12, R6
RCALL lcd_write_data
// Jede Sekunde LEDs toggeln
MOV R0, 0
CP.W R0, R7
BRNE notoggle
RCALL LedToggle
notoggle:
MOV R6, R7
// Doppelpunkt
MOV R12, LWRD(colon)
ORH R12, HWRD(colon)
RCALL lcd_write_string
// Sekunde Zehntel (100 ms)
MOV R0, 100
DIVU R6, R6, R0 // R7 rest
ADD R6, R1
MOV R12, R6
RCALL lcd_write_data
MOV R6, R7
// Sekunde Hunderstel (10 ms)
MOV R0, 10
DIVU R6, R6, R0 // R7 rest
ADD R6, R1
MOV R12, R6
RCALL lcd_write_data
MOV R6, R7
timer_ende:
POPM R0-R3
RETE
////////////////////////////////////////////////////////////////////////
// Button Interrupt Service Routine ////////////////////////////////////
////////////////////////////////////////////////////////////////////////
ButtonInt:
PUSHM R0-R3
MOV R0, LWRD(AVR32_GPIO_ADDRESS)
ORH R0, HWRD(AVR32_GPIO_ADDRESS)
// GPIO Interrupt Flag Register einlesen
LD.W R3, R0[AVR32_GPIO_PORT_2 + AVR32_GPIO_IFR]
// welche Taste, welcher PIN aktiviert?
BLD R3, 24
BREQ handle_start_stop
BLD R3, 21
BREQ handle_reset
RJMP ende
handle_start_stop:
/////////////////////////////////
// Toggle des timer_active-Wertes
MOV R0, LWRD(timer_active)
ORH R0, HWRD(timer_active)
LD.W R1, R0
COM R1
ST.W R0, R1
RJMP ende
handle_reset:
//////////////////////////
// Timer-Wert auf 0 setzen
MOV R5, LWRD(timer_count)
ORH R5, HWRD(timer_count)
MOV R6, 0
// 0000000 ausgeben
MOV R12, 2
MOV R11, 2
RCALL lcd_set_cursor_position
MOV R12, LWRD(initial)
ORH R12, HWRD(initial)
RCALL lcd_write_string
ST.W R5, R6
ende:
// GPIO Interrupt Flag Register clean
MOV R0, LWRD(AVR32_GPIO_ADDRESS)
ORH R0, HWRD(AVR32_GPIO_ADDRESS)
ST.W R0[AVR32_GPIO_PORT_2 + AVR32_GPIO_IFRC], R3
POPM R0-R3
RETE // Return from Event/Interrupt
///////////////////////////////////////////////////////////////////////////////
//
// Das Segment DATA32_C dient Ihnen zur Festlegung eigener Constanten, d. h.
// der permanenten Speicherung von Daten. Ein Beispiel, das den Wert '200' unter
// dem Namen 'constant' im Speicher konstant (unveränderbar) ablegt, ist Ihnen
// gegeben.
//
///////////////////////////////////////////////////////////////////////////////
RSEG DATA32_C:CONST:REORDER:NOROOT(2)
start_timer:
DC8 "Timer gestartet"
stop_timer:
DC8 "Timer gestoppt"
reset:
DC8 "Timer Reset"
timer:
DC8 "Timer Interrupt"
colon:
DC8 ":"
initial:
DC8 "00:00:00:00"
///////////////////////////////////////////////////////////////////////////////
//
// Interrupt Tabelle
//
//////////////////////////////////////////////////////////////////////////////
COMMON EVTAB:CODE:ROOT(9)
ORG 0x204 // GPIO (Button) Interrupt
_handle_gpio_int:
RJMP ButtonInt
ORG 0x208 // Timer Interrupt
_handle_timer_int:
RJMP TimerInt
///////////////////////////////////////////////////////////////////////////////
//
// Das Segment DATA32_Z dient Ihnen zur Festlegung von Speicherbereichen für
// Ihre Variablen. Ein Beispiel, dass 16 Byte Platz unter dem Namen 'variable'
// reserviert, ist Ihnen gegeben.
//
///////////////////////////////////////////////////////////////////////////////
RSEG DATA32_Z:DATA:REORDER:NOROOT(2)
timer_count:
DS32 1
timer_active:
DS32 1
END
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment