 |
 |
View previous topic :: View next topic |
Author |
Message |
bulut_01
Joined: 24 Feb 2024 Posts: 317
|
|
Posted: Wed Jul 23, 2025 9:54 am |
|
|
PrinceNai wrote: | This is the image of the data how my (real hardware) transmitter sends data out. Now we just need to decode that back. Steps to do that (I'm sure there are other ways, this is mine):
1. detect preamble somewhere in the range of 4Te
2. detect and forget the first 0 - 1 combo (symbol). This is the part that is missing in the code you are using and the reason it is not working, because it was only a single 0 at the beginning of the stream you were trying to decode back then
3. Go through data portion of the stream and decode on the fly
My mind is set on state machines (switch statement), so I try to push every problem into that solution.
I do not intend to write a ready made code for you, but I'm willing to help you do it. Experience teaches me that you'll find another remote very soon, so it's better to understand what you are doing and why. The same goes for me, it wasn't meant in a bad way :-)
https://ibb.co/21vW9zBG |
Help me with the second option. What should I do to detect 0-1 transition? I don't know the Manchester decode code, so if you help me, I can skip the first step and I have bigger problems in front of me in deciphering the remote control encryption algorithm. |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 19929
|
|
Posted: Wed Jul 23, 2025 12:05 pm |
|
|
You still have not posted where you setup INTEDG?.
I'd guess something really silly, like this is not set for the correct bit in
the processor. |
|
 |
bulut_01
Joined: 24 Feb 2024 Posts: 317
|
|
Posted: Wed Jul 23, 2025 12:13 pm |
|
|
Ttelmah wrote: | You still have not posted where you setup INTEDG?.
I'd guess something really silly, like this is not set for the correct bit in
the processor. |
I THINK THE EDGE IS MEASURED FROM HERE WHEN THE IOC INT SIGNAL OCCURS.
////////////////////////// FUNCTIONS /////////////////////////////////////////
void ToggleIntEdge(void){
if(INTEDG == 1){
INTEDG = 0;
}
else{
INTEDG = 1;
}}
// ---------------------------------------------------------------------------- |
|
 |
PrinceNai
Joined: 31 Oct 2016 Posts: 554 Location: Montenegro
|
|
Posted: Wed Jul 23, 2025 12:39 pm |
|
|
Are you using IOC or External interrupt? At least on 18f46k22 IOC fires both ways, no need to change direction. The piece of code you show is from the version with external interrupt and you can delete it. It does nothing. Edge is measured from the moment interrupt occurs, every time you set timer to 0. Once again, your existing code doesn't work because it doesn't read the start bit combination correctly. I feel it's better to just post the code, because you are looking in the wrong place. Below is the working, tested code that on 18f46k22 correctly receives an decodes the stream you showed. It's much faster this way.
Code: |
// A piece of code used to decode Manchester encodeed data. The code
// presumes that one step of the Timer0 is 1us which enables that Te
// length in us can be expressed directly in TMR0 counts.
// With different clock speeds simply change the divider
// when TMR0 is set up, and it works fine for 4, 8, 16 and 32MHz. For
// 20MHz clock Te value should be calculated accordingly, for instance
// Te = width of the signal * 20 / 32 and leave the TMR0 setup as it is.
// Te represents the width of one half of the encoded Manchester symbol.
// The second presumptions is that the signal has some synch signals
// distinctly wider than 2*Te and a 7*Te long preamble, followed by
// a one Te wide 0. After that goes the actual encoded data. The type
// of coding (Thomas or IEEE 802) must be defined.
//
// Sample input signal shape is below:
//
// PREAMBLE START BITS ENCODED DATA 64 SYMBOLS END OF DATA
// 000001111 01 011001100110.......01 0000000000000
//
// Each 1 or 0 is one Te long
// ******************************************************************
#include <18F46K22.h>
#device ADC=10
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOPUT
#FUSES DEBUG
#device ICD=TRUE
#use delay(internal = 32000000)
///////////////////////////// DEFINES ///////////////////////////////
#define NUMBER_OF_BYTES 8 // number of DECODED bytes to receive
#define TE 416 // duration of one bit in us, change as needed
#define PREAMBLE_MIN_TIME 3.5*TE // we expect a 4 bit preamble, make some room for clock error
#define PREAMBLE_MAX_TIME 4.5*TE // on the transmitting and receiving side
#define SAMPLING_MIN_TIME 1.5*TE // same here when sampling
#define SAMPLING_MAX_TIME 2.5*TE // the transitions we are looking for are always 2*TE apart
#define EDGE_VALID 0.5*TE // anythig shorter than this is considered a glitch
#define INPUT_PIN PIN_B4
//#define IEEC_802 // comment out for Thomas encoding
/////////////////////////// VARIABLES ///////////////////////////////
char DecodedInputData[10]; // buffer for decoded data
char WorkingtByte = 0;
int8 InputByteCounter = 0; // keeps track about which byte we are filling in
int8 CurrentBitPosition = 0; // current bit position of the incoming data
int8 Have_Data = 0; // flag to inform main data was received and decoded
// switch
enum {PreambleRising = 1, PreambleFalling, StartBit, SampleData}; // decode state machine
int8 DecodeSwitch = PreambleRising;
// Timer
int16 TimerValue;
int8 TMR0_Overflow = 0; // how many times TMR0 has overflowed
int8 BitCheck = 0; // number of set bits in a received byte. Must be 4 for Manchester encoded data. Also used as a flag for wrong data format
////////////////////////// FUNCTIONS ////////////////////////////////
// ------------------------------------------------------------------
void ClearBuffer (void){ // clear data buffer
int8 i;
for (i=0; i<10; i++){
DecodedInputData[i] = 0x00;
}
}
// Function to implement count of set bits using Brian Kernighan's Algorithm
int8 CountSetBits(int8 n){
int count = 0; // Initialise count
while (n) { // Iterate until n is 0
n &= (n - 1);
count++;
}
return count; // Return the final set bit count
}
//////////////////////// END OF FUNCTIONS //////////////////////////
// ******************************************************************
// INTERRUPTS
// ******************************************************************
#INT_TIMER0
void TIMER0_isr(void)
{
TMR0_Overflow++; // count timer TMR0_Overflows
}
#INT_RB
void RB_isr(void)
{
// ******************************************************************
// ******************************************************************
switch (DecodeSwitch) // state machine is used to receive and decode Mancester encoded data
{
// PreambleRising looks for a rising edge and prepares all the variables
// PreambleFalling finds a falling edge and checks if the time fits the preamble. If yes, goes to StartBit
// If no, it returns to PreambleRising to look for the next rising edge
// SampleData does the actual decoding of the data. It also checks if the format of the received data is correct.
// If everything is ok, it sets a flag to indicate that. Then it returns to PreambleRising
// ------------------------------------------------------------------
// wait for a rising edge on the input, this state also serves as a reset.
case PreambleRising: // we have a rising edge, could be start of the preamble
{
if(input_state(INPUT_PIN) == 1){ // input is 1 after interrupt, transition is good, from 0 to 1
set_timer0(0); // reset timer
TMR0_Overflow = 0; // and various counters
CurrentBitPosition = 0;
InputByteCounter = 0;
WorkingtByte = 0;
Have_Data = 0; // and flags
DecodeSwitch = PreambleFalling; // and go to PreambleFalling to see if we have a preamble
}
break;
}
// ------------------------------------------------------------------
case PreambleFalling: // we have a falling edge, pulse ended. Might be preamble.
{
TimerValue = get_timer0(); // check the time that elapsed between two interrupts
if(TMR0_Overflow == 0 && TimerValue > PREAMBLE_MIN_TIME && TimerValue < PREAMBLE_MAX_TIME) { // bingo, time is good, we have a preamble
set_timer0(0); // clear timer
DecodeSwitch = StartBit; // go wait for start bit
}
else{ // not good, pulse was either too short or too long for a preamble.
DecodeSwitch = PreambleRising; // Reset state machine
}
break;
}
// ------------------------------------------------------------------
// 0 - 1 combo. We come here on the rising edge change of the start symbol.
case StartBit:
{
TimerValue = get_timer0();
if(TMR0_Overflow == 0 && TimerValue >= EDGE_VALID && TimerValue <= SAMPLING_MIN_TIME){
set_timer0(0); // clear timer for decoding
DecodeSwitch = SampleData; // timing is ok, proceed to sampling
}
else{
DecodeSwitch = PreambleRising; // Timing is off, reset state machine
}
break;
}
// ------------------------------------------------------------------
// Preamble and start bit were received OK.
// Now there are 4 options:
//
// 1 - time between two consecutive interrupts is too long for a valid transmission, abort
// 2 - time between two interrupts is too short to be a valid transmission, abort
// 3 - same symbol is coming as the previous one was: 01 01 or 10 10 Two edges. There will be interrupt in the middle of the symbol AND at the beginning of the symbol.
// 4 - different symbol is comming in as the previous one: 01 10 or 10 01 One edge. Interrupt will come in the middle of the symbol only.
case SampleData:
{
TimerValue = get_timer0();
// --------------------------
// 1. time between two edges is to long for a valid symbol, reset
if(TMR0_Overflow != 0 || TimerValue > SAMPLING_MAX_TIME){ // time between two edges was too long,
DecodeSwitch = PreambleRising; // reset state machine
}
// --------------------------
// 2. time between two interupts is too short to be valid, abort
else if(TimerValue < EDGE_VALID){ // time between two transitions was too short,
DecodeSwitch = PreambleRising; // reset state machine
}
// --------------------------
// 3. time between two edges is within limits, but too short for sampling, it may be transition between two symbols with the same value
else if(TimerValue >= EDGE_VALID && TimerValue <= SAMPLING_MIN_TIME){ // the transition came too soon for sampling, exit interrupt but leave
delay_cycles(1); // the timer running and stay in the same state for next IOC
}
// -------------------------
// 4. time is ok, around 2*Te, sample input line
else if(TimerValue >= SAMPLING_MIN_TIME && TimerValue <= SAMPLING_MAX_TIME){ // this is the interrupt we are looking for, approx. 2*TE after the first one, sample and store the data
set_timer0(0); // reset timer for the next symbol
// ------------------------------------------------------------------
// DECODING LOGIC IS DEFINED AT THE BEGINNING
#IFDEF IEEC_802
if(input_state(INPUT_PIN) == 1){ // IEEC 802 encoding
bit_set(WorkingtByte, CurrentBitPosition); // Sample input. Set appropriate bit if needed, leave 0 otherwise
}
#ELSE
if(input_state(INPUT_PIN) == 0){ // Thomas encoding scheme
bit_set(WorkingtByte, CurrentBitPosition); // Sample input. Set appropriate bit if needed, leave 0 otherwise
}
#ENDIF
// ------------------------------------------------------------------
CurrentBitPosition++;
if(CurrentBitPosition > 7){ // 8 bits, one byte of data was received
CurrentBitPosition = 0; // reset bit position counter
DecodedInputData[InputByteCounter] = WorkingtByte; // store data into the buffer
// check for correct format of the received data. Counts ones in the
// received byte. Must be four of them, of course. If not, inform main and exit
BitCheck = CountSetBits(WorkingtByte); // test received data. Not implemented yet.
WorkingtByte = 0; // prepare variable for next byte (all zeroes, since we are only setting the ones as needed)
InputByteCounter++; // increment byte counter for a correct position in the buffer
if (InputByteCounter == NUMBER_OF_BYTES){ // if all the bytes are in the buffer, reception is done
Have_Data = 1; // we have data, signal that to main
DecodeSwitch = PreambleRising; // and reset state machine for the next reception
} // if byte counter
} // if bit position
} // end of sampling
// if there is an option not covered above, abort
else{
DecodeSwitch = PreambleRising;
}
break;
} // end case
}
}
// ------------------------------------------------------------------
// ******************************************************************
// END OF INTERRUPTS
// ******************************************************************
void main()
{
ClearBuffer(); // clear data buffer
// setup TMR0 setting for the different clock speeds
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_8); // 65.535us interrupt, resolution 1us at 32MHz
// setup_timer_0(RTCC_INTERNAL|RTCC_DIV_4); // 65.535us interrupt, resolution 1us at 16MHz
// setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2); // 65.535us interrupt, resolution 1us at 8MHz
// setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); // 65.535us interrupt, resolution 1us at 4MHz
enable_interrupts(INT_TIMER0);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
while(TRUE)
{
if(Have_Data == 1){
Have_Data = 0; // do something with the data
}
if(BitCheck == -1){
BitCheck = 0;
}
} // while true
} // main
|
|
|
 |
bulut_01
Joined: 24 Feb 2024 Posts: 317
|
|
Posted: Wed Jul 23, 2025 1:22 pm |
|
|
PrinceNai wrote: | Are you using IOC or External interrupt? At least on 18f46k22 IOC fires both ways, no need to change direction. The piece of code you show is from the version with external interrupt and you can delete it. It does nothing. Edge is measured from the moment interrupt occurs, every time you set timer to 0. Once again, your existing code doesn't work because it doesn't read the start bit combination correctly. I feel it's better to just post the code, because you are looking in the wrong place. Below is the working, tested code that on 18f46k22 correctly receives an decodes the stream you showed. It's much faster this way.
Code: |
// A piece of code used to decode Manchester encodeed data. The code
// presumes that one step of the Timer0 is 1us which enables that Te
// length in us can be expressed directly in TMR0 counts.
// With different clock speeds simply change the divider
// when TMR0 is set up, and it works fine for 4, 8, 16 and 32MHz. For
// 20MHz clock Te value should be calculated accordingly, for instance
// Te = width of the signal * 20 / 32 and leave the TMR0 setup as it is.
// Te represents the width of one half of the encoded Manchester symbol.
// The second presumptions is that the signal has some synch signals
// distinctly wider than 2*Te and a 7*Te long preamble, followed by
// a one Te wide 0. After that goes the actual encoded data. The type
// of coding (Thomas or IEEE 802) must be defined.
//
// Sample input signal shape is below:
//
// PREAMBLE START BITS ENCODED DATA 64 SYMBOLS END OF DATA
// 000001111 01 011001100110.......01 0000000000000
//
// Each 1 or 0 is one Te long
// ******************************************************************
#include <18F46K22.h>
#device ADC=10
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOPUT
#FUSES DEBUG
#device ICD=TRUE
#use delay(internal = 32000000)
///////////////////////////// DEFINES ///////////////////////////////
#define NUMBER_OF_BYTES 8 // number of DECODED bytes to receive
#define TE 416 // duration of one bit in us, change as needed
#define PREAMBLE_MIN_TIME 3.5*TE // we expect a 4 bit preamble, make some room for clock error
#define PREAMBLE_MAX_TIME 4.5*TE // on the transmitting and receiving side
#define SAMPLING_MIN_TIME 1.5*TE // same here when sampling
#define SAMPLING_MAX_TIME 2.5*TE // the transitions we are looking for are always 2*TE apart
#define EDGE_VALID 0.5*TE // anythig shorter than this is considered a glitch
#define INPUT_PIN PIN_B4
//#define IEEC_802 // comment out for Thomas encoding
/////////////////////////// VARIABLES ///////////////////////////////
char DecodedInputData[10]; // buffer for decoded data
char WorkingtByte = 0;
int8 InputByteCounter = 0; // keeps track about which byte we are filling in
int8 CurrentBitPosition = 0; // current bit position of the incoming data
int8 Have_Data = 0; // flag to inform main data was received and decoded
// switch
enum {PreambleRising = 1, PreambleFalling, StartBit, SampleData}; // decode state machine
int8 DecodeSwitch = PreambleRising;
// Timer
int16 TimerValue;
int8 TMR0_Overflow = 0; // how many times TMR0 has overflowed
int8 BitCheck = 0; // number of set bits in a received byte. Must be 4 for Manchester encoded data. Also used as a flag for wrong data format
////////////////////////// FUNCTIONS ////////////////////////////////
// ------------------------------------------------------------------
void ClearBuffer (void){ // clear data buffer
int8 i;
for (i=0; i<10; i++){
DecodedInputData[i] = 0x00;
}
}
// Function to implement count of set bits using Brian Kernighan's Algorithm
int8 CountSetBits(int8 n){
int count = 0; // Initialise count
while (n) { // Iterate until n is 0
n &= (n - 1);
count++;
}
return count; // Return the final set bit count
}
//////////////////////// END OF FUNCTIONS //////////////////////////
// ******************************************************************
// INTERRUPTS
// ******************************************************************
#INT_TIMER0
void TIMER0_isr(void)
{
TMR0_Overflow++; // count timer TMR0_Overflows
}
#INT_RB
void RB_isr(void)
{
// ******************************************************************
// ******************************************************************
switch (DecodeSwitch) // state machine is used to receive and decode Mancester encoded data
{
// PreambleRising looks for a rising edge and prepares all the variables
// PreambleFalling finds a falling edge and checks if the time fits the preamble. If yes, goes to StartBit
// If no, it returns to PreambleRising to look for the next rising edge
// SampleData does the actual decoding of the data. It also checks if the format of the received data is correct.
// If everything is ok, it sets a flag to indicate that. Then it returns to PreambleRising
// ------------------------------------------------------------------
// wait for a rising edge on the input, this state also serves as a reset.
case PreambleRising: // we have a rising edge, could be start of the preamble
{
if(input_state(INPUT_PIN) == 1){ // input is 1 after interrupt, transition is good, from 0 to 1
set_timer0(0); // reset timer
TMR0_Overflow = 0; // and various counters
CurrentBitPosition = 0;
InputByteCounter = 0;
WorkingtByte = 0;
Have_Data = 0; // and flags
DecodeSwitch = PreambleFalling; // and go to PreambleFalling to see if we have a preamble
}
break;
}
// ------------------------------------------------------------------
case PreambleFalling: // we have a falling edge, pulse ended. Might be preamble.
{
TimerValue = get_timer0(); // check the time that elapsed between two interrupts
if(TMR0_Overflow == 0 && TimerValue > PREAMBLE_MIN_TIME && TimerValue < PREAMBLE_MAX_TIME) { // bingo, time is good, we have a preamble
set_timer0(0); // clear timer
DecodeSwitch = StartBit; // go wait for start bit
}
else{ // not good, pulse was either too short or too long for a preamble.
DecodeSwitch = PreambleRising; // Reset state machine
}
break;
}
// ------------------------------------------------------------------
// 0 - 1 combo. We come here on the rising edge change of the start symbol.
case StartBit:
{
TimerValue = get_timer0();
if(TMR0_Overflow == 0 && TimerValue >= EDGE_VALID && TimerValue <= SAMPLING_MIN_TIME){
set_timer0(0); // clear timer for decoding
DecodeSwitch = SampleData; // timing is ok, proceed to sampling
}
else{
DecodeSwitch = PreambleRising; // Timing is off, reset state machine
}
break;
}
// ------------------------------------------------------------------
// Preamble and start bit were received OK.
// Now there are 4 options:
//
// 1 - time between two consecutive interrupts is too long for a valid transmission, abort
// 2 - time between two interrupts is too short to be a valid transmission, abort
// 3 - same symbol is coming as the previous one was: 01 01 or 10 10 Two edges. There will be interrupt in the middle of the symbol AND at the beginning of the symbol.
// 4 - different symbol is comming in as the previous one: 01 10 or 10 01 One edge. Interrupt will come in the middle of the symbol only.
case SampleData:
{
TimerValue = get_timer0();
// --------------------------
// 1. time between two edges is to long for a valid symbol, reset
if(TMR0_Overflow != 0 || TimerValue > SAMPLING_MAX_TIME){ // time between two edges was too long,
DecodeSwitch = PreambleRising; // reset state machine
}
// --------------------------
// 2. time between two interupts is too short to be valid, abort
else if(TimerValue < EDGE_VALID){ // time between two transitions was too short,
DecodeSwitch = PreambleRising; // reset state machine
}
// --------------------------
// 3. time between two edges is within limits, but too short for sampling, it may be transition between two symbols with the same value
else if(TimerValue >= EDGE_VALID && TimerValue <= SAMPLING_MIN_TIME){ // the transition came too soon for sampling, exit interrupt but leave
delay_cycles(1); // the timer running and stay in the same state for next IOC
}
// -------------------------
// 4. time is ok, around 2*Te, sample input line
else if(TimerValue >= SAMPLING_MIN_TIME && TimerValue <= SAMPLING_MAX_TIME){ // this is the interrupt we are looking for, approx. 2*TE after the first one, sample and store the data
set_timer0(0); // reset timer for the next symbol
// ------------------------------------------------------------------
// DECODING LOGIC IS DEFINED AT THE BEGINNING
#IFDEF IEEC_802
if(input_state(INPUT_PIN) == 1){ // IEEC 802 encoding
bit_set(WorkingtByte, CurrentBitPosition); // Sample input. Set appropriate bit if needed, leave 0 otherwise
}
#ELSE
if(input_state(INPUT_PIN) == 0){ // Thomas encoding scheme
bit_set(WorkingtByte, CurrentBitPosition); // Sample input. Set appropriate bit if needed, leave 0 otherwise
}
#ENDIF
// ------------------------------------------------------------------
CurrentBitPosition++;
if(CurrentBitPosition > 7){ // 8 bits, one byte of data was received
CurrentBitPosition = 0; // reset bit position counter
DecodedInputData[InputByteCounter] = WorkingtByte; // store data into the buffer
// check for correct format of the received data. Counts ones in the
// received byte. Must be four of them, of course. If not, inform main and exit
BitCheck = CountSetBits(WorkingtByte); // test received data. Not implemented yet.
WorkingtByte = 0; // prepare variable for next byte (all zeroes, since we are only setting the ones as needed)
InputByteCounter++; // increment byte counter for a correct position in the buffer
if (InputByteCounter == NUMBER_OF_BYTES){ // if all the bytes are in the buffer, reception is done
Have_Data = 1; // we have data, signal that to main
DecodeSwitch = PreambleRising; // and reset state machine for the next reception
} // if byte counter
} // if bit position
} // end of sampling
// if there is an option not covered above, abort
else{
DecodeSwitch = PreambleRising;
}
break;
} // end case
}
}
// ------------------------------------------------------------------
// ******************************************************************
// END OF INTERRUPTS
// ******************************************************************
void main()
{
ClearBuffer(); // clear data buffer
// setup TMR0 setting for the different clock speeds
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_8); // 65.535us interrupt, resolution 1us at 32MHz
// setup_timer_0(RTCC_INTERNAL|RTCC_DIV_4); // 65.535us interrupt, resolution 1us at 16MHz
// setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2); // 65.535us interrupt, resolution 1us at 8MHz
// setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); // 65.535us interrupt, resolution 1us at 4MHz
enable_interrupts(INT_TIMER0);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
while(TRUE)
{
if(Have_Data == 1){
Have_Data = 0; // do something with the data
}
if(BitCheck == -1){
BitCheck = 0;
}
} // while true
} // main
|
|
Thank you. My MCU doesn't have an RB interrupt, I used RA instead. You used timer0 in your code. I made the necessary changes to set my MCU to timer1, but the code didn't work. i.e., ready 1 doesn't work. The RA interrupt works, but I toggled the LED. What could I have done wrong?
Code: |
#include <16F1824.h>
#device ADC = 8
//#FUSES PROTECT
//#FUSES CPD
//
#fuses BROWNOUT //voltaj koruması 1.9v altına inince resetliyor
#fuses BORV19 //bu bölüm eeprom korumak için aktif
#fuses PUT
//
#FUSES NOMCLR
#FUSES NOLVP
#FUSES NOSTVREN
#FUSES NOIESO
#FUSES NOFCMEN
#FUSES NOWRT
#FUSES NOWDT
#FUSES NODEBUG
#use delay(internal = 32M)
//
#use fast_io(A)
#use fast_io(C)
//
#OPT 9
////
#define NUMBER_OF_BYTES 8 // number of DECODED bytes to receive
#define TE 416 // duration of one bit in us, change as needed
#define PREAMBLE_MIN_TIME 3.5*TE // we expect a 4 bit preamble, make some room for clock error
#define PREAMBLE_MAX_TIME 4.5*TE // on the transmitting and receiving side
#define SAMPLING_MIN_TIME 1.5*TE // same here when sampling
#define SAMPLING_MAX_TIME 2.5*TE // the transitions we are looking for are always 2*TE apart
#define EDGE_VALID 0.5*TE // anythig shorter than this is considered a glitch
#define INPUT_PIN PIN_B4
//#define IEEC_802 // comment out for Thomas encoding
/////////////////////////// VARIABLES /////////////////////////////////////////
char DecodedInputData[10]; // buffer for decoded data
char WorkingtByte = 0;
int8 InputByteCounter = 0; // keeps track about which byte we are filling in
int8 CurrentBitPosition = 0; // current bit position of the incoming data
int8 Have_Data = 0; // flag to inform main data was received and decoded
// switch
enum {PreambleRising = 1, PreambleFalling, StartBit, SampleData}; // decode state machine
int8 DecodeSwitch = PreambleRising;
// Timer
int16 TimerValue;
int8 TMR1_Overflow = 0; // how many times TMR0 has overflowed
int8 BitCheck = 0; // number of set bits in a received byte. Must be 4 for Manchester encoded data. Also used as a flag for wrong data format
////////////////////////// FUNCTIONS //////////////////////////////////////////
// ----------------------------------------------------------------------------
void ClearBuffer (void){ // clear data buffer
int8 i;
for (i=0; i<10; i++){
DecodedInputData[i] = 0x00;
}
}
// Function to implement count of set bits using Brian Kernighan's Algorithm
int8 CountSetBits(int8 n){
int count = 0; // Initialise count
while (n){ // Iterate until n is 0
n &= (n - 1);
count++;
}
return count; // Return the final set bit count
}
//////////////////////// END OF FUNCTIONS //////////////////////////
// ****************************************************************************
// INTERRUPTS
// ****************************************************************************
#INT_TIMER1
void TIMER1_isr(void)
{
TMR1_Overflow++; // count timer TMR0_Overflows
}
///////////////////////////////////////////////////////////////////////////////
#INT_RA
void RA_isr(void)
{
switch (DecodeSwitch) // state machine is used to receive and decode Mancester encoded data
{
// PreambleRising looks for a rising edge and prepares all the variables
// PreambleFalling finds a falling edge and checks if the time fits the preamble. If yes, goes to StartBit
// If no, it returns to PreambleRising to look for the next rising edge
// SampleData does the actual decoding of the data. It also checks if the format of the received data is correct.
// If everything is ok, it sets a flag to indicate that. Then it returns to PreambleRising
// ------------------------------------------------------------------
// wait for a rising edge on the input, this state also serves as a reset.
case PreambleRising: // we have a rising edge, could be start of the preamble
{
if(input_state(data_inputs) == 1){ // input is 1 after interrupt, transition is good, from 0 to 1
set_timer1(0); // reset timer
TMR1_Overflow = 0; // and various counters
CurrentBitPosition = 0;
InputByteCounter = 0;
WorkingtByte = 0;
Have_Data = 0; // and flags
DecodeSwitch = PreambleFalling; // and go to PreambleFalling to see if we have a preamble
}
break;
}
// ------------------------------------------------------------------
case PreambleFalling: // we have a falling edge, pulse ended. Might be preamble.
{
TimerValue = get_timer0(); // check the time that elapsed between two interrupts
if(TMR1_Overflow == 0 && TimerValue > PREAMBLE_MIN_TIME && TimerValue < PREAMBLE_MAX_TIME) { // bingo, time is good, we have a preamble
set_timer0(0); // clear timer
DecodeSwitch = StartBit; // go wait for start bit
}
else{ // not good, pulse was either too short or too long for a preamble.
DecodeSwitch = PreambleRising; // Reset state machine
}
break;
}
// ------------------------------------------------------------------
// 0 - 1 combo. We come here on the rising edge change of the start symbol.
case StartBit:
{
TimerValue = get_timer0();
if(TMR1_Overflow == 0 && TimerValue >= EDGE_VALID && TimerValue <= SAMPLING_MIN_TIME){
set_timer0(0); // clear timer for decoding
DecodeSwitch = SampleData; // timing is ok, proceed to sampling
}
else{
DecodeSwitch = PreambleRising; // Timing is off, reset state machine
}
break;
}
// ------------------------------------------------------------------
// Preamble and start bit were received OK.
// Now there are 4 options:
//
// 1 - time between two consecutive interrupts is too long for a valid transmission, abort
// 2 - time between two interrupts is too short to be a valid transmission, abort
// 3 - same symbol is coming as the previous one was: 01 01 or 10 10 Two edges. There will be interrupt in the middle of the symbol AND at the beginning of the symbol.
// 4 - different symbol is comming in as the previous one: 01 10 or 10 01 One edge. Interrupt will come in the middle of the symbol only.
case SampleData:
{
TimerValue = get_timer0();
// --------------------------
// 1. time between two edges is to long for a valid symbol, reset
if(TMR1_Overflow != 0 || TimerValue > SAMPLING_MAX_TIME){ // time between two edges was too long,
DecodeSwitch = PreambleRising; // reset state machine
}
// --------------------------
// 2. time between two interupts is too short to be valid, abort
else if(TimerValue < EDGE_VALID){ // time between two transitions was too short,
DecodeSwitch = PreambleRising; // reset state machine
}
// --------------------------
// 3. time between two edges is within limits, but too short for sampling, it may be transition between two symbols with the same value
else if(TimerValue >= EDGE_VALID && TimerValue <= SAMPLING_MIN_TIME){ // the transition came too soon for sampling, exit interrupt but leave
delay_cycles(1); // the timer running and stay in the same state for next IOC
}
// -------------------------
// 4. time is ok, around 2*Te, sample input line
else if(TimerValue >= SAMPLING_MIN_TIME && TimerValue <= SAMPLING_MAX_TIME){ // this is the interrupt we are looking for, approx. 2*TE after the first one, sample and store the data
set_timer1(0); // reset timer for the next symbol
// ------------------------------------------------------------------
// DECODING LOGIC IS DEFINED AT THE BEGINNING
#IFDEF IEEC_802
if(input_state(INPUT_PIN) == 1){ // IEEC 802 encoding
bit_set(WorkingtByte, CurrentBitPosition); // Sample input. Set appropriate bit if needed, leave 0 otherwise
}
#ELSE
if(input_state(data_inputs) == 0){ // Thomas encoding scheme
bit_set(WorkingtByte, CurrentBitPosition); // Sample input. Set appropriate bit if needed, leave 0 otherwise
}
#ENDIF
// ------------------------------------------------------------------
CurrentBitPosition++;
if(CurrentBitPosition > 7){ // 8 bits, one byte of data was received
CurrentBitPosition = 0; // reset bit position counter
DecodedInputData[InputByteCounter] = WorkingtByte; // store data into the buffer
// check for correct format of the received data. Counts ones in the
// received byte. Must be four of them, of course. If not, inform main and exit
BitCheck = CountSetBits(WorkingtByte); // test received data. Not implemented yet.
WorkingtByte = 0; // prepare variable for next byte (all zeroes, since we are only setting the ones as needed)
InputByteCounter++; // increment byte counter for a correct position in the buffer
if (InputByteCounter == NUMBER_OF_BYTES){ // if all the bytes are in the buffer, reception is done
for(int i = 0; i < 7; i++){ //7
paket[i] = DecodedInputData[i];
}
READY = 1; // we have data, signal that to main
DecodeSwitch = PreambleRising; // and reset state machine for the next reception
} // if byte counter
} // if bit position
} // end of sampling
// if there is an option not covered above, abort
else{
DecodeSwitch = PreambleRising;
}
break;
} // end case
}
}
////////////////////////////////////////
void main()
{
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8); //65.5 ms overflow
enable_interrupts(INT_TIMER1);
set_timer1(0);
//
enable_interrupts(INT_RA);
ClearBuffer();
............................
..........................
while(true){
if(BitCheck == -1){
BitCheck = 0;
}
//
if(ready == 1){
ready_();
}
...........................
..........................
..........................
|
|
|
 |
PrinceNai
Joined: 31 Oct 2016 Posts: 554 Location: Montenegro
|
|
Posted: Wed Jul 23, 2025 1:33 pm |
|
|
One thing could be that you haven't changed input pin to your hardware. |
|
 |
bulut_01
Joined: 24 Feb 2024 Posts: 317
|
|
Posted: Wed Jul 23, 2025 1:36 pm |
|
|
PrinceNai wrote: | One thing could be that you haven't changed input pin to your hardware. |
If you look at the code it is set to A1.
#define data_inputs pin_a1 |
|
 |
PrinceNai
Joined: 31 Oct 2016 Posts: 554 Location: Montenegro
|
|
Posted: Wed Jul 23, 2025 1:39 pm |
|
|
Code: |
// DECODING LOGIC IS DEFINED AT THE BEGINNING
#IFDEF IEEC_802
if(input_state(INPUT_PIN) == 1){ // IEEC 802 encoding
bit_set(WorkingtByte, CurrentBitPosition); // Sample input. Set appropriate bit if needed, leave 0 otherwise
}
#ELSE
if(input_state(data_inputs) == 0){ // Thomas encoding scheme
bit_set(WorkingtByte, CurrentBitPosition); // Sample input. Set appropriate bit if needed, leave 0 otherwise
}
#ENDIF |
Not here, where the actual sampling is done. And I can't find #define data_inputs pin_a1. Maybe I just missed it. As I missed it in the above code :-) |
|
 |
bulut_01
Joined: 24 Feb 2024 Posts: 317
|
|
Posted: Wed Jul 23, 2025 1:56 pm |
|
|
PrinceNai wrote: | Code: |
// DECODING LOGIC IS DEFINED AT THE BEGINNING
#IFDEF IEEC_802
if(input_state(INPUT_PIN) == 1){ // IEEC 802 encoding
bit_set(WorkingtByte, CurrentBitPosition); // Sample input. Set appropriate bit if needed, leave 0 otherwise
}
#ELSE
if(input_state(data_inputs) == 0){ // Thomas encoding scheme
bit_set(WorkingtByte, CurrentBitPosition); // Sample input. Set appropriate bit if needed, leave 0 otherwise
}
#ENDIF |
Not here, where the actual sampling is done. And I can't find #define data_inputs pin_a1. Maybe I just missed it. As I missed it in the above code :-) |
Thank you for your help, PrinceNai. The code is working fine now. The invisible side of the mountain will be a big problem from now on. |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 19929
|
|
Posted: Thu Jul 24, 2025 7:10 am |
|
|
INT_RA, like INT_RB, cannot be cleared unless the port is read.
Now your logic does not read the input on all states. It'll therefore loop
a second time and repeat until it gets to a state when the input is read.
Result incorrect logic..... |
|
 |
bulut_01
Joined: 24 Feb 2024 Posts: 317
|
|
Posted: Thu Jul 24, 2025 7:36 am |
|
|
Ttelmah wrote: | INT_RA, like INT_RB, cannot be cleared unless the port is read.
Now your logic does not read the input on all states. It'll therefore loop
a second time and repeat until it gets to a state when the input is read.
Result incorrect logic..... |
I don't know why you commented like that, the final version of the code works as we want. |
|
 |
bulut_01
Joined: 24 Feb 2024 Posts: 317
|
|
Posted: Thu Jul 24, 2025 8:29 am |
|
|
@princenai preamble bits ignore 0 Can I read data like this in the last code you sent ?
 |
|
 |
PrinceNai
Joined: 31 Oct 2016 Posts: 554 Location: Montenegro
|
|
Posted: Thu Jul 24, 2025 9:06 am |
|
|
Mr. T, first of all, thank you for spotting this. I didn't think about it. Funny thing is that the code works and on Pickit3 merrily steps out of interrupt, even with RBIF still set. I put a counter inside RB interrupt and ran the code to a breakpoint separately set in each state. It doesn't go wild at all. I don't know. Anyway, better to be safe than sorry, so i put clear_interrupt(INT_RB); on the entry to interrupt handler, which clears interrupt flag.
The other thing I did was to add some kind of error recovery. The code could get stuck, say if there were less bits than expected coming in. The code would wait for the next interrupt and only then reset. Because timer is never allowed to overflow while reception is in progress, any overflow now automatically resets state machine. For that reason
DecodeSwitch = PreambleRising; // Reset state machine if overflow happens during reception
is added to timer interrupt. I'll post the corrected code. |
|
 |
bulut_01
Joined: 24 Feb 2024 Posts: 317
|
|
Posted: Thu Jul 24, 2025 9:27 am |
|
|
After setting princenai preamble bits ignore to 0, can I read data like this in the code you last sent ? |
|
 |
PrinceNai
Joined: 31 Oct 2016 Posts: 554 Location: Montenegro
|
|
Posted: Thu Jul 24, 2025 9:32 am |
|
|
Quote: | After setting princenai preamble bits ignore to 0, can I read data like this in the code you last sent ? |
I'm sorry, I don't understand the question. What does a logic analyzer setting have to do with a reception and decoding on a PIC? |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|