wkrug
31.05.2019, 11:13
Hallo Leute,
da Ich mich ab und zu auch mal mit Funkübertragung beschäftige bin Ich auf den sog. Hamming Code gestossen.
Wie die Paritäts Bit's da gebildet werden und die Fehlererkennung funktioniert ist mir im Prinzip klar.
Nun bin Ich auf diese Seite gestossen:
https://www.mikrocontroller.net/articles/RFM12_Protokoll_Stack
Dort werden 4 Bit Nibbles in 8 Bit Bytes umcodiert.
Das ist in C mit einer Tabelle zu lösen und somit kein Problem.
Das Verständnis hört auf, wie Ich damit beim Empfänger ankommende Bitfehler erkennen und korrigieren kann.
Ich hab das jetzt mit einer Vergleichsoption ( EXOR mit der Tabelle ) über die beiden verwendeten Nibbles gemacht.
Nur wenn ein Bit im high bzw. low nibble gekippt ist wird ein Fehler erkannt und korrigiert.
Meine Fragen:
Wie kommt der Kollege auf diese Tabelle?
Gibt es eine bessere Möglichkeit ankommende Bitfehler mit dieser Codierung zu erkennen und evtl. zu korrigieren?
Wo sind in dieser Tabelle die Daten und Paritätsbits codiert und woher kommt das achte Bit?
Erklärung wenn's geht ohne komplizierte Mathematik - Da bin Ich nicht so fit!
Hier noch mein erstellter Quellcode:
/*
* Hamming.c
*
* Created: 30.05.2019 09:42:04
* Author : USER
*/
#include <avr/io.h>
#define F_CPU 8000000
// Declare your global variables here
volatile uint8_t innibble = 0b00000000, recover;
volatile uint8_t hamout;
uint8_t ham_table [16]= {0x15,0x02,0x49,0x5E,0x64,0x73,0x38,0x2F,0xD0,0xC7 ,0x8C,0x9B,0xA1,0xB6,0xFD,0xEA};
//Codieren mit Hamming Tabelle
uint8_t make_ham (uint8_t nibble)
{
return (ham_table[nibble]);
}
//Encodieren der Hamming Tabelle mit Fehlerkorrektur
uint8_t get_nibble (uint8_t hamcode)
{
uint8_t i=0, result, hnibble, lnibble;
result=0xFF; //Fehlerkenner nicht reperabler Fehler
for (i=0;i<16;i++)
{
hnibble = hamcode^ham_table[i]; //Passt eine der Codierungen ?
lnibble = hnibble & 0x0F; //Splitten in High und Low Nibble
hnibble = hnibble & 0xF0;
if(lnibble == 0 && hnibble == 0) //Kein Bitfehler
{
result = i;
break;
}
else
{
if((hnibble == 0x80 || hnibble == 0x40 || hnibble == 0x20 || hnibble == 0x10 ) && (lnibble == 0)) //Fehler im hnibble
{
result = i;
break;
}
if((lnibble == 0x08 || lnibble == 0x04 || lnibble == 0x02 || lnibble == 0x01 ) && (hnibble == 0)) // Fehler im lnibble
{
result = i;
break;
}
}
}
return(result);
}
int main(void)
{
// Declare your local variables here
// Crystal Oscillator division factor: 1
CLKPR=(1<<CLKPCE);
CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) | (0<<CLKPS0);
// Input/Output Ports initialization
// Port B initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
DDRB=(0<<DDB7) | (0<<DDB6) | (0<<DDB5) | (0<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);
// Port C initialization
// Function: Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
DDRC=(0<<DDC6) | (0<<DDC5) | (0<<DDC4) | (0<<DDC3) | (0<<DDC2) | (0<<DDC1) | (0<<DDC0);
// State: Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
PORTC=(0<<PORTC6) | (0<<PORTC5) | (0<<PORTC4) | (0<<PORTC3) | (0<<PORTC2) | (0<<PORTC1) | (0<<PORTC0);
// Port D initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
DDRD=(0<<DDD7) | (0<<DDD6) | (0<<DDD5) | (0<<DDD4) | (0<<DDD3) | (0<<DDD2) | (0<<DDD1) | (0<<DDD0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
PORTD=(0<<PORTD7) | (0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0);
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=0xFF
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00);
TCCR0B=(0<<WGM02) | (0<<CS02) | (0<<CS01) | (0<<CS00);
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer1 Stopped
// Mode: Normal top=0xFFFF
// OC1A output: Disconnected
// OC1B output: Disconnected
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (0<<CS10);
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer2 Stopped
// Mode: Normal top=0xFF
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=(0<<EXCLK) | (0<<AS2);
TCCR2A=(0<<COM2A1) | (0<<COM2A0) | (0<<COM2B1) | (0<<COM2B0) | (0<<WGM21) | (0<<WGM20);
TCCR2B=(0<<WGM22) | (0<<CS22) | (0<<CS21) | (0<<CS20);
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=(0<<OCIE0B) | (0<<OCIE0A) | (0<<TOIE0);
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=(0<<ICIE1) | (0<<OCIE1B) | (0<<OCIE1A) | (0<<TOIE1);
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=(0<<OCIE2B) | (0<<OCIE2A) | (0<<TOIE2);
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=(0<<ISC11) | (0<<ISC10) | (0<<ISC01) | (0<<ISC00);
EIMSK=(0<<INT1) | (0<<INT0);
PCICR=(0<<PCIE2) | (0<<PCIE1) | (0<<PCIE0);
// USART initialization
// USART disabled
UCSR0B=(0<<RXCIE0) | (0<<TXCIE0) | (0<<UDRIE0) | (0<<RXEN0) | (0<<TXEN0) | (0<<UCSZ02) | (0<<RXB80) | (0<<TXB80);
// Analog Comparator initialization
// Analog Comparator: Off
// The Analog Comparator's positive input is
// connected to the AIN0 pin
// The Analog Comparator's negative input is
// connected to the AIN1 pin
ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIC) | (0<<ACIS1) | (0<<ACIS0);
ADCSRB=(0<<ACME);
// Digital input buffer on AIN0: On
// Digital input buffer on AIN1: On
DIDR1=(0<<AIN0D) | (0<<AIN1D);
// ADC initialization
// ADC disabled
ADCSRA=(0<<ADEN) | (0<<ADSC) | (0<<ADATE) | (0<<ADIF) | (0<<ADIE) | (0<<ADPS2) | (0<<ADPS1) | (0<<ADPS0);
// SPI initialization
// SPI disabled
SPCR=(0<<SPIE) | (0<<SPE) | (0<<DORD) | (0<<MSTR) | (0<<CPOL) | (0<<CPHA) | (0<<SPR1) | (0<<SPR0);
// TWI initialization
// Mode: TWI Master
// Bit Rate: 400 kHz
// twi_master_init(400);
// Globally enable interrupts
__asm("sei");
while (1)
{
// Place your code here
//Test für Hamming Encoder und Decoder
for(innibble=0;innibble<16;innibble++)
{
hamout = make_ham(innibble); //Alle 16 möglichen Codes Testen
recover = get_nibble(hamout); //Bits wieder herstellen
}
recover = get_nibble(0x15);
recover = get_nibble(0x05);
recover = get_nibble(0x02);
recover = get_nibble(0x00);
recover = get_nibble(0x49);
recover = get_nibble(0x41);
recover = get_nibble(0x5E);
recover = get_nibble(0x1F); //Nicht korrigierbar
recover = get_nibble(0x64);
recover = get_nibble(0x60);
}
}
da Ich mich ab und zu auch mal mit Funkübertragung beschäftige bin Ich auf den sog. Hamming Code gestossen.
Wie die Paritäts Bit's da gebildet werden und die Fehlererkennung funktioniert ist mir im Prinzip klar.
Nun bin Ich auf diese Seite gestossen:
https://www.mikrocontroller.net/articles/RFM12_Protokoll_Stack
Dort werden 4 Bit Nibbles in 8 Bit Bytes umcodiert.
Das ist in C mit einer Tabelle zu lösen und somit kein Problem.
Das Verständnis hört auf, wie Ich damit beim Empfänger ankommende Bitfehler erkennen und korrigieren kann.
Ich hab das jetzt mit einer Vergleichsoption ( EXOR mit der Tabelle ) über die beiden verwendeten Nibbles gemacht.
Nur wenn ein Bit im high bzw. low nibble gekippt ist wird ein Fehler erkannt und korrigiert.
Meine Fragen:
Wie kommt der Kollege auf diese Tabelle?
Gibt es eine bessere Möglichkeit ankommende Bitfehler mit dieser Codierung zu erkennen und evtl. zu korrigieren?
Wo sind in dieser Tabelle die Daten und Paritätsbits codiert und woher kommt das achte Bit?
Erklärung wenn's geht ohne komplizierte Mathematik - Da bin Ich nicht so fit!
Hier noch mein erstellter Quellcode:
/*
* Hamming.c
*
* Created: 30.05.2019 09:42:04
* Author : USER
*/
#include <avr/io.h>
#define F_CPU 8000000
// Declare your global variables here
volatile uint8_t innibble = 0b00000000, recover;
volatile uint8_t hamout;
uint8_t ham_table [16]= {0x15,0x02,0x49,0x5E,0x64,0x73,0x38,0x2F,0xD0,0xC7 ,0x8C,0x9B,0xA1,0xB6,0xFD,0xEA};
//Codieren mit Hamming Tabelle
uint8_t make_ham (uint8_t nibble)
{
return (ham_table[nibble]);
}
//Encodieren der Hamming Tabelle mit Fehlerkorrektur
uint8_t get_nibble (uint8_t hamcode)
{
uint8_t i=0, result, hnibble, lnibble;
result=0xFF; //Fehlerkenner nicht reperabler Fehler
for (i=0;i<16;i++)
{
hnibble = hamcode^ham_table[i]; //Passt eine der Codierungen ?
lnibble = hnibble & 0x0F; //Splitten in High und Low Nibble
hnibble = hnibble & 0xF0;
if(lnibble == 0 && hnibble == 0) //Kein Bitfehler
{
result = i;
break;
}
else
{
if((hnibble == 0x80 || hnibble == 0x40 || hnibble == 0x20 || hnibble == 0x10 ) && (lnibble == 0)) //Fehler im hnibble
{
result = i;
break;
}
if((lnibble == 0x08 || lnibble == 0x04 || lnibble == 0x02 || lnibble == 0x01 ) && (hnibble == 0)) // Fehler im lnibble
{
result = i;
break;
}
}
}
return(result);
}
int main(void)
{
// Declare your local variables here
// Crystal Oscillator division factor: 1
CLKPR=(1<<CLKPCE);
CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) | (0<<CLKPS0);
// Input/Output Ports initialization
// Port B initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
DDRB=(0<<DDB7) | (0<<DDB6) | (0<<DDB5) | (0<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);
// Port C initialization
// Function: Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
DDRC=(0<<DDC6) | (0<<DDC5) | (0<<DDC4) | (0<<DDC3) | (0<<DDC2) | (0<<DDC1) | (0<<DDC0);
// State: Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
PORTC=(0<<PORTC6) | (0<<PORTC5) | (0<<PORTC4) | (0<<PORTC3) | (0<<PORTC2) | (0<<PORTC1) | (0<<PORTC0);
// Port D initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
DDRD=(0<<DDD7) | (0<<DDD6) | (0<<DDD5) | (0<<DDD4) | (0<<DDD3) | (0<<DDD2) | (0<<DDD1) | (0<<DDD0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
PORTD=(0<<PORTD7) | (0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0);
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=0xFF
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00);
TCCR0B=(0<<WGM02) | (0<<CS02) | (0<<CS01) | (0<<CS00);
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer1 Stopped
// Mode: Normal top=0xFFFF
// OC1A output: Disconnected
// OC1B output: Disconnected
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (0<<CS10);
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer2 Stopped
// Mode: Normal top=0xFF
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=(0<<EXCLK) | (0<<AS2);
TCCR2A=(0<<COM2A1) | (0<<COM2A0) | (0<<COM2B1) | (0<<COM2B0) | (0<<WGM21) | (0<<WGM20);
TCCR2B=(0<<WGM22) | (0<<CS22) | (0<<CS21) | (0<<CS20);
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=(0<<OCIE0B) | (0<<OCIE0A) | (0<<TOIE0);
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=(0<<ICIE1) | (0<<OCIE1B) | (0<<OCIE1A) | (0<<TOIE1);
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=(0<<OCIE2B) | (0<<OCIE2A) | (0<<TOIE2);
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=(0<<ISC11) | (0<<ISC10) | (0<<ISC01) | (0<<ISC00);
EIMSK=(0<<INT1) | (0<<INT0);
PCICR=(0<<PCIE2) | (0<<PCIE1) | (0<<PCIE0);
// USART initialization
// USART disabled
UCSR0B=(0<<RXCIE0) | (0<<TXCIE0) | (0<<UDRIE0) | (0<<RXEN0) | (0<<TXEN0) | (0<<UCSZ02) | (0<<RXB80) | (0<<TXB80);
// Analog Comparator initialization
// Analog Comparator: Off
// The Analog Comparator's positive input is
// connected to the AIN0 pin
// The Analog Comparator's negative input is
// connected to the AIN1 pin
ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIC) | (0<<ACIS1) | (0<<ACIS0);
ADCSRB=(0<<ACME);
// Digital input buffer on AIN0: On
// Digital input buffer on AIN1: On
DIDR1=(0<<AIN0D) | (0<<AIN1D);
// ADC initialization
// ADC disabled
ADCSRA=(0<<ADEN) | (0<<ADSC) | (0<<ADATE) | (0<<ADIF) | (0<<ADIE) | (0<<ADPS2) | (0<<ADPS1) | (0<<ADPS0);
// SPI initialization
// SPI disabled
SPCR=(0<<SPIE) | (0<<SPE) | (0<<DORD) | (0<<MSTR) | (0<<CPOL) | (0<<CPHA) | (0<<SPR1) | (0<<SPR0);
// TWI initialization
// Mode: TWI Master
// Bit Rate: 400 kHz
// twi_master_init(400);
// Globally enable interrupts
__asm("sei");
while (1)
{
// Place your code here
//Test für Hamming Encoder und Decoder
for(innibble=0;innibble<16;innibble++)
{
hamout = make_ham(innibble); //Alle 16 möglichen Codes Testen
recover = get_nibble(hamout); //Bits wieder herstellen
}
recover = get_nibble(0x15);
recover = get_nibble(0x05);
recover = get_nibble(0x02);
recover = get_nibble(0x00);
recover = get_nibble(0x49);
recover = get_nibble(0x41);
recover = get_nibble(0x5E);
recover = get_nibble(0x1F); //Nicht korrigierbar
recover = get_nibble(0x64);
recover = get_nibble(0x60);
}
}