;******************************************************************************* ;* ;* Titel: Aufnahmegeraet mit EEPROM (24LC256) ;* (C306_I2C_EEPROM_ADDA.asm) ;* Datum: 25/01/11 Version: 0.1 ;* Autor: WEIGU ;* ;* Informationen zur Beschaltung: ;* ;* Prozessor: ATmega32A Quarzfrequenz: 16MHz ;* Eingaenge: Potentiometer (0-5V) an PA1, Mikrofonschaltung an PA0 (0-5V) ;* Aufnahmetaster an PC2 ;* Ausgaenge: D/A-Wandler an PortB, EEPROM (I2C) an SCL und SDA ;* (PC0 und PC1), LED Aufnahme an PC3, LED Abspielen an PC4 ;* ;* Informationen zur Funktionsweise: ;* ;******************************************************************************* ;------------------------------------------------------------------------------- ; Einbinden der controllerspezifischen Definitionsdatei ;------------------------------------------------------------------------------- .NOLIST ;List-Output ausschalten .INCLUDE "m32def.inc" ;AVR-Definitionsdatei einbinden .LIST ;List-Output wieder einschalten ;------------------------------------------------------------------------------- ; Organisation des Datenspeichers (SRAM) ;------------------------------------------------------------------------------- .DSEG ;was ab hier folgt kommt in den SRAM-Speicher E24ADL: .BYTE 1 ;16 Bit Adressezeiger EEPROM E24ADH: .BYTE 1 E24BYTE: .BYTE 1 ;Datenbyte EEPROM E24PAGE: .BYTE 64 ;64 Byte Seite (Page) im EEPROM TCNT: .BYTE 1 ;Tabellenzeiger TAB1: .BYTE 128 ;128 Byte Tabelle ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Programmspeicher (FLASH) Programmstart nach RESET ab Adr. 0x0000 ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .CSEG ;was ab hier folgt kommt in den FLASH-Speicher .ORG 0x0000 ;Programm beginnt an der FLASH-Adresse 0x0000 RESET1: rjmp INIT ;springe nach INIT (ueberspringe ISR Vektoren) ;------------------------------------------------------------------------------- ; Sprungadressen fuer die Interrupts organisieren (ISR VECTORS) ;------------------------------------------------------------------------------- ;Vektortabelle (im Flash-Speicher) .ORG OC2addr ;interner Vektor fuer Timer2 Compare rjmp ISR_T2 ;Bei TCNT2=OCR2 springe zur ISR Timer2 .ORG OC0addr ;interner Vektor fuer Timer0 Compare rjmp ISR_T0 ;Bei TCNT0=OCR0 springe zur ISR Timer0 .ORG ADCCaddr ;interner Vektor fuer ADCC (alt.: .ORG 0x0020) ;AD-Wandlung vollstaendig ADC complete rjmp ISR_AD ;Springe zur ISR von ADCC ;------------------------------------------------------------------------------- ; Initialisierungen und eigene Definitionen ;------------------------------------------------------------------------------- .ORG INT_VECTORS_SIZE ;Platz fuer ISR Vektoren lassen INIT: .DEF Zero = r15 ;Register 1 wird zum Rechnen benoetigt clr r15 ;und mit Null belegt .DEF Tmp1 = r16 ;Register 16 dient als erster Zwischenspeicher .DEF Tmp2 = r17 ;Register 17 dient als zweiter Zwischenspeicher .DEF Cnt1 = r18 ;Register 18 dient als Zaehler .DEF WL = r24 ;Register 24 und 25 dienen als universelles .DEF WH = r25 ;Doppelregister W und zur Parameteruebergabe ;Stapel initialisieren (fuer Unterprogramme bzw. Interrupts) ldi Tmp1,HIGH(RAMEND) ;RAMEND (SRAM) ist in der Definitions- out SPH,Tmp1 ;datei festgelegt ldi Tmp1,LOW(RAMEND) out SPL,Tmp1 ;ADC initialisieren ldi Tmp1,0b01100000 ;REFS = 01 AVCC als Referenzspannung out ADMUX,Tmp1 ;ADLAR = 1 linksb. (obere 8 Bit in ADCH) ;MUX = 00000 unsymetrisch PA0 (ADC0) ldi Tmp1,0b10100100 ;ADEN = 1 (ADC einschalten) out ADCSRA,Tmp1 ;ADATE = 1 (Auto Trigger Modus ein) ;ADIE = 0 (noch kein Interrupt) ;ADPS = 100 (16MHz/16 = 1MHz) ;andere Bits per default = 0 in Tmp1,SFIOR ;ADTS = 011 Timer 0 Compare andi Tmp1,0b01111111 ori Tmp1,0b01100000 out SFIOR,Tmp1 ;Timer0 einschalten und Vorteiler festlegen (SAVE) ldi Tmp1,0x0B ;TCCR0 = 0b00001011 (Systemtakt/64) out TCCR0,Tmp1 ;WGM = 01 CTC-Modus ;Vergleichswert T0 fuer den Zaehler festlegen ldi Tmp1,36 ;36 Zaehlschritte = 6,8kHz; fs = 3,4kHz out OCR0,Tmp1 ;Timer2 einschalten und Vorteiler festlegen (PLAY) ldi Tmp1,0x0C ;TCCR0 = 0b00001100 (Systemtakt/64) ;!! CS2 <> CS0 anders als Timer0!!) out TCCR2,Tmp1 ;WGM = 01 CTC-Modus ;Vergleichswert T2 fuer den Zaehler festlegen ldi Tmp1,36 ;50 Zaehlschritte = 5000Hz out OCR2,Tmp1 ;D/A-Wandler initialisieren ser Tmp1 ;D/A-Wandler an PORTB out DDRB,Tmp1 ;Aufnahmetaster und LEDs initialisieren cbi DDRC,2 ;Aufnahmetaster an PC2 sbi PORTC,2 ;Pull-Up sbi DDRC,3 ;AufnahmeLED (SAVE) an PC3 sbi DDRC,4 ;AbspieLED (PLAY) an PC4 ;I2C Bus initialisieren (400 kHz) rcall I2CINI ;Interrupts global erlauben sei ;------------------------------------------------------------------------------- ; Hauptprogramm ;------------------------------------------------------------------------------- MAIN: ;T2 Interrupt (PLAY) ausschalten in Tmp1,TIMSK ; andi Tmp1,0x7F ;Mit einer UND-Maskierung (0b01111111) ;Bit 7 (OCIE2) im TIMSK-Register loeschen out TIMSK,Tmp1 ; cbi PORTC,4 ;Abspiel LED loeschen ;Potentiometer zum Verstellen der Abspielgeschwindigkeit an PA1 ;Option! dieser Teil kann falls erwuenscht geloescht werden ldi Tmp1,0b01100001 ;REFS = 01 AVCC als Referenzspannung out ADMUX,Tmp1 ;ADLAR = 1 linksb. (obere 8 Bit in ADCH) ldi Tmp1,0b10000100 ;ADEN = 1 (ADC einschalten) out ADCSRA,Tmp1 ;ADPS = 100 (16MHz/16 = 1MHz) sbi ADCSRA,ADSC ;eine AD-Wandlung ausloesen LOOPV: sbic ADCSRA,ADSC ;Polling bis Wandlung fertig rjmp LOOPV in Tmp1,ADCH ;oberste 8 Bit einlesen und ausgeben lsr Tmp1 ;Wert durch 4 teilen lsr Tmp1 brne LOOPG ;auf Endstellung (0) ldi Tmp1,36 ;normale Abspielgeschwindigkeit LOOPG: out OCR2,Tmp1 ldi Tmp1,0b01100000 ;A/D Wandler zuruecksetzen (PA0 Mikrofoneingang) out ADMUX,Tmp1 ldi Tmp1,0b10100100 out ADCSRA,Tmp1 sbic PINC,2 ;Aufnahmetaster rjmp PLAY SAVE: ;Timer0 (SAVE) Interrupt einschalten in Tmp1,TIMSK ; ori Tmp1,0x02 ;Mit einer ODER-Maskierung (0b00000010) ;Bit 2 (OCIE0) im TIMSK-Register auf eins setzen out TIMSK,Tmp1 ; sbi ADCSRA,ADIE ;Anfangsadresse und Tabellenzaehler initialisieren, AufnahmeLED ein clr Tmp1 sts E24ADL,Tmp1 sts E24ADH,Tmp1 sts TCNT,Tmp1 sbi PORTC,3 SAVE0: lds Tmp1,TCNT ;zweite Haelfte der Tabelle? cpi Tmp1,64 brge SAVE1 rjmp SAVE0 SAVE1: clr Cnt1 ;PAGE (64 Byte) schreiben ldi XL,LOW(E24PAGE) ldi XH,HIGH(E24PAGE) ldi YL,LOW(TAB1) ldi YH,HIGH(TAB1) LOOP2: ld Tmp1,Y+ st X+,Tmp1 inc Cnt1 cpi Cnt1,64 brne LOOP2 rcall E24SP ;Pageadresse erhoehen lds XL,E24ADL lds XH,E24ADH adiw XL,32 ;64 addieren (naechste Seite) adiw XL,32 sts E24ADL,XL sts E24ADH,XH LOOP3: lds Tmp1,TCNT ;erste Haelfte der Tabelle? cpi Tmp1,64 brlo SAVE2 rjmp LOOP3 SAVE2: clr Cnt1 ;PAGE (64 Byte) schreiben ldi XL,LOW(E24PAGE) ldi XH,HIGH(E24PAGE) ldi YL,LOW(TAB1+64) ldi YH,HIGH(TAB1+64) LOOP4: ld Tmp1,Y+ st X+,Tmp1 inc Cnt1 cpi Cnt1,64 brne LOOP4 rcall E24SP ;Pageadresse erhoehen lds XL,E24ADL lds XH,E24ADH adiw XL,32 ;64 addieren (naechste Seite) adiw XL,32 brmi PLAY ;Falls EEPROM voll (Bit15 = 1) dann Raus sts E24ADL,XL sts E24ADH,XH rjmp SAVE0 PLAY: ;T0 Interrupt (SAVE) ausschalten in Tmp1,TIMSK ; andi Tmp1,0xFD ;Mit einer UND-Maskierung (0b11111101) ;Bit 1 (OCIE0) im TIMSK-Register loeschen out TIMSK,Tmp1 ; cbi ADCSRA,ADIE ;Anfangsadresse und Tabellenzaehler initialisieren, Abspiel LED ein clr Tmp1 sts E24ADL,Tmp1 sts E24ADH,Tmp1 sts TCNT,Tmp1 sbi PORTC,4 PLAY2: rcall E24RS ;Werte an der gleichen Adresse abholen (1,53ms) clr Cnt1 ;und ausgeben ldi XL,LOW(E24PAGE) ldi XH,HIGH(E24PAGE) ldi YL,LOW(TAB1) ldi YH,HIGH(TAB1) LOOP5: ld Tmp1,X+ st Y+,Tmp1 inc Cnt1 cpi Cnt1,64 brne LOOP5 ;Pageadresse erhoehen lds XL,E24ADL lds XH,E24ADH adiw XL,32 ;64 addieren (naechste Seite) adiw XL,32 ;brmi MAINR ;Falls EEPROM voll (Bit15 = 1) dann Raus sts E24ADL,XL sts E24ADH,XH LOOP6: lds Tmp1,TCNT ;erste Haelfte der Tabelle? cpi Tmp1,64 brlo PLAY3 rjmp LOOP6 PLAY3: lds Tmp1,E24ADL ;erstes Mal? cpi Tmp1,0x40 brne PLAY4 lds Tmp1,E24ADH cpi Tmp1,0x00 brne PLAY4 ;T2 Interrupt einschalten in Tmp1,TIMSK ; ori Tmp1,0x80 ;Mit einer ODER-Maskierung (0b10000000) ;Bit 7 (OCIE2) im TIMSK-Register auf eins setzen out TIMSK,Tmp1 ; cbi PORTC,3 PLAY4: rcall E24RS ;Werte an der gleichen Adresse abholen (1,53ms) clr Cnt1 ;und ausgeben ldi XL,LOW(E24PAGE) ldi XH,HIGH(E24PAGE) ldi YL,LOW(TAB1+64) ldi YH,HIGH(TAB1+64) LOOP7: ld Tmp1,X+ st Y+,Tmp1 inc Cnt1 cpi Cnt1,64 brne LOOP7 ;Pageadresse erhoehen lds XL,E24ADL lds XH,E24ADH adiw XL,32 ;64 addieren (naechste Seite) adiw XL,32 brmi MAINR ;Falls EEPROM voll (Bit15 = 1) dann Raus sts E24ADL,XL sts E24ADH,XH LOOP8: lds Tmp1,TCNT ;zweite Haelfte der Tabelle? cpi Tmp1,64 brge PLAYR rjmp LOOP8 PLAYR: rjmp PLAY2 ;Endlosschleife MAINR: rjmp MAIN ;------------------------------------------------------------------------------- ; Unterprogramme und Interrupt-Behandlungsroutinen ;------------------------------------------------------------------------------- ; Interrupt-Behandlungsroutine Timer2 (PLAY) ISR_T2: push r16 ;benutzte Reg. retten (r16 = Zwischenspeicher) in r16,SREG ;Statusregister einlesen push r16 ;Statusregister retten push r17 push YL push YH cbi PORTC,4 ;dient der Visualisierung per Oszilloskop nop sbi PORTC,4 lds r17,TCNT ldi YL,LOW(TAB1) ldi YH,HIGH(TAB1) add YL,r17 adc YH,Zero ld r16,Y out PORTB,r16 ;Wert aus Tabelle ausgeben inc r17 cpi r17,128 breq ISR_TF sts TCNT,r17 rjmp ISR_TR ISR_TF: clr r17 sts TCNT,r17 ISR_TR: pop YH pop YL pop r17 pop r16 ;Werte der geretteten Register wieder- out SREG,r16 ;herstellen pop r16 reti ;Ruecksprung aus einer ISR ;Dummy Interrupt-Behandlungsroutine ISR_T0: reti ;Ruecksprung aus einer ISR ;Interrupt-Behandlungsroutine ADC (SAVE) ISR_AD: push r16 ;benutzte Reg. retten (r16 = Zwischenspeicher) in r16,SREG ;Statusregister einlesen push r16 ;Statusregister retten push r17 push YL push YH cbi PORTC,3 ;dient der Visualisierung per Oszilloskop nop sbi PORTC,3 lds r17,TCNT ldi YL,LOW(TAB1) ldi YH,HIGH(TAB1) add YL,r17 adc YH,Zero in r16,ADCH ;oberste 8 Bit einlesen und st Y,r16 ;abspeichern inc r17 cpi r17,128 breq ISR_AF sts TCNT,r17 rjmp ISR_AR ISR_AF: clr r17 sts TCNT,r17 ISR_AR: pop YH pop YL pop r17 pop r16 ;Werte der geretteten Register wieder- out SREG,r16 ;herstellen pop r16 reti ;Ruecksprung aus einer ISR .INCLUDE "SR_I2C.asm" ;I2C-Bibliothek einbinden .INCLUDE "SR_EEPROM_24LC256.asm" ;EEPROM-Bibliothek einbinden ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .EXIT ;Ende des Quelltextes