;------------------------------------------------------------------------------- ; VLF Kalender-Morse-Empfaenger mit Trägem Peak-Hold S-Meter (vlf_rx.asm) ; Dekodiert VLF bei 8.3333 kHz und misst die Signalstaerke ueber ADC0 (Pin 23) ; S-Meter haelt den Spitzenwert fuer 2s und faellt danach sehr langsam ab. ; Ausgabe: Zeile 1 = Text, Zeile 2 = [■■■■■ ] + Signal ; Taktfrequenz des ATmega328P: 1 MHz (Werkseinstellung) ;------------------------------------------------------------------------------- .include "m328pdef.inc" ;--- Registerdefinitionen --- .def temp = r16 .def lcd_data = r17 .def sample_cnt = r18 ; Zaehlt die Signal-Praesenz (Timing) .def morse_len = r19 ; Anzahl der Elemente im aktuellen Zeichen .def morse_pat = r20 ; Bit-Muster (0=Dit, 1=Dah) .def space_cnt = r21 ; Zaehlt die Dauer der Signalstille .def adc_val = r22 ; Aktueller ADC-Wert (ADCH) .def bar_cnt = r23 ; Hilfsregister fuer die Balkengrafik .def adc_max = r24 ; Gespeicherter Spitzenwert fuer das S-Meter .def decay_cnt = r25 ; Zaehlt die Hold-Zeit und bremst den Abfall ; Warteschleifen-Register (unterer Block) .def dcnt1 = r2 .def dcnt2 = r3 .def dcnt3 = r4 ;--- LCD-Pin-Definitionen --- .equ LCD_PORT = PORTD .equ LCD_DDR = DDRD .equ LCD_CTRL_PT = PORTB .equ LCD_CTRL_DR = DDRB .equ LCD_RS = 1 ; PB1 .equ LCD_E = 2 ; PB2 ;------------------------------------------------------------------------------- ; Interrupt-Vektortabelle ;------------------------------------------------------------------------------- .org 0x0000 rjmp RESET .org OC1Aaddr rjmp TIMER1_COMPA_ISR ; Sampling-Takt & ADC-Start: Alle 10ms ;------------------------------------------------------------------------------- ; Initialisierung ;------------------------------------------------------------------------------- RESET: ; Stackpointer initialisieren ldi temp, low(RAMEND) out SPL, temp ldi temp, high(RAMEND) out SPH, temp ; LCD-Steuerleitungen als Ausgang sbi LCD_CTRL_DR, LCD_RS sbi LCD_CTRL_DR, LCD_E cbi LCD_CTRL_PT, LCD_RS cbi LCD_CTRL_PT, LCD_E ; LCD-Datenleitungen (obere 4 Bits von PORTD) als Ausgang ldi temp, 0xF0 out LCD_DDR, temp ; Digitaler Signaleingang: PD2 (INT0-Pin) vom MAX9010 kommend cbi DDRD, 2 sbi PORTD, 2 ; --- ADC Setup --- ; REFS0 = AVCC, ADLAR = 1 (Linksbuendig für 8-Bit Aufloesung in ADCH) ; MUX3..0 = 0000 fuer ADC0 (Pin 23) ldi temp, (1< neuer Peak ; Kein neuer Peak: Pruefe ob Hold-Zeit (2 Sekunden) abgelaufen ist tst decay_cnt breq DECAY_PROCESS ; Wenn 0, springe zum langsamen Absinken dec decay_cnt ; Sonst Hold-Zeit runterzaehlen rjmp UPDATE_DISPLAY NEW_PEAK: mov adc_max, adc_val ; Aktualisiere den Spitzenwert ldi decay_cnt, 200 ; Setze Hold-Zeit auf 200 Ticks (200 * 10ms = 2 Sekunden) rjmp UPDATE_DISPLAY DECAY_PROCESS: ; Um den Abfall ueber einen groesseren Zeitraum zu strecken, nutzen wir ; decay_cnt negativ als Teiler. Wir lassen adc_max nur alle 4 Ticks sinken. dec decay_cnt ; Wird von 0 auf 255, 254, 253... heruntergezaehlt mov temp, decay_cnt andi temp, 0x03 ; Nur alle 4 Ticks (40ms) wahr brne UPDATE_DISPLAY tst adc_max breq UPDATE_DISPLAY ; Bereits bei 0, kein weiterer Abfall noetig dec adc_max ; Spitzenwert ganz langsam verringern UPDATE_DISPLAY: ; S-Meter Balken mit dem gedaempften adc_max aktualisieren rcall UPDATE_SMETER ; 2. Digitalen Morse-Kanal abtasten (PD2) sbis PIND, 2 rjmp SIGNAL_PRESENT ; --- SIGNALSTILLE --- tst sample_cnt breq NO_CARRIER_END rcall EVALUATE_IMPULSE ; Impuls auswerten (Dit/Dah) clr sample_cnt NO_CARRIER_END: inc space_cnt cpi space_cnt, 35 ; > 350ms Pause? -> Zeichen fertig brcc DECODE_CHARACTER reti SIGNAL_PRESENT: ; --- TRÄGER VORHANDEN --- clr space_cnt inc sample_cnt reti ;------------------------------------------------------------------------------- ; S-Meter Balkengrafik generieren (Zeile 2, Spalte 0 bis 7) ;------------------------------------------------------------------------------- UPDATE_SMETER: push lcd_data rcall REFRESH_BAR_CURSOR ; Cursor auf Anfang Zeile 2 setzen ; Wir teilen adc_max (0-255) durch 32, um max 8 Balken-Segmente zu erhalten mov temp, adc_max lsr temp lsr temp lsr temp lsr temp lsr temp ; temp = adc_max / 32 (Wert von 0 bis 8) mov bar_cnt, temp draw_blocks: tst bar_cnt breq fill_spaces ldi lcd_data, 0xFF ; Voller HD44780-Blockcharakter rcall LCD_DATA_OUT dec bar_cnt rjmp draw_blocks fill_spaces: mov bar_cnt, temp ldi temp, 8 sub temp, bar_cnt mov bar_cnt, temp draw_spaces: tst bar_cnt breq smeter_done ldi lcd_data, ' ' rcall LCD_DATA_OUT dec bar_cnt rjmp draw_spaces smeter_done: ldi lcd_data, '|' rcall LCD_DATA_OUT pop lcd_data ret REFRESH_BAR_CURSOR: ldi lcd_data, 0xC0 ; Zeile 2, Spalte 0 rcall LCD_CMD_OUT ret ;------------------------------------------------------------------------------- ; Morse-Dekodierung & Zeichentabelle ;------------------------------------------------------------------------------- DECODE_CHARACTER: cpi morse_len, 0 breq DECODE_SKIP ; Setze den Cursor hinter das S-Meter (Zeile 2, Spalte 10) vor der Ausgabe ldi lcd_data, 0xCA rcall LCD_CMD_OUT cpi morse_len, 1 breq LEN_1 cpi morse_len, 2 breq LEN_2 cpi morse_len, 3 breq LEN_3 cpi morse_len, 4 breq LEN_4 cpi morse_len, 5 breq LEN_5 rjmp RESET_DECODER LEN_1: cpi morse_pat, 0b00000010 breq CHAR_E cpi morse_pat, 0b00000011 breq CHAR_T rjmp RESET_DECODER LEN_2: cpi morse_pat, 0b00000110 breq CHAR_M cpi morse_pat, 0b00000100 breq CHAR_I rjmp RESET_DECODER LEN_3: cpi morse_pat, 0b00001111 breq CHAR_O cpi morse_pat, 0b00001100 breq CHAR_D cpi morse_pat, 0b00001000 breq CHAR_S rjmp RESET_DECODER LEN_4: cpi morse_pat, 0b0011011 breq CHAR_Y cpi morse_pat, 0b0010000 breq CHAR_H rjmp RESET_DECODER LEN_5: cpi morse_pat, 0b00111111 breq CHAR_1 cpi morse_pat, 0b00111110 breq CHAR_2 cpi morse_pat, 0b00111100 breq CHAR_3 cpi morse_pat, 0b00111000 breq CHAR_4 cpi morse_pat, 0b00110000 breq CHAR_5 cpi morse_pat, 0b00100000 breq CHAR_6 cpi morse_pat, 0b00100001 breq CHAR_7 cpi morse_pat, 0b00100011 breq CHAR_8 cpi morse_pat, 0b00100111 breq CHAR_9 cpi morse_pat, 0b00101111 breq CHAR_0 RESET_DECODER: clr morse_len ldi morse_pat, 0x01 DECODE_SKIP: reti CHAR_E: ldi lcd_data, 'E' rcall PRINT rjmp RESET_DECODER CHAR_T: ldi lcd_data, 'T' rcall PRINT rjmp RESET_DECODER CHAR_M: ldi lcd_data, 'M' rcall PRINT rjmp RESET_DECODER CHAR_I: ldi lcd_data, 'I' rcall PRINT rjmp RESET_DECODER CHAR_O: ldi lcd_data, 'O' rcall PRINT rjmp RESET_DECODER CHAR_D: ldi lcd_data, 'D' rcall PRINT rjmp RESET_DECODER CHAR_S: ldi lcd_data, 'S' rcall PRINT rjmp RESET_DECODER CHAR_Y: ldi lcd_data, 'Y' rcall PRINT rjmp RESET_DECODER CHAR_H: ldi lcd_data, 'H' rcall PRINT rjmp RESET_DECODER CHAR_1: ldi lcd_data, '1' rcall PRINT rjmp RESET_DECODER CHAR_2: ldi lcd_data, '2' rcall PRINT rjmp RESET_DECODER CHAR_3: ldi lcd_data, '3' rcall PRINT rjmp RESET_DECODER CHAR_4: ldi lcd_data, '4' rcall PRINT rjmp RESET_DECODER CHAR_5: ldi lcd_data, '5' rcall PRINT rjmp RESET_DECODER CHAR_6: ldi lcd_data, '6' rcall PRINT rjmp RESET_DECODER CHAR_7: ldi lcd_data, '7' rcall PRINT rjmp RESET_DECODER CHAR_8: ldi lcd_data, '8' rcall PRINT rjmp RESET_DECODER CHAR_9: ldi lcd_data, '9' rcall PRINT rjmp RESET_DECODER CHAR_0: ldi lcd_data, '0' rcall PRINT rjmp RESET_DECODER PRINT: rcall LCD_DATA_OUT ret EVALUATE_IMPULSE: cpi sample_cnt, 20 brcc IS_DAH lsl morse_pat rjmp IMPULSE_DONE IS_DAH: lsl morse_pat ori morse_pat, 0x01 IMPULSE_DONE: inc morse_len ret ;------------------------------------------------------------------------------- ; HD44780 LCD-Treiber (4-Bit Modus) ;------------------------------------------------------------------------------- LCD_INIT: rcall delay_100ms ldi temp, 0x30 out LCD_PORT, temp rcall LCD_TOGGLE_E rcall delay_5ms rcall LCD_TOGGLE_E rcall delay_100ms rcall LCD_TOGGLE_E ldi temp, 0x20 out LCD_PORT, temp rcall LCD_TOGGLE_E ldi lcd_data, 0x28 rcall LCD_CMD_OUT ldi lcd_data, 0x0C rcall LCD_CMD_OUT ldi lcd_data, 0x01 rcall LCD_CMD_OUT rcall delay_5ms ret LCD_CMD_OUT: cbi LCD_CTRL_PT, LCD_RS rcall LCD_SEND_NIBBLES ret LCD_DATA_OUT: sbi LCD_CTRL_PT, LCD_RS rcall LCD_SEND_NIBBLES ret LCD_SEND_NIBBLES: mov temp, lcd_data andi temp, 0xF0 out LCD_PORT, temp rcall LCD_TOGGLE_E mov temp, lcd_data swap temp andi temp, 0xF0 out LCD_PORT, temp rcall LCD_TOGGLE_E rcall delay_5ms ret LCD_TOGGLE_E: sbi LCD_CTRL_PT, LCD_E nop nop cbi LCD_CTRL_PT, LCD_E ret delay_5ms: ldi temp, 70 mov dcnt2, temp W2: ldi temp, 70 mov dcnt3, temp W3: dec dcnt3 brne W3 dec dcnt2 brne W2 ret delay_100ms: ldi temp, 2 mov dcnt1, temp ldi temp, 4 mov dcnt2, temp ldi temp, 186 mov dcnt3, temp W1: dec dcnt3 brne W1 dec dcnt2 brne W1 dec dcnt1 brne W1 ret