Sie sind nicht angemeldet.

1

Freitag, 22. Mai 2020, 12:08

ATtiny13A: HESUNSE (CY800) Funksteckdosenprotokoll auswerten

Hallo zusammen,

ich war auf der Suche nach einer günstigen Funksteckdosenfernbedienung mit 4 Empfängern. Ein Empfänger in Reserve ist ja auch nicht schlecht, deshalb hab ich mich für dies entschieden :

Hesunse 2/3/4/5 Ways Digital RF Wireless Remote Control Switch 220V Receivers:

https://www.youtube.com/watch?v=n7p5oDoknxA

Blöderweise gibt es zwei Dinge die mich stören.

1. Beim Anlegen der Spannung schalten die Empfänger
2. Es ist ein Relais mit Schließer verbaut.



Das erste Problem ist zwar störend, da ich erstmal alle nicht benötigten Empfänger ausschalten könnte, aber ich benötige ein Wechsler-Relais.
Also fing ich an dass Ganze auf Umbaumöglichkeiten hin zu untersuchen.




















Ein Wechsler-Relais einzubauen, war mir zu gefährlich, da der Kontakt zu nahe an den 24V war.
Wäre eigentlich egal, da dass ganze eh nicht galvanisch getrennt ist.
Da dachte ich mir, dass ich selber eine Platine entwickle die dann auch nicht sofort beim Anlegen der Spannung schaltet. Also ging es erstmal darum überhaupt herauszufinden wie das Ganze funktioniert. Geholfen hat mir dabei in erster Linie diese Seite :

http://avr.börke.de/Funksteckdosen.htm

Mit meinen ersten Fragen startete ich in diesem Forum :

https://www.mikrocontroller.net/topic/487338#6099487

und wechselte dann lieber hierhin, da mir dort besser geholfen wurde :

https://www.roboternetz.de/community/thr…ll=1#post659655

Der Code ist in AVR8ASM im Atmel Studio 7 ( AS7 ) geschrieben und daher nicht jedermans Sache. Ich selber konnte auch nur mit der Hilfe eines PAP's ( Programmablaufplanes ) noch einigermaßen durchblicken, was ich da fabriziert habe.


















Hier mal ein Ausschnitt und die Quelle des verwendeten kostenlosen PAP-Designers :





https://www.heise.de/download/product/papdesigner-51889


So, jetzt ist erstmal genung.


_Machtwas_
CRS Robotics A255, TRONXY X3A, TinkerCAD, c´t-Lab, ProfiLab Expert, AVR8 Assembler

2

Montag, 25. Mai 2020, 10:49

Empängermodul CY800 ( ? ) und Amplituden Shift Keying ( ASK ) bzw. ON-OFF-Keying ( OOK )

Die Recherchen ergaben, dass es sich bei dem Empfänger vermutlich um den Baustein CY800 handelt, der mit einem 6,7458Mhz Quarz betrieben wird.

















Der Sender sendet vermutlich per Amplituden Shift Keying ( ASK ) bzw. ON-OFF-Keying ( OOK ).




Am Data-Pin des Moduls ( IN/Data ) ist auf jedenfall ohne dass eine Taste gedrückt wurde, folgendes Signal zu sehen gewesen. Das Monoflop-Signal erstmal nicht beachten :



Meine nächtse Idee war, wenn ich es schon neu mache, dass es auch stromsparend für einen evtl. Batteriebetrieb sein sollte. Aus dem stromsparensten Mode des ATtiny13A, dem PowerDown, kommt man außer mit den verschiedenen Resets, mit dem Pin Change Interrupt ( PCINT0 ), dem Level Interrupt ( INT0 ) oder dem Watchdog Interrupt ( WDT ) heraus. Ich entschied mich für den PCINT0, da der INT0 für die Erkennung der steigenden Flanke der Datenelemente benötigt wird. Damit der µC nicht ständig durch den PCINT0 aus seinem Tiefschlaf gerissen wird, habe ich ein retriggerbares Monoflop ( CD4538B ) eingebaut und dadurch kann der µC so lange schlafen, bis er vom Monoflop ( MF ), welches nun nicht mehr nachgetrigert wird, durch die fallende Flanke am PCINT0-Pin geweckt wird. Tiefer in die Analen des Stromsparens bin ich nicht eingedrungen, da dass ganze Projekt viel, viel länger dauerte als mir lieb war und ich es für dieses Projekt gar nicht brauche.

Wenn zum Beispiel die Taste A auf der Fernbedienung gedrückt wird, sieht dass Ganze dann so im Logic Analyser ( LA ) aus :

Die deutlich zu erkennenden Lücken zwischen den Paketen, nutze ich als Erkennung dass der Anfang eines Datenpaketes bevorsteht und der µC dadurch so lange schlafen kann, bis er vom Monoflop ( MF ), welches nun nicht mehr nachgetrigert wird, durch die fallende Flanke am PCINT0-Pin geweckt wird.

Dekodiert sieht dass Ganze dann so aus:



Und ein Datenpaket im Detail so :

Es sind 3 verschiedene Datenelemente ( 0, 1, f ) und ein Synchronisierimpuls ( Sync ) zu erkennen. Auch zu sehen ist dass so ein Datenpaket aus 12 Datenelementen besteht. Eine 0 wird durch zwei mal 1/4 High und 3/4 Low gekennzeichnet. Eine 1 durch zwei mal 3/4 High und 1/4 Low und dass f durch eine Kombination der beiden ( 0 & 1 ). Ein mal 1/4 High und 3/4 Low, sowie ein mal 3/4 High und 1/4 Low. Der Synchronisierungsimpuls besteht aus ein mal High und einunddreißig mal Low. Dies sind die idealen Werte. Ich habe also überlegt, wie ich dies nun verarbeiten soll. Meine Idee war es nach jeder steigenden Flanke eines Datenelementes die eingetragene Zeit zu nehmen ( wieder als ideal anzusehen ) und als Einlesezeitpunkt zu gebrauchen. Somit kam ich darauf 24 Abtastungen zu machen, da jeweils ein Datenelement aus zwei " Bits " besteht.
CRS Robotics A255, TRONXY X3A, TinkerCAD, c´t-Lab, ProfiLab Expert, AVR8 Assembler

3

Mittwoch, 27. Mai 2020, 15:46

Anfang der Programmumsetzung

Zu Beginn erfolgt die Intialsierungsprozedur, wo unter anderem, alles vorbereitet wird damit der µC zuerst in den SLEEP-Mode -> PowerDown geht und durch den PCINT0-IRQ, den das regtriggerbare MF erzeugt, aus diesem geweckt werden kann. Um einen Kompromiss zwischen stromsparen und schnell genug reagieren zu können, wird für die INT0-IRQ Initialisierung, der Systemtakt auf nominal 600kHz eingestellt.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
;
;IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
;IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
;I Erstinitialisierungen
;IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
;IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
;
_reset:
;
;Systemtakt ( 4,8MHz ) durch 8 teilen ( 600kHz = 1,666µs )
;
 ldi  a,1<<CLKPCE           ;Im Clock Prescaler Register Bit..
 out  CLKPR,a               ;..Clock Prescaler Change Enable setzen..
 ldi  a,1<<CLKPS1|1<<CLKPS0 ;..und CLKPS[3:0] loeschen (Sicherheitsprozedur)..
 out  CLKPR,a               ;..nun mit CLKPCE=0 und CLKPS[3:0] SYS-Takt aendern
;
;Stapelzeiger initialisieren (fuer Unterprogramme und / oder Interrupts)
;
 ;ldi  a,High(RAMEND)        ;RAMEND, also das Ende vom SRAM, ist in der.. 
 ;out  SPH,a                 ;..Definitions-datei festgelegt  
 ldi  a,Low (RAMEND)        ;Hier reicht ein Byte, weil das...
 out  SPL,a                 ;...SRAM nur 64Byte gross ist
;
;Variablen initialisieren ( r0-r31 haben unbestimmten Inhalt )
;
 clr  flag_reg              ;Allgemeines Flaggenregister loeschen
;
;Die drei Bytes des CY800-Protokolls loeschen
;
 clr  byte_2                ;Die 3..
 clr  byte_1                ;..Bytes..
 clr  byte_0                ;..loeschen
;
;Bitzaehler auf 24 Bits einstellen
;
 ldi  bit_zlr,#bit_zlr     ;Wert f. Bitzaehler laden..
;
;Codeadresse fuer Taste A laden
;
 ldi  zh,high(_code*2)      ;Z-Zeiger mit Vergleichscode-Adresse..
 ldi  zl,low (_code*2)      ;..laden
;
;Vergleichszaehler f. 3x hintereinander gueltigen Code 
;
 ldi  a,#vergleichs_zlr     ;..Vergleichszaehler..
 mov  vergleichs_zlr,a      ;..laden
;
;Sleep-Mode -> Power Down gewuenscht
; 
 sbr  flag_reg,1<<pdm       ;Power-Down-Mode FLAG setzen
;
;Ports Erstkonfiguration
; 
 sbi   DDRB,led.pla			;PORT-Bit als Ausgang f. PLA-LED
 sbi   DDRB,led.ora			;PORT-Bit als Ausgang f. SLEEP-LED
 sbi   DDRB,led.ge          ;PORT-Bit als Ausgang f. TEST-LED

 sbi   LED_PORT,led.ora     ;LED-Orange ausschalten
;
;PCINT0-IRQ einrichten
;
 in   a,PCMSK               ;Pin Change Mask Register laden..
 sbr  a,1<<PCINT0           ;..den Pin Change Enable Mask 1..
 out  PCMSK,a               ;..auswaehlen
 in   a,GIMSK               ;General Interrupt Mask Register laden..
 sbr  a,1<<PCIE             ;..Pin Change Interrupt Enable Bit setzen..
 out  GIMSK,a               ;..und somit den PCI1-IRQigeben
 ldi  a,1<<PCIF             ;Pin Change Interrupt Flag im..          
 out  GIFR,a                ;..General Interrupt Flag Register laden loeschen
 sei                        ;Alle programmierbaren Interrupts freigeben


Die Hauptprogrammschleife ( _main: ), besteht praktisch nur darin, zu unterscheiten, ob der der µC in den PowerDown,- oder ILDE-Mode versetzt werden soll. Die LED-Orange ist praktisch der Ausgang und wurde hier Testweise benutzt, um anzuzeigen, wenn in einem der SLEEP-Modes eingetreten wurde.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
;
;HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
;HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
;H Hauptprogrammschleife
;HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
;HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
;
_main:
 ;
 ;SLEEP-Mode ausschalten und auf Werkseinstellung setzen
 ;
 in   a,MCUCR				;MCU Control Register laden und..
 cbr  a,1<<SE|1<<SM1|1<<SM0	;..auf Werkseinstellung..
 out  MCUCR,a				;..setzen
;
;Pruefen welcher Sleep-Mode drann ist
; 
 sbrs flag_reg,pdm		    ;Power-Down-Mode erwuenscht?
 rjmp _idle 				;Nein -> µC in IDLE-Mode versetzen
;
;SLEEP-MODE -> Power Down
;

 ;cbi  PORTB,led.ora         ;LED-Orange einschalten T E S T Z W E C K E ###########################
 ;sbi  PORTB,led.ora         ;LED-Orange ausschalten T E S T Z W E C K E ###########################
 ;cbi  PORTB,led.ora         ;LED-Orange einschalten T E S T Z W E C K E ###########################

 in   a,MCUCR				;MCU Control Register laden..
 sbr  a,1<<SE|1<<SM1	    ;..Power-Down-Mode und Sleep Enable vorbereiten..
 out  MCUCR,a				;..und freigeben
 sleep						;µC in den Schlaf-Modus versetzen
 
 rjmp _main                 ;Arbeitsschleife ausfuehren
;
;SLEEP-MODE -> IDLE
;
_idle: 
 
 ;sbi  PORTB,led.ora		 ;LED Orange ausschalten T E S T Z W E C K E ###########################
 ;cbi  PORTB,led.ora         ;LED-Orange einschalten T E S T Z W E C K E ###########################
 ;sbi  PORTB,led.ora         ;LED-Orange ausschalten T E S T Z W E C K E ###########################

 in   a,MCUCR				;MCU Control Register laden(IDLE ist vorgegeben)..
 sbr  a,1<<SE		        ;..Sleep Enable vorbereiten..
 out  MCUCR,a				;..und freigeben
 sleep
 
 rjmp _main                 ;Arbeitsschleife ausfuehren


Im Pin Change Interrupt0 ( PCIN0 ) wird dieser erstmal gesperrt, angezeigt dass der SLEEP-Mode in IDLE geändert werden soll, weil der in dieser Routine initialisierte INT0-IRQ mit seiner steigenden Flanke, den µC nicht mehr aus dem PowerDown holen kann.
Jetzt kann auch der Systemtakt heruntergeteilt werden ( spart Strom ), da ja eh nach jeder steigenden Flanke zu Beginn eines jeden Datenelementes, ideal gesehen 550µs vergehen müssen, bis der dann vorliegende Signalpegel im Timer/Counter0 Overflow Interrupt eingelesen wird. Hier wird auch schon mal die Zeit für den später in der INT0-ISR inititalierten Timer/Counter0 Interruppt eingestellt, die die Hauptarbeit macht und erst im nächsten Posting besprochen wird.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
;
;QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
; PIN CHANGE INTERRUPT 0
;QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
;
_PCI0addr:
 
 ;sbi  LED_PORT,led.ge       ;LED-Gelb einschalten T E S T Z W E C K E #############################
 ;cbi  LED_PORT,led.ge       ;LED-Gelb ausschalten T E S T Z W E C K E #############################
 ;sbi  LED_PORT,led.ge       ;LED-Gelb einschalten T E S T Z W E C K E #############################
 ;cbi  LED_PORT,led.ge       ;LED-Gelb ausschalten T E S T Z W E C K E #############################
   
 in   s_sreg,SREG           ;CPU-Statusregister sichern 
;
;PCINT0 Interrupt sperren
; 
 in   ia,GIMSK				;General Interrupt Masken Register laden und..
 cbr  ia,1<<PCIE 			;..Pin Change Interruput 0 Freigabebit loeschen..
 out  GIMSK,ia				;..und somit die PCI0-IRQ sperren
; 
;Power-Down-Mode sperren
;
 cbr  flag_reg,1<<pdm       ;Power-Down-Mode FLAG loeschen
;
;INT0 Interrupt auf steigende Flanke einstellen
;
 in   ia,MCUCR              ;MCU Control Register laden..
 sbr  ia,1<<ISC01|1<<ISC00  ;..die steigende Flanke einstellen und dies..
 out  MCUCR,ia              ;..nun uebernehmen, nun dass..
 in   ia,GIMSK              ;..General Interrupt Mask Register  laden, dort..
 sbr  ia,1<<INT0            ;..dass External Interrupt Request 0 Enable bit..
 out  GIMSK,ia              ;..setzen und somit den INT0-IRQ freigeben..
 ldi  ia,1<<INTF0           ;..Nun dass External Interrupt Flag 0 Bit..
 out  GIFR,ia               ;..im General Interrupt Flag Register loeschen
;
;Systemtakt ( 4,8MHz ) durch 16 teilen ( 300kHz = 3,333µs )
;
 ldi  ia,1<<CLKPCE           ;Im Clock Prescaler Register Bit..
 out  CLKPR,ia               ;..Clock Prescaler Change Enable setzen..
 ldi  ia,1<<CLKPS2           ;..Sicherheitsprozedur nun mit CLKPCE=0 und
 out  CLKPR,ia               ;..CLKPS[3:0] SYS-Takt aendern, abschliessen
;
;Timer/Counter0 Zaehlregister fuer die Biterfassung einstellen
; 
 ldi  ia,$FF-#top           ;Wert f. TOV0-IRQ ( Normal- Mode )..
 out  TCNT0,ia              ;..ins Timer/Counter0 Zaehlregister laden

_exit_PCI0addr:
 out  SREG,s_sreg           ;Statusregister restaurieren

 ;sbi  LED_PORT,led.ge       ;LED-Gelb einschalten T E S T Z W E C K E #############################
 ;cbi  LED_PORT,led.ge       ;LED-Gelb ausschalten T E S T Z W E C K E #############################
 ;sbi  LED_PORT,led.ge       ;LED-Gelb einschalten T E S T Z W E C K E #############################
 ;cbi  LED_PORT,led.ge       ;LED-Gelb ausschalten T E S T Z W E C K E #############################
 
 reti						;_PCI0addr ISR verlassen

In der INT0-ISR passiert auch nicht viel und wie üblich dieser erstmal zu Beginn gesperrt. Der Timer/Counter0 wird in den Normalmode versetzt bzw. dies ist schon die Werkseinstellung, sowie die T/C0 Overflow Interrupt ohne Vorteiler initialisiert und dadurch gleichzeitig der Timer0 gestartet.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
;
;QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
; INTERRUPT REQUEST 0 INT0 
;QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
;
_INT0addr:	
 
 ;sbi  LED_PORT,led.ge       ;LED-Gelb einschalten T E S T Z W E C K E #############################
 ;cbi  LED_PORT,led.ge       ;LED-Gelb ausschalten T E S T Z W E C K E #############################
 
 in   s_sreg,SREG           ;CPU-Statusregister sichern 
;
;INT0 Interrupt sperren
;
 in   ia,GIMSK              ;General Interrupt Mask Register laden..
 cbr  ia,1<<INT0            ;..INT0 Interrupt sperren vorbereiten und..
 out  GIMSK,ia              ;..ausfuehren..
;
;Timer/Counter0 Overflow Interrupt ( TOV0-IRQ ) einrichten
;
 in   ia,TIMSK0              ;Timer/Counter0 Interrupt Mask Register laden und.. 
 sbr  ia,1<<TOIE0            ;..Timer/Counter0 Overflow Interrupt Enable setzen..
 out  TIMSK0,ia              ;..somit den TOV0-IRQ ermoeglichen
 ldi  ia,1<<TOV0             ;Nun dass Timer/Counter0 Overflow Flag im..
 out  TIFR0,ia               ;..Timer/Counter0 Interrupt Flag Register loeschen..
 in   ia,TCCR0B              ;..dass Timer/Counter0 Control Register B laden..
 sbr  ia,1<<CS00             ;..Clock Select = 1:1 einstellen..
 out  TCCR0B,ia              ;..und den T/C0 gleichzeitig starten

_exit_INT0addr:
 out  SREG,s_sreg           ;Statusregister restaurieren
 
 ;sbi  LED_PORT,led.ge       ;LED-Gelb einschalten T E S T Z W E C K E #############################
 ;cbi  LED_PORT,led.ge       ;LED-Gelb ausschalten T E S T Z W E C K E #############################
  
 reti                       ;_INT0addr ISR verlassen
























_Machtwas_
CRS Robotics A255, TRONXY X3A, TinkerCAD, c´t-Lab, ProfiLab Expert, AVR8 Assembler

4

Gestern, 16:39

Timer/Counter0 Overflow ISR: Bits erfassen und den Ausgang umschalten

Die Timer/Counter0 Interrupt-ISR ist ziemlich verzweigt und einigermaßen komplex. Den kompletten PAP hierzu als Screenshot darzustellen ist also zu unleserlich. Ich habe ihn deshalb zerstückelt hier dargestellt, um die jeweiligen Codesequenzen besser erklären zu können. Auch der Code ist so zusammengestückelt. Wer also den PAP in seiner vollen " Schönheit " sehen möchte, sollte sich dieses hierzu benötigte Programm herunterladen und wenn ich mal alles hier Hochgeladen habe, ansehen.

Der Signalpegel wird nun erfasst ( CY800-Bits erfassen ) und dieses Bit dann innerhalb der 3 Bytes ( 24Bits ) positioniert ( Bits zusammenfassen ). Danach wird überprüft, ob alle Bits erfasst sind und wenn nicht, dann wird die INT0-IRQ für die Erfassung des nächsten Datenelementpegels wieder aktiviert. Hiernach wird der Timer0 erstmal wieder gestoppt und für den nächsten Zeitpunkt des Überlaufs, dass Timer Counter0 Zählregister eingestellt. Scharf gemacht wird ja die T/C0-Overflow-IRQ dann wieder in der INT0-ISR.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
;670 im Windows Editor
;QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
; Timer0 Overflow ISR ( Interrupt Service Routine )
;QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
;
_OVF0addr:
 in   s_sreg,SREG           ;CPU-Statusregister sichern 
 
 ;sbi  LED_PORT,led.pla      ;LED-PLA einschalten T E S T Z W E C K E ##############################
 ;cbi  LED_PORT,led.pla      ;LED-PLA ausschalten T E S T Z W E C K E ##############################

;
;CY800-Bits erfassen
; 
 sec			   ;High-Bit vorgeben
 sbis CY800_PIN,cy800.data ;CY800 Signalpin = 1 ?..			   
 clc			   ;..Nein -> Bit = 0 setzen
;
;Bits zusammenfassen
;
 rol  byte_0	           ;Carry-Bit und weitere Bits links rotieren..
 rol  byte_1		   ;Carry-Bit und weitere Bits links rotieren
 rol  byte_2		   ;Carry-Bit und weitere Bits links rotieren..
 dec  bit_zlr		   ;Bitzaehler um eins verringern
 brne _next_bit		   ;Alle 24 Bits erfasst? NEIN -> springen..
;
;INT0 Interrupt auf steigende Flanke einstellen
;
_next_bit:
 in   ia,MCUCR              ;MCU Control Register laden..
 sbr  ia,1<<ISC01|1<<ISC00  ;..die steigende Flanke einstellen und dies..
 out  MCUCR,ia              ;..nun uebernehmen, nun dass..
 in   ia,GIMSK              ;..General Interrupt Mask Register  laden, dort..
 sbr  ia,1<<INT0            ;..dass External Interrupt Request 0 Enable bit..
 out  GIMSK,ia              ;..setzen und somit den INT0-IRQ freigeben..
 ldi  ia,1<<INTF0           ;..Nun dass External Interrupt Flag 0 Bit..
 out  GIFR,ia               ;..im General Interrupt Flag Register loeschen

 rjmp _timer_stopp          ;
;
;Timer/Counter0 stoppen.
;
_timer_stopp: 
 in   ia,TCCR0B             ;..dass Timer/Counter0 Control Register B laden..
 cbr  ia,1<<CS02|1<<CS01|1<<CS00;..Clock Select = T/C0 stopp einstellen..
 out  TCCR0B,ia             ;..und nun den T/C0 stoppen
;
;Timer/Counter0 Zaehlregister fuer die Biterfassung einstellen
; 
 ldi  ia,$FF-#top           ;Wert f. TOV0-IRQ ( Normal- Mode )..
 out  TCNT0,ia              ;..ins Timer/Counter0 Zaehlregister laden
;
;Timer/Counter0 Overflow ISR verlassen
; 
_exit_OVF0addr:             ;Timer0 Overflow ISR verlassen
 out  SREG,s_sreg           ;Statusregister restaurieren
 
 reti                       ;_OVF0addr ISR verlassen



Hier wird der Pfad erklärt, falls der richtige Code, drei mal, direkt hintereinander erkannt wurde.

Wenn alle 24-Bits erfasst wurden, wird erstmal der Bitzähler wieder neu geladen und der Code im Programmspeicher, für die Taste A, mit den drei Bytes verglichen.

Es wird eine Pausenzeit geladen, deren Zweck ich zum Schluß erkläre.

Jetzt wird geschaut ob die Empfangenen Bits den dreimaligen Vergleich hinter sich haben und falls nicht, der Vergleichszähler aktualisiert.

Nun wird überprüft, ob zum ersten Mal die Bytes, dreimal direkt hintereinander, mit dem Code übereinstimmten, daraufhin halt einmalig der Ausgang umgeschaltet und danach, wie bei den beiden anderen Verzweigungen, zu dem Pfad für ein neues Paket gesprungen.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 brne _next_bit		    ;Alle 24 Bits erfasst? NEIN -> springen..
;
;Bitzaehler auf 24 Bits einstellen
;
 ldi  bit_zlr,#bit_zlr      ;Wert f. Bitzaehler laden..
;
;CY800-Paket vergleichen
;
 lpm  code,Z+               ;Code-Byte2 laden und Zeiger inkrementieren..
 cp   code,byte_2           ;..beide Bytes vergleichen..
 brne _ungueltig            ;Der Code stimmt nicht -> springen
 lpm  code,Z+               ;Code-Byte1 laden und Zeiger inkrementieren..
 cp   code,byte_1           ;..beide Bytes vergleichen..
 brne _ungueltig            ;Der Code stimmt nicht -> springen
 lpm  code,Z                ;Code-Byte0 laden..
 cp   code,byte_0           ;..beide Bytes vergleichen..
 brne _ungueltig            ;Der Code stimmt nicht -> springen
;
;Pausenzeit laden
;
 ldi  ia,#pausenzeit
 mov  pausenzeit,ia
;
;Pruefen ob alle 3 Bytes, 3 mal direkt hintereinander gleich waren
;bzw. der Vergleichszaehler 0 ist
; 
 tst  vergleichs_zlr        ;3x positiver Vergleich?..
 breq _neues_paket          ;..JA -> Auf ein neues Paket vorbereiten
;
;Vergleichszaehler dekrementieren
;
 dec  vergleichs_zlr        
 breq _umschalten           ;Code akzeptiert -> Ausgang toggeln

 rjmp _neues_paket          ;Auf ein neues Paket vorbereiten
;
;Ausgang Umschalten
; 
_umschalten:
 
 sbi  LED_PIN,led.ora       ;LED-Orange toggeln T E S T Z W E C K E #############################
 
 rjmp _neues_paket          ;Auf ein neues Paket vorbereiten
Der Vergleichzähler erfüllt in diesem Pfad eine Doppelfunktion. Zum einen zählt er die Anzahl der positiven Vergleiche und zum Anderen verhindert dieser nach Ablauf ( Vergleichzähler = 0 ), dass der Ausgang immer wieder umschaltet, solange der Taster betätigt ist.
Die Pausenzeit dient der Erkennung, dass innerhalb einer Zeit von ca. einer Sekunde, kein einziges Mal ein gültiger Code empfangen wurde, was einer losgelassenen Taste, für mindestens dieser Zeit entspricht. Der Ausgang kann also frühestens nach dieser Zeit, durch einen erneuten Tastendruck umgeschaltet werden.

_Machtwas_
CRS Robotics A255, TRONXY X3A, TinkerCAD, c´t-Lab, ProfiLab Expert, AVR8 Assembler

5

Heute, 11:42

Timer/Counter0 Overflow ISR: Bits ungültig und ein paar Screenshots vom Logic Analyser

Da die Verarbeitungsbreite der CPU ein Byte ist, wird bereits nach einem nicht mit dem Code übereinstimmendem Byte hierher verzweigt. Vielleicht ginge es auch bitweise, aber das bringt ja nichts, da der Vergleich erst stattfindet, wenn alle drei Bytes bereits eingelesen sind.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
;650,460
;CY800-Paket vergleichen
;
 lpm  code,Z+               ;Code-Byte2 laden und Zeiger inkrementieren..
 cp   code,byte_2           ;..beide Bytes vergleichen..
 brne _ungueltig            ;Der Code stimmt nicht -> springen
 lpm  code,Z+               ;Code-Byte1 laden und Zeiger inkrementieren..
 cp   code,byte_1           ;..beide Bytes vergleichen..
 brne _ungueltig            ;Der Code stimmt nicht -> springen
 lpm  code,Z                ;Code-Byte0 laden..
 cp   code,byte_0           ;..beide Bytes vergleichen..
 brne _ungueltig            ;Der Code stimmt nicht -> springen
;
;Das Paket passt nicht zum Code
;
_ungueltig:

 ;cbi  LED_PORT,led.pla       ;LED-PLA ausschalten T E S T Z W E C K E #############################
 
 ;sbi  LED_PORT,led.pla       ;LED-PLA einschalten T E S T Z W E C K E #############################
 ;cbi  LED_PORT,led.pla       ;LED-PLA ausschalten T E S T Z W E C K E #############################
 
 ;sbi  LED_PORT,led.pla       ;LED-PLA einschalten T E S T Z W E C K E #############################
 ;cbi  LED_PORT,led.pla       ;LED-PLA ausschalten T E S T Z W E C K E #############################
 
 ;sbi  LED_PORT,led.pla       ;LED-PLA einschalten T E S T Z W E C K E #############################
 ;cbi  LED_PORT,led.pla       ;LED-PLA ausschalten T E S T Z W E C K E #############################

;
;Pruefen ob alle 3 Bytes 3 mal direkt hintereinander gleich waren
;bzw. der Vergleichszaehler 0 ist
; 
 tst  vergleichs_zlr        ;3x positiver Vergleich?..
 breq _pausenzeit           ;..JA -> Pausenzeit -1
;
;Vergleichszaehler laden f. Erkennung dass der Code 3x hintereinander 
;OK war
;
_vgz_laden: 
 ldi  ia,#vergleichs_zlr    ;..Vergleichszaehler..
 mov  vergleichs_zlr,ia     ;..laden
;
;Alles fuer die Erfassung eines neuen CY800-Paketes veranlassen
;
_neues_paket:

Zur Signalisierung dass die eingelesenen Bits nicht mit dem Code im Programmspeicher übereinstimmen, wird per LED-PLA ( was ich meistens als Programm Lauf Anzeige nutze ), dies mit drei Impulsen kenntlich gemacht.

Jetzt gilt es, mit der Hilfe einer weiteren Funktion des Vergleichszählers zu ermitteln, ob die Bits deshalb ungültig sind, weil die Taste losgelassen wurde oder ob eine sonstige Störung beim Einlesen der vierundzwanzig Bitpegel vorlag. Bei einer Störung oder wenn halt noch nicht die 3 Bytes, drei mal direkt hintereinander gültig waren, ist der der Vergleichszähler ungleich Null und wird zurückgesetzt ( Neu geladen ). Dieses Rücksetzen vom Vergleichszähler dient der Realisierung der Funktion, um zu erkennen dass dreimal direkt hintereinander, die 3 Bytes mit dem Code übereinstimmten.

Wenn die Taste losgelassen wurde, dürfte es nie dazukommen, dass die Bytes dem Code entsprechen und die Pausenzeit kann ablaufen. Als Zeiteinheit wird einfach die Zeit genommen, die es dauert bis alle 24-Bits eingelesen wurden. Also 24 mal der Aufruf der T/C0 Overflow-ISR, mal einem Faktor, um ca. eine Sekunde hinzubekommen. Falls die Pausenzeit noch nicht abgelaufen ist, wird einfach so vorgegangen, wie es üblich ist, um dass nächste Bit ( Datenelement ) einzulesen ( _next_bit: ). Der Vergleichzähler bleibt also bei Null stehen.

Beim erreichen des Pausenzeitendes, wird alles so vorbereitet dass ein neues Datenpaket erfasst werden kann.

Ein dekremieren des Pausenzählers erfolgt nur einmal. Habe es nur hierhin geschoben um die Orientierung zu verbessern ( Pausenzeit -1 ).

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
;670,610
;Alles fuer die Erfassung eines neuen CY800-Paketes veranlassen
;
_neues_paket:
;
;Variablen initialisieren
;
 clr  byte_2                ;Die 3..
 clr  byte_1                ;..Bytes..
 clr  byte_0                ;..loeschen
;
;Codeadresse fuer Taste A laden
;
 ldi  zh,high(_code*2)      ;Z-Zeiger mit Vergleichscode-Adresse..
 ldi  zl,low (_code*2)      ;..laden
;
;Sleep-Mode -> Power Down vorgeben
; 
 sbr  flag_reg,1<<pdm       ;Power-Down-Mode FLAG setzen
;
;Systemtakt ( 4,8MHz ) durch 8 teilen ( 600kHz = 1,666µs )
;
 ldi  ia,1<<CLKPCE          ;Im Clock Prescaler Register Bit..
 out  CLKPR,ia              ;..Clock Prescaler Change Enable setzen..
 ldi  ia,1<<CLKPS1|1<<CLKPS0;..und CLKPS[3:0] loeschen (Sicherheitsprozedur)..
 out  CLKPR,ia              ;..nun mit CLKPCE=0 und CLKPS[3:0] SYS-Takt aendern
;
;PCINT0-IRQ einrichten
;
 in   ia,PCMSK              ;Pin Change Mask Register laden..
 sbr  ia,1<<PCINT0          ;..den Pin Change Enable Mask 1..
 out  PCMSK,ia              ;..auswaehlen
 in   ia,GIMSK              ;General Interrupt Mask Register laden..
 sbr  ia,1<<PCIE            ;..Pin Change Interrupt Enable Bit setzen..
 out  GIMSK,ia              ;..und somit den PCI1-IRQigeben
 ldi  ia,1<<PCIF            ;Pin Change Interrupt Flag im..          
 out  GIFR,ia               ;..General Interrupt Flag Register laden loeschen
;
;Timer/Counter0 stoppen.
;
_timer_stopp: 
 in   ia,TCCR0B             ;..dass Timer/Counter0 Control Register B laden..
 cbr  ia,1<<CS02|1<<CS01|1<<CS00;..Clock Select = T/C0 stopp einstellen..
 out  TCCR0B,ia             ;..und nun den T/C0 stoppen
;
;Timer/Counter0 Zaehlregister fuer die Biterfassung einstellen
; 
 ldi  ia,$FF-#top           ;Wert f. TOV0-IRQ ( Normal- Mode )..
 out  TCNT0,ia              ;..ins Timer/Counter0 Zaehlregister laden
;
;Timer/Counter0 Overflow ISR verlassen
; 
_exit_OVF0addr:             ;Timer0 Overflow ISR verlassen
 out  SREG,s_sreg           ;Statusregister restaurieren
 
 reti                       ;_OVF0addr ISR verlassen
Ich denke hier gibt es nicht viel zu erklären, da lediglich alles vorbereitet wird um auf ein Neues Datenpaket reagieren zu können.


Hier wird nach drei mal direkt hintereinander gültigen Bytes der Ausgang umgeschaltet:


Hier sind die Pegeleinlesezeitpunkte der einzelnen Bits:


_Machtwas_
CRS Robotics A255, TRONXY X3A, TinkerCAD, c´t-Lab, ProfiLab Expert, AVR8 Assembler

Zur Zeit ist neben Ihnen 1 Benutzer in diesem Thema unterwegs:

1 Besucher