Bonjour,
Désirant m'amuser avec les transmission HF de messages numériques je me suis bien sur orienté vers un codage Manchester et comme j'utilise pas mal d'ATMEGA 328 je me suis demandé comment recevoir un message codé de cette façon avec ce µC.
On trouve pas mal de code pour faire çà en logiciel mais ils sont gourmands en temps d’exécution et n'utilisent pas l'UART ce qui est bêta, aussi ai je cherché le moyen de faire çà avec un minimum de hard externe et un minimum de soft.
Je pense avoir trouvé une solution élégante, toutefois peu compatible avec les cartes arduino si celle ci sont utilisées dans cet environnement car l'UART y est déjà utilisé.
Pour les autres:
On suppose un flux de données issues d'une sortie UART TX standard , le codage Manchester est obtenu par un XNOR entre donnée et horloge(données synchronisées sur le front montant) celui ci attaque un émetteur ad hoc et est reçu par un récepteur du même bois (pas d'inversion en cours de route) alors avec ce qui suit on peut récupérer les données transmises.
La récupération d'horloge est faite par le AZ4052 qui est un équivalent rapide du 14052(2xMUX1/4), la première moitié réalise l’équivalent d'un ou exclusif suivi d'un monostable non réarmable qui se synchronisera sur les fronts pertinents du code reçu à partir du moment ou une séquence comportant au moins 8 stop bits(au sens rs 232) aura été reçue;Pour ce faire le signal RX est envoyé sur l'une des entrées d'adresse et une version retardée par un petit RC sur l'autre, on décode alors les états 01 et 10 qui forcent un '1' sur la sortie qui est couplée à l'entrée d’inhibition par une capa qui en association avec une resistance de décharge assure une temporisation et donc la fonction monostable souhaitée. La seconde moitié sert uniquement a recopier l’état de l'inhibition de façon propre et est l'horloge qui sera envoyée au µC.Code:; ****************************************************************************************************************** ; * Manchester_decoder * ; * for ATEMEGA328P on external clock , internal clock is possible also * ; * Version 1.0 by JRV * ; ****************************************************************************************************************** ; .INCLUDE "m328Pdef.inc" ;==================================================================================================================== ; Hardware connections processor ;==================================================================================================================== ; ___ ___ ; (PCINT14/RESET) PC6|1 |_| 28| PC5 (ADC5/SCL/PCINT13) ; RX (PCINT16/RXD) PD0|2 A 27| PC4 (ADC4/SDA/PCINT12) ; TX (PCINT17/TXD) PD1|3 T 26| PC3 (ADC3/PCINT11) ; (PCINT18/INT0) PD2|4 M 25| PC2 (ADC2/PCINT10) ; (PCINT19/OC2B/INT1) PD3|5 E 24| PC1 (ADC1/PCINT9) ; CKi (PCINT20/XCK/T0) PD4|6 L 23| PC0 (ADC0/PCINT8) ; VCC|7 22| GND ; GND|8 A 21| AREF ; PCINT6/XTAL1/TOSC1) PB6|9 T 20| AVCC ; (PCINT7/XTAL2/TOSC2) PB7|10 M 19| PB5 (SCK/PCINT5) ; (PCINT21/OC0B/T1) PD5|11 E 18| PB4 (MISO/PCINT4) ; (PCINT22/OC0A/AIN0) PD6|12 G 17| PB3 (MOSI/OC2A/PCINT3) ; (PCINT23/AIN1) PD7|13 A 16| PB2 (SS/OC1B/PCINT2) ; (PCINT0/CLKO/ICP1) PB0|14 328 15| PB1 (OC1A/PCINT1) ; |_________| ;==================================================================================================================== ; Hardware connections logic of clock recovery ;==================================================================================================================== ; ___ ___ ; CKi VCC|1 |_| 16| VCC ; | VCC|2 A 15| VCC ; GND--------2,2K--x------|3 Z 14| VCC ; VCC|4 4 13|---------------x ; VCC|5 0 12| GND | ; GND--------56K---x------|6 5 11| GND | ; | GND|7 2 10|-----------RX | ; _|_ GND|8 P 9|--x---15K--RX | ; 2,2nF ___ |_________| | | ; | _|_ | ; VCC--------2,2K---x ___ 330P | ; | | | ; | GND | ; x--------------------------------x ;==================================================================================================================== ;==================================================================================================================== ; Constants definitions ;==================================================================================================================== ;define processing clock frequency #define _FREQ_ACT 3.6864;in MHz ;port configuration .EQU _DDRB = 0x00; .EQU _PORTB = 0xFF; pull up on all inputs .EQU _DDRC = 0x00; 7 inputs .EQU _PORTC = 0x40; pull up on reset input .EQU _DDRD = 0x02; 1 output others input .EQU _PORTD = 0xFF; pull up .EQU _RX_PIN = 0; .EQU _CK_PIN = 4; ;PCINT configuration .EQU _PCICR = 1<< PCIE2; .EQU _PCIFR = 1<< PCIF2; .EQU _PCMSK2 = 1<< PCINT20; .EQU _PCMSK1 = 0x00; .EQU _PCMSK0 = 0x00; ;USART configuration,number of bits could be changed and parity added .EQU _BAUD = (((_FREQ_ACT*1000000)/(16*19200))+0.5)-1; .EQU _UCSR0A = 1<<TXC0; .EQU _UCSR0B = 1<<RXCIE0|1<<RXEN0|1<<TXEN0|0<<UCSZ02|0<<TXB80; .EQU _UCSR0C = 1<<UCSZ01|0<<UCSZ00|0<<UMSEL01|1<<UMSEL00|1<< UCPOL0;7 bits synchronous, rising .EQU _UBRR0H = HIGH(_BAUD); .EQU _UBRR0L = LOW(_BAUD); .EQU _UCSR0B0 = 1<<RXCIE0|0<<RXEN0|1<<TXEN0|0<<UCSZ02|0<<TXB80; ;==================================================================================================================== ; Register definitions ;==================================================================================================================== ; .DEF rmp0 = R16 ; Multi-purpose register .DEF rmp1 = R17 ; Multi-purpose register .DEF rmp2 = R18 ; Multi-purpose register .DEF rmp3 = R19 ; Multi-purpose register .DEF rmp4 = R20 ; Multi-purpose register .DEF rmp5 = R21; Multi-purpose register .DEF rmp6 = R22 ; Multi-purpose register .DEF rmp7 = R23 ; Multi-purpose register ;==================================================================================================================== ; Macro definitions ;==================================================================================================================== .MACRO xpush01 push rmp0; push rmp1; in rmp0,SREG ; save SREG push rmp0; .ENDMACRO .MACRO xpop01 pop rmp0; out SREG,rmp0; restore SREG pop rmp1; pop rmp0; .ENDMACRO ;==================================================================================================================== ; SRAM definitions ;==================================================================================================================== ; .DSEG .ORG Sram_Start sCounted: .BYTE 1; ;==================================================================================================================== ; Reset and Interrupt Vectors starting here ;==================================================================================================================== ; .CSEG .ORG $0000 ; ; Reset/Intvectors ; jmp Main ; Reset ;nop; reti ; EXT_INT0 ; IRQ0 Handler nop; reti ; EXT_INT1 ; IRQ1 Handler nop; reti ; PCINT0 ; PCINT0 Handler nop; reti ; PCINT1 ; PCINT1 Handler nop; jmp PCINT_2 ;reti ; PCINT2 ; PCINT2 Handler ;nop; reti ; WDT ; Watchdog Timer Handler nop; reti ; TIM2_COMPA ; Timer2 Compare A Handler nop; reti ; TIM2_COMPB ; Timer2 Compare B Handler nop; reti ; TIM2_OVF ; Timer2 Overflow Handler nop; reti ; TIM1_CAPT ; Timer1 Capture Handler nop; reti ; TIM1_COMPA ; Timer1 Compare A Handler nop; reti ; TIM1_COMPB ; Timer1 Compare B Handler nop; reti ; TIM1_OVF ; Timer1 Overflow Handler nop; reti ; TIM0_COMPA ; Timer0 Compare A Handler nop; reti ; TIM0_COMPB ; Timer0 Compare B Handler nop; reti ; TIM0_OVF ; Timer0 Overflow Handler nop; reti ; SPI_STC ; SPI Transfer Complete Handler nop; jmp USART_RXC;reti ; USART_RXC ; USART, RX Complete Handler ;nop; reti ; USART_UDRE ; USART, UDR Empty Handler nop; reti ; USART_TXC ; USART, TX Complete Handler nop; reti ; ADC ; ADC Conversion Complete Handler nop; reti ; EE_RDY ; EEPROM Ready Handler nop; reti ; ANA_COMP ; Analog Comparator Handler nop; reti ; TWI ; 2-wire Serial Interface Handler nop; reti ; SPM_RDY ; Store Program Memory Ready Handler nop; ; ;==================================================================================================================== ; Interrupt Service Routines ;==================================================================================================================== ; PCINT2 interrupt is used to synchronize Receiver on incomming data, it expects 8 consecutive ones PCINT_2: ; called on each edge of generated clock xpush01; lds rmp1,sCounted; in rmp0,PIND; sbrs rmp0,_CK_PIN; is clock pin hi rjmp end_tim2_compb; no ignore sbrc rmp0,_RX_PIN; check RX pin inc rmp1; sbrs rmp0,_RX_PIN; clr rmp1; cpi rmp1,8; is there 8 consecutive ones detected brne end_tim2_compb; no clr rmp0; sts PCICR,rmp0; kill interrupt ldi rmp0,_UCSR0B0 ;reinit receiver sts UCSR0B,rmp0; ldi rmp0,_UCSR0B sts UCSR0B,rmp0; dec rmp1; end_tim2_compb: sts sCounted,rmp1; 0<= value <= 7 xpop01; reti; ;==================================================================================================================== ; UART receive interrupt ;==================================================================================================================== USART_RXC: xpush01; lds rmp1,UCSR0A; status must be read before data lds rmp0,UDR0; andi rmp1, 1<<FE0 | 1<< DOR0| 1<<UPE0; brne resync; wrong status lds rmp1,sCounted cpi rmp1,7; locked ? brne end_usart_rxc; no sts UDR0,rmp0; echo on TX for test purpose end_usart_rxc: xpop01; reti; resync:; Will reactivate sync process in case of detected errors clr rmp0; sts sCounted,rmp0; ldi rmp0,_PCICR; sts PCICR,rmp0; enable interrupt rjmp end_usart_rxc; ;==================================================================================================================== ; Main Program Start ;==================================================================================================================== main: ; set stack pointer ldi ZH,HIGH(RAMEND); out SPH,ZH; ldi ZL,LOW(RAMEND); out SPL,ZL; adiw ZL,1; ; init whole memory to zero ldi YH,HIGH(SRAM_START); Y point ram location ldi YL,LOW(SRAM_START); ldi rmp0,0; init_ram: st Y+,rmp0 cp YL,ZL; cpc YH,ZH; brne init_ram; ; init ports ;port B ldi rmp0,_PORTB out PORTB,rmp0; ldi rmp0,_DDRB; out DDRB,rmp0; ;port C ldi rmp0,_PORTC out PORTC,rmp0; ldi rmp0,_DDRC; out DDRC,rmp0; ;port D ldi rmp0,_PORTD out PORTD,rmp0; ldi rmp0,_DDRD; out DDRD,rmp0; ;init External interrupt ldi rmp0,_PCICR; sts PCICR,rmp0; ldi rmp0,_PCIFR; sts PCIFR,rmp0; ldi rmp0,_PCMSK2; sts PCMSK2,rmp0; ;init USART0 ldi rmp0,_UCSR0A; sts UCSR0A,rmp0; ldi rmp0,_UCSR0B; sts UCSR0B,rmp0; ldi rmp0,_UCSR0C; sts UCSR0C,rmp0; ldi rmp0,_UBRR0H; sts UBRR0H,rmp0; ldi rmp0,_UBRR0L; sts UBRR0L,rmp0; ;enable interrupt ldi rmp0,1<<SREG_I; out SREG,rmp0; loop: rjmp loop; ; End of source code
Les valeurs(56K,2,2nF) sont pour du 9600 bds mais sont adaptables à d'autre fréquences(règle de trois).
C'est equivalent à un ou exclusif(86) suivi d'un monostable non réarmable (121)
Coté soft il n'y a qu'une routine d’interruption qui s'active au démarrage ou lors d'une perte de synchro et qui va compter le nombre de '1' consecutifs reçu pour réinitialiser la fonction récepteur de l'UART.
Si la durée du monostable est bien calibrée(front montant de l'horloge au milieu des '1' des stops) alors cela supporte pas mal de variation de fréquence.
Pour les questions je reste à votre disposition.
JR
Nota: par habitude tous mes commentaires sont en godon.
-----