auch zu finden unter
https://www.mikrocontroller.net/topic/574081#7800773
Auf der Suche nach einer Lösung einen Drehgeber in asm auszuwerten,
stieß ich auf diesen Code der genau meinen Vorstellungen entsprach.
Beitrag "Drehencoder auslesen ASM"
Als Grundauswertung ist das Programm fast so geblieben nur das man jetzt
die Auswertung in einer ISR, für Timer oder Interrupt gesteuert, lösen
kann.
Zusatz ist die Auswertung des Drucktasters, die bei einigen Ausführungen
vorhanden ist. Aber das war das deutlich geringere Problem...
Zeilen mit * gehören zur TIMER-Auswertung
Zeilen mit ** gehören zum Interrupt
Timer 0 CTCMODE OC0A auf unter 10ms einstellen, PinToggle deaktiviert
Pins entsprechend beschalten
oder
INT0/1 jeden Flankewechsel(_- / -_) aktivieren
PCI aktivieren (jeder Flankenwechsel wird beachtet, nicht einstellbar)
ISR für Timer und INT0/1 PCI
Ablauf wie folgt INT0/1 Drehencoder, PCI: Taster:
1. Altwert laden
2. Neuwert einlesen
3. UND Maskierung Neuwert (abhängig an welchen Pins)
4. Neuwert in Altwert speichern
5. Vergleich alt neu ?
wenn alt = neu 9. Ende
6. Altwert swapen
7. Neu Altwert odern
(so steht der Zustand vorher nacher in einem Register)
8. Vergleich und dann jeweils die Sprungbedingung links/rechts
9. Ende
Links/Rechts UP
Richtung als veränderbare Zahl oder nur als Bitstetzung zur weiteren
Auswertung
Der Interrupt zeigt nur an DAS eine Auswertung zu tätigen ist!!
.include "AtMega328_timercounter.asm" ist hier zu finden
https://www.roboternetz.de/community...328-Bibliothek
Code:
;########################################################
;# Projekt: #
;# Drehencoder Auswertung #
;# mit Timer #
;# oder #
;# mit INT0/1 Drehnencoder & PCI Taster #
;# #
;# Timer Zeilen mit * aktivieren & ** deaktivieren #
;# Interrupts Zeilen mit * deaktvieren & ** aktivieren #
;# #
;# Taktfrequenz des AVR: 16 MHz #
;# #
;# CS-SOFT #
;########################################################
.include "m328Pdef.inc" ;AtmegaNN8
.def math1h = r8
.def math1l = r9
.def math2h = R10
.def math2l = r11
.def matherghh = r12
.def mathergh = r13
.def mathergl = r14
.def mathergll = r15
.def temp0 = r16 ;
.def temp1 = r17 ;
.def temp2 = r18
.def temp3 = r19 ;
.def temp4 = r20
.def cnt = r21
.equ cpu = 16000000
.equ Baud0 = 9600
.equ UBRR0 = cpu/(16*Baud0)-1
;**********LCD Port mit 74HC164
.equ LCD_signs = 20
.equ Zeile1 = $00+$80
.equ Zeile2 = $40+$80
.equ Zeile3 = Zeile1+LCD_signs
.equ Zeile4 = Zeile2+LCD_signs
.equ port_lcd_x = portc ;gilt für 4/8bit modus
.equ ddrx_lcd_x = ddrc
; Pinbelegungen
; STD
.equ SClock = 0 ;LCD ;;;
.equ SRS = 0
.equ SData = 1 ;74164 ;;;;;so Kann die HW angeschlossen sein
.equ SRW = 1
.equ Light = 2 ;LCD ;;;;;
.equ SEnable = 3 ;74164 ;;;
;********* parallel für LCD/Simulationssoftware*************
;.equ st_port_lcd_x = portb
;.equ st_ddrx_lcd_x = ddrb
; STD
.equ PRS = 4 ;
.equ PEnable = 5 ;
;Entry Set
.equ SH = 0 ;1 = Display shift 0 = not shifted
.equ ID = 1 ;1 = increase 0 = decrease
.equ HES = 2 ;immer 1 setzen Symbolisiert das Ende
;des Commandos
;DISPLAY on/off
.equ B = 0 ;1 = Blink 0 = no Blink
.equ C = 1 ;1 = Cursor on 0 = Cursor off
.equ D = 2 ;1 = Disp on 0 = Disp off
.equ HD = 3 ;immer 1 setzen Symbolisiert das Ende
;des Commandos
;Shift
.equ RL = 2 ;1 = right shift 0 = left shift
.equ SC = 3 ;1 = Disp shift 0 = Cursor move
.equ HS = 4 ;immer 1 setzen Symbolisiert das Ende
;des Commandos
;SET Function
.equ F = 2 ;1 = 5x10 0 = 5x7
.equ N = 3 ;1 = 2line(4line) 0 = 1line
.equ DL = 4 ;1 = 8bit int 0 = 4bit interface
.equ HSF = 5 ;immer 1 setzen Symbolisiert das Ende
;des Commandos
;************ Drehencoder Zuordnung************
.equ DrehENC_ddr = ddrD
.equ DrehENC_port= Portd
.equ DrehENC_pin = Pind
.equ Phase_A = 2
.equ Phase_B = 3
.equ Taster_ENC = 4
;**********interner ADC
.equ ADC_ddr = ddrc
.equ ADC_Port = Portc
.equ ADC_Pin = PinC
.equ Chan0 = 0
.equ Chan1 = 1
.equ Chan2 = 2
.equ Chan3 = 3
.equ Chan4 = 4
.equ Chan5 = 5
.equ ref5 = $1312
.equ ref52 = $0
.equ ref256 = $09d0
.equ ref2562 = $0
;**********SRAM
.equ erg_k = $0100 ;erg_k wird bis zu 5 weiteren bytes genutzt sprich erg_k+5
.equ ocra0 = $0105 ;für T0
.equ ocrb0 = $0106
.equ ocra1h = $0107 ;;;;;
.equ ocra1l = $0108 ;;;;;;;; für T1 A channel
.equ ocrb1h = $0109 ;;;;;
.equ ocrb1l = $010a ;;;;;;;; für T1 B channel
.equ icr1xh = $010b ;;;;;
.equ icr1xl = $010c ;;;;;;;; für T1 ICR
.equ ocra2 = $010d
.equ ocrb2 = $010e
.equ hadc = $0110 ;adc
.equ ladc = $0111 ;adc
.equ eep_adrh = $0112 ;eeprom
.equ eep_adrl = $0113 ;eeprom
.equ LTC_wertH = $0114
.equ LTC_wertL = $0115
.equ dreh_ENC_old= $0116
.equ dreh_Richt = $0117
.equ dreh_tast_old = $0118
.equ RSdebug = $0140 ;debug serielle Schnittstelle
;***************************Einsprungadressen***********************
.cseg
.org $0000
rjmp stack
.org $0002 ;2
rjmp INT_EX0 ;**
.org $0004 ;4
rjmp INT_EX1 ;**
.org $0006 ;6
reti;rjmp INT_PC0
.org $0008 ;8
reti;rjmp INT_PC1
.org $000a ;a
rjmp INT_PC2 ;**
.org $000c ;c
reti;rjmp INT_WDT
.org $000e ;e
reti;rjmp INT_OC2A
.org $0010 ;10
reti;rjmp INT_OC2B
.org $0012 ;12
reti;rjmp INT_OVF2
.org $0014 ;14
reti;rjmp INT_CPT1
.org $0016 ;16
reti;rjmp INT_OC1A
.org $0018 ;18
reti;rjmp INT_OC1B
.org $001a ;1a
reti;rjmp INT_OVF1
.org $001c ;1c
;reti rjmp INT_OC0A
.org $001e ;1e
reti;rjmp INT_OC0B
.org $0020 ;20
reti;rjmp INT_OVF0
.org $0022 ;22
reti;rjmp INT_SPI
.org $0024 ;24
reti;rjmp INT_USART_RX
.org $0026 ;26
reti;rjmp INT_USART_UDRE
.org $0028 ;28
reti;rjmp INT_USART_TX
.org $002a ;2a
reti;rjmp INT_ADC
.org $002c ;2c
reti;rjmp INT_EE_Ready
.org $002e ;2e
reti;rjmp INT_ANALOG_COMP
reti ;11 keine 2wireRoutinen
reti ;a keine SPI Routinen
;***************************Init mit allem drumdran*****************
stack: ldi temp1,high(ramend) ;Stackpointer festlegen
out sph, temp1
ldi temp1,low(ramend) ;Stackpointer festlegen
out spl, temp1
rcall sram
; rcall lcd_init
; rcall lcd_clear
; rcall werbe1
; rcall werbe2
; rcall wait1s
; rcall leer_z
; rcall INIT_ext_Int01
; rcall deak_int01
; rcall INIT_PC_INTx
; rcall mode7_t0_init
; rcall prescaler_T0_on
; rcall mode4_t1_init
; rcall prescaler_T1_on
; rcall mode2_t2_init
; rcall prescaler_T2_on
; rcall adc_header
; rcall eeprom_init ;wenn ints bevorzugt werden
; rcall adr_cnt
; rcall eeprom_write
; rcall AC_init
; rcall ac_change
; rcall usart_init ;wenn INT bevorzugt dann hier aktivieren und prog erweitern
; rcall werbe_rs
rcall init_DrehEncoder
start: nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
rjmp start
;*********Sram clearen***********************************************
sram: clr temp0
ldi yl,low(SRAM_START)
ldi yh,high(SRAM_START) ;Masterclr des Sram's über
sram2: st y+,temp0 ;die indirekte Adressierung
cpi yl,$50 ;bis zur zelle x=$a0 löschen
brne sram2
ret
;*************************weitere*includedata***********************
;.include "AtMega328_adc_lst.asm"
;.include "AtMega328_analogcomparator.asm"
.include "AtMega328_ext_ints.asm"
;.include "AtMega328_eeprom.asm"
.include "AtMega328_timercounter.asm"
;.include "AtMega328_uart_std.asm"
;.include "AtMega328_LCD_Txt_out.asm"
;.include "AtMega328_RS_Txt_out.asm"
;.include "h:\etronik\Software3\sonstiges\origin\mathe.asm"
;.include "i:\etronik\Software3\sonstiges\origin\lcd_KS0066_KS0070_8bit.asm"
;.include "h:\etronik\Software3\sonstiges\origin\lcd_KS0066_KS0070_4bit_HapSim.asm" ;Nur zur Simulation mit HapSim aktivieren
;.include "h:\etronik\Software3\sonstiges\origin\zeitschleifen.asm"
;.include "h:\etronik\Software3\sonstiges\origin\hex_dez_wandlung.asm" ;gebraucht für LCD oder nur umwandlung
.include "h:\etronik\Software3\sonstiges\origin\DrehEncoder.asm"
;*************************ENDE**************************************
DrehEncoder.asm
Code:
;************ Drehencoder Zuordnung************
/*.equ DrehENC_ddr = ddrD
.equ DrehENC_port= Portd
.equ DrehENC_pin = PinD
.equ Phase_A = 2
.equ Phase_B = 3
.equ Taster_ENC = 4
*/
;Initialisierung Drehencoder
init_DrehEncoder:
; rcall mode2_t0_init ;*
; rcall prescaler_T0_on ;*
rcall INIT_EXT_INT01 ;**
rcall INIT_PC_INTx ;**
sbi DrehENC_port,Phase_A
sbi DrehENC_port,Phase_B
sbi DrehENC_port,Taster_ENC
;Test Ausgabe
sbi DrehENC_ddr,0
sbi DrehENC_ddr,1
;Test Ende
in temp0,DrehENC_pin
andi temp0,(1<<Phase_A | 1<<Phase_B)
sts dreh_ENC_old,temp0
sts dreh_Richt,temp0
in temp0,DrehENC_pin
andi temp0,(1<<Taster_ENC)
sts dreh_tast_old,temp0
ret
;Auswertung funktioniert für Interrupt und Timer
Dreh_ENCODER:
lds temp1,dreh_ENC_old
;mov temp1,temp2 ;Wert der letzten ISR
in temp0,DrehENC_pin ;Neuen Wert holen
;sbrs temp0,Taster_ENC ;* Abfrage Drucktaster mit Timer
;rjmp push_button ;* Ausführung beachten
andi temp0,$0C ;Nur PinX0 und 1 auswerten
sts dreh_ENC_old,temp0
; mov temp2,temp0 ;für nächste ISR merken
cp temp0,temp1 ;Alter und neuer Wert Vergleichen
breq Dreh_ENCODER_ende ;Wenn gleich, wude nicht gedreht
swap temp1 ;alter Wert ins obere Nibble ..
or temp0,temp1 ;.. und in einem Byte zusammenfassen
cpi temp0,$0C ;00>>11 neu
breq Dreh_ENCODER_ende
cpi temp0,$C0 ;11>>00 neu
breq Dreh_ENCODER_ende
;bei folgenden Kombinationen wurde nach links gedreht
;cpi temp0,$23 ;>>>8C 10(2,8) -- 11(3,C) <<<C8
cpi temp0,$8C ; links rechts
breq links
;cpi temp0,$31 ;>>>C4 11(3,C) -- 01(1,4) <<<4C
cpi temp0,$C4 ; links rechts
breq links
;cpi temp0,$10 ;>>>40 01(1,4) -- 00(0,0) <<<04
cpi temp0,$40 ; links rechts
breq links
;cpi temp0,$02 ;>>>08 00(0,0) -- 10(2,8) <<<80
cpi temp0,$08 ; links rechts
breq links
;Ansonsten wurde nach rechts gedreht, Fehler (z.B. von 00 nach 11) werden bei Auskommentierung unten
;als rechtsdrehung gewertet. Passiert nicht wenn die Abtastrate hoch genug ist.
; cpi temp0,$01 ;von 00(0) nach 01(1)
; breq rechts
; cpi temp0,$13 ;von 01(1) nach 11(3)
; breq rechts
; cpi temp0,$32 ;von 11(3) nach 10(2)
; breq rechts
; cpi temp0,$20 ;von 10(2) nach 00(0)
; breq rechts
rechts: ;lds temp3,dreh_Richt
;inc temp3 ;Richtung als Zahl verändern
;sts dreh_Richt,temp3
;lds temp3,dreh_Richt ;Drehrichtung nur als Bit setzen
;andi temp3,(0<<Phase_A | 0<<Phase_B) ;
;ori temp3,(1<<Phase_A | 0<<Phase_B) ;
;sts dreh_Richt,temp3 ;
sbi portd,0 ;test
cbi portd,1 ;test
ret
links: ;lds temp3,dreh_Richt ;Richtung als Zahl verändern
;dec temp3 ;
;sts dreh_Richt,temp3 ;
;lds temp3,dreh_Richt ; Drehrichtung nur als Bit setzen
;andi temp3,(0<<Phase_A | 0<<Phase_B) ;
;ori temp3,(0<<Phase_A | 1<<Phase_B) ;
;sts dreh_Richt,temp3 ;
sbi portd,1 ;test
cbi portd,0 ;test
ret
;wird angesprungen wenn es keine Veränderung des Drehencoders gab
Dreh_ENCODER_ende:
lds temp3,dreh_Richt ; Drehrichtung Bit löschen
andi temp3,(0<<Phase_A | 0<<Phase_B)
sts dreh_Richt,temp3
ret
;Achtung wenn über PinChangeIntXY gearbeitet wird, reagiert der
;PCI auf beide Flanken. Beim loslassen wird die Routine aufgerufen
;solange aber dreh_tast_old nicht zurückgesetzt wird
;wird dreh_tast_old nicht verändert
push_button:
lds temp1,dreh_tast_old
in temp0,DrehENC_pin ;** Neuen Wert holen
andi temp0,$10 ;Nur Taster abfragen
sts dreh_tast_old,temp0 ;NEU zu ALT
cp temp0,temp1 ;NEU vergleich ALT
breq push_button_end ;wenn gleich brech ab
swap temp1 ;Pegelwechsel
or temp0,temp1 ;erstellen
cpi temp0,$01 ;von 0(0) nach 1(1)
breq taster_an
cpi temp0,$10 ;von 1(1) nach 0(0)
breq taster_aus
push_button_end:
ret
taster_an:
ldi temp0,(1<<Taster_ENC)
sts dreh_tast_old,temp0
cbi portd,0
cbi portd,1
ret
taster_aus:
ret
- - - Aktualisiert - - -
AtMega328_ext_ints.asm
Code:
;PD2/3 sind INT0/1
INIT_EXT_INT01:
rcall int0_sc_any_cha ;INT 0 Flanke
rcall int1_sc_any_cha ;INT 1 Flanke
rcall INT01_on ;INT 01 on
sei ;global int
ret
INT01_on:
in temp0,EIMSK
ori temp0,(1<<INT1|1<<INT0) ;beide INTs aktiv
out EIMSK,temp0
ret
INT01_off:
lds temp0,EIMSK
andi temp0,(0<<INT1|0<<INT0) ;beide INTs aktiv
sts EIMSK,temp0
ret
INT_EX0:rcall Dreh_ENCODER
reti
INT_EX1:rcall Dreh_ENCODER
reti
;**************Int0 Trigger************
int0_sc_low_level:
lds temp0,EICRA
ori temp0,(0<<ISC01|0<<ISC00) ;hier INT0/1 auf steigende flanke siehe PDF KAP.13
sts EICRA,temp0
ret
int0_sc_any_cha:
lds temp0,EICRA
ori temp0,(0<<ISC01|1<<ISC00) ;hier INT0/1 auf steigende flanke siehe PDF KAP.13
sts EICRA,temp0
ret
int0_sc_falling:
lds temp0,EICRA
ori temp0,(1<<ISC01|0<<ISC00) ;hier INT0/1 auf steigende flanke siehe PDF KAP.13
sts EICRA,temp0
ret
int0_sc_rising:
lds temp0,EICRA
ori temp0,(1<<ISC01|1<<ISC00) ;hier INT0/1 auf steigende flanke siehe PDF KAP.13
sts EICRA,temp0
ret
;**************Int1 Trigger************
int1_sc_low_level:
lds temp0,EICRA
ori temp0,(0<<ISC11|0<<ISC10) ;hier INT0/1 auf steigende flanke siehe PDF KAP.13
sts EICRA,temp0
ret
int1_sc_any_cha:
lds temp0,EICRA
ori temp0,(0<<ISC11|1<<ISC10) ;hier INT0/1 auf steigende flanke siehe PDF KAP.13
sts EICRA,temp0
ret
int1_sc_falling:
lds temp0,EICRA
ori temp0,(1<<ISC11|0<<ISC10) ;hier INT0/1 auf steigende flanke siehe PDF KAP.13
sts EICRA,temp0
ret
int1_sc_rising:
lds temp0,EICRA
ori temp0,(1<<ISC11|1<<ISC10) ;hier INT0/1 auf steigende flanke siehe PDF KAP.13
sts EICRA,temp0
ret
;*******************Pin Change Interrupt*********************************************
INIT_PC_INTx:
rcall INIT_PC_INTx_port ;2=(23:16),1=(14:8),0=(7:0)
;rcall PCIE0_active
;rcall PCIE1_active
rcall PCIE2_active
sei
ret
INIT_PC_INTx_port:
lds temp0,PCICR ;Hier Portbereich wählen
ori temp0,(1<<PCIE2|0<<PCIE1|0<<PCIE0) ;2=(23:16),1=(14:8),0=(7:0)
sts PCICR,temp0
ret
INIT_PC_INTx_deakt:
lds temp0,PCICR
andi temp0,(0<<PCIE2|0<<PCIE1|0<<PCIE0) ;Hier Portbereich wählen
sts PCICR,temp0 ;2=(23:16),1=(14:8),0=(7:0)
ret
PCIE0_active:
lds temp0,PCMSK0
ori temp0,(0<<PCINT7 | 0<<PCINT6 | 0<<PCINT5| 0<<PCINT4 | 0<<PCINT3 | 0<<PCINT2 | 0<<PCINT1 | 0<<PCINT0)
sts PCMSK0,temp0
ret
PCIE1_active:
lds temp0,PCMSK1
ori temp0,(0<<PCINT14 | 0<<PCINT13 | 0<<PCINT12 | 0<<PCINT11 | 0<<PCINT10 | 0<<PCINT9 | 0<<PCINT8)
sts PCMSK1,temp0
ret
PCIE2_active:
lds temp0,PCMSK2
ori temp0,(0<<PCINT23 | 0<<PCINT22 | 0<<PCINT21 | 1<<PCINT20 | 0<<PCINT19 | 0<<PCINT18 | 0<<PCINT17 | 0<<PCINT16)
sts PCMSK2,temp0
ret
;********PullUPs aktivieren******************************************************************
PCIE0_07_pullup_on:
in temp0,portb
ori temp0,(0<<PCINT7 | 0<<PCINT6 | 0<<PCINT5| 0<<PCINT4 | 0<<PCINT3 | 0<<PCINT2 | 0<<PCINT1 | 0<<PCINT0)
out portb,temp0
ret
PCIE1_814_pullup_on:
in temp0,portc
ori temp0,(0<<PCINT14 | 0<<PCINT13 | 0<<PCINT12 | 0<<PCINT11 | 0<<PCINT10 | 0<<PCINT9 | 0<<PCINT8)
out portc,temp0
ret
PCIE2_1622_pullup_on:
in temp0,portd
ori temp0,(0<<PCINT23 | 0<<PCINT22 | 0<<PCINT21 | 0<<PCINT20 | 0<<PCINT19 | 0<<PCINT18 | 0<<PCINT17 | 0<<PCINT16)
out portd,temp0
ret
PCIE0_07_pullup_off:
in temp0,ddrb
andi temp0,(0<<PCINT7 | 0<<PCINT6 | 0<<PCINT5| 0<<PCINT4 | 0<<PCINT3 | 0<<PCINT2 | 0<<PCINT1 | 0<<PCINT0)
out ddrb,temp0
ret
PCIE1_814_pullup_off:
in temp0,ddrc
andi temp0,(0<<PCINT14 | 0<<PCINT13 | 0<<PCINT12 | 0<<PCINT11 | 0<<PCINT10 | 0<<PCINT9 | 0<<PCINT8)
out ddrc,temp0
ret
PCIE2_1622_pullup_off:
in temp0,ddrd
andi temp0,(0<<PCINT23 | 0<<PCINT22 | 0<<PCINT21 | 0<<PCINT20 | 0<<PCINT19 | 0<<PCINT18 | 0<<PCINT17 | 0<<PCINT16)
out ddrd,temp0
ret
;*********************Interrupthandler*************************************************
INT_PC0: ;PC_INT0:7
reti
INT_PC1: ;PC_INT8:14
reti
INT_PC2:rcall push_button ;** PC_INT16:23
reti
Lesezeichen