; *********************************************************
; * Angeschlossener Taster macht Toene, Tonhoehe mit Poti *
; * (C)2005 by info@avr-asm-tutorial.net                  *
; *********************************************************
;
.INCLUDE "tn13def.inc"
;
; Schaltbild:
;                   ATMEL ATtiny13
;                     ___   ____
;            ___    1/   |_|    |8
;+5 Volt O--|___|----|Res    Vcc|----O + 5 Volt
;                    |          |
; +0..5 Volt O-------|ADC3   PB2|   ___
;                /  3|          |6  \_/
;     0 Volt O--O O--|PB4    PB1|---|_|--O + 5 Volt
;                   4|          |   LSP
;        0 Volt O----|Gnd    PB0|
;                    |__________|
;
; Register Definitionen
;
.DEF rTonA = R14 ; Tonhoehe = TC0 Compare Match A
.DEF rTonB = R15 ; halbe Tonhoehe = TC0 Compare Match B
.DEF rmp = R16 ; Multipurpose register
.DEF rimp = R17 ; Interrupt multipurpose register
;
; Reset- und Interrupt Vektoren
;
.CSEG ; Assembliere in den Programm-Flash-Speicher
.ORG $0000 ; beginne mit Adresse 0
;
; Sprungvektoren fuer Reset und Interrupts
;
	rjmp main ; Reset vector
	reti ; Int0 interrupt vector
	rjmp intpcint ; PCINT0 vector
	reti ; TC0 overflow vector
	reti ; Eeprom ready vector
	reti ; Analog comparator int vector
	reti ; TC0 CompA vector
	reti ; TC0 CompB vector
	reti ; WDT vector
	rjmp intadc ; ADC conversion complete vector
;
; PCINT0 Service Routine
;   wird jedes Mal ausgefuehrt, wenn sich der Pegel am
;   Pin 3 (=PB4) aendert 
;
intpcint:
	sbic PINB,4 ; Ueberspringe Befehl wenn PB4=Null
	rjmp intpcint1 ; springe weil PB4 = Eins
	out OCR0A,rTonA ; Tonhoehe einstellen
	out OCR0B,rTonB
	ldi rimp,0b01010010 ; CTC, Ausg. A und B bei 
	out TCCR0A,rimp ; compare match auf toggle (NF an)
	ldi rimp,0b00000010 ; Vorteiler 1024, Timer start
	out TCCR0B,rimp
	reti ; Kehre vom Interrupt zurueck
intpcint1:
	ldi rimp,0b11110010 ; CTC, Ausgaenge A und B bei
	out TCCR0A,rmp ;  Compare Match auf 1 stellen (NF aus)
	reti ; Kehre vom Interrupt zurueck
;
; AD-Wandler hat einen Wert gewandelt, abholen und speichern
;
intadc:
	in rTonA,ADCL ; Lese ADC-Wert, niedriges Byte
	in rTonB,ADCH ; Lese ADC-Wert, hohes Byte
	lsr rTonB ; durch 2 teilen
	ror rTonA
	lsr rTonB ; durch 4 teilen
	ror rTonA
	mov rTonB,rTonA ; Ergebnis kopieren
	lsr rTonB ; durch zwei teilen
	reti ; fertig und zureck
;
; Main program start
;
main:
;
; Stapelzeiger setzen fuer Rueckkehr-Adressen vom Interrupt
;
	ldi rmp,LOW(RAMEND) ; Stapelzeiger auf Ende SRAM
	out SPL,rmp
;
; Angeschlossene Hardware initiieren
;
	sbi DDRB,1 ; Lautsprecher-Pin als Ausgang definieren
	cbi DDRB,4 ; Taster-Eingang als Eingang definieren
	sbi PORTB,4 ; Internen Pull-Up-Widerstand einschalten
;
; AD-Wandler starten
;
	ldi rmp,0b00001000 ; PB3 Treiber aus, spart Strom
	out DIDR0,rmp
	ldi rmp,0b00000011 ; Referenzspannung UB, ADC3 waehlen
	out ADMUX,rmp
	ldi rmp,0b00000000 ; Freilauf waehlen (startet selbst)
	out ADCSRB,rmp
	ldi rmp,0b11101111 ; ADC starten, Autostart,
	out ADCSRA,rmp ;  Int Enable, Teiler auf 128
;
; Tonerzeugung mit Timer TC0
; 8-Bit-Timer mit 1,2 MHz Prozessortakt mit Vorteiler durch 8
; 1,2 MHz / 8 = 150 kHz, / 75 = 2000 Hz, /2 = 1000 Hz
; Start erfolgt erst bei PCINT-Interrupt
;
	ldi rmp,75 ; Setze Compare A auf 147 (Ende Zaehler)
	mov rTonA,rmp ; speichere in Register
	ldi rmp,38 ; Setze Compare B auf halben Timer-Wert
	mov rTonB,rmp ; speichere in Register
;
; Pin-Change-Interrupt fuer Taste aktivieren
;
	ldi rmp,0b00010000 ; Maskieren der aktiven Eingaenge
	out PCMSK,rmp
	ldi rmp,0b00100000 ; PCINT0-Interrupts ermoeglichen
	out GIMSK,rmp
;
; Interrupts generell einschalten
;
	sei ; Setze Interrupt Flagge
;
; Schlafmodus der CPU einstellen
;
	ldi rmp,0b00100000 ; Schlafmodus auf Idle
	out MCUCR,rmp
;
; Loop mit Interrupt
;
loop:
	sleep ; Prozessor schlafen legen
	nop ; Tue nichts nach dem Aufwachen
	rjmp loop ; Prozessor wieder schlafen legen
;
; Ende Quellcode
;