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
DrehEncoder.asmCode:;######################################################## ;# 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**************************************
- - - Aktualisiert - - -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
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







Zitieren

Lesezeichen