First, let's find, what's wrong with your method. You try to poll the signal pins continously and write them out to serial. Default serial rate is 9600. Which means, that you can transmit approx. 900 characters per second. Looking at your oscillogram we can tell, that the signal you want to analyse has a base clock of roughly 2.5 kHz. Which means you definitely won't be able to sample every change of level with your method.
You can in fact use the loop()
function to listen for changes, i.e. poll the signal, when you increase your serial baud rate. But I suggest using interrupts.
My suggestion is a three step process.
- get the signal thoroughly recorded with all relevant information about the signal. This includes transmission to your PC via serial interface.
- Analyse the signal offline. i.e. after having it received on your PC
- Adapt your arduino code to decode it further before transmitting it to your PC
let's get to part 1):
read Arduino documentation on interrupts
the interrupt allows you to prevent interference of your two tasks (reading the inputs and writing to serial).
What is the interesting information? I think it's the waveform (i.e. the signal in best resolution you can deliver). You can sample your waveform at a high rate, but the resulting data volume will overwhelm your serial output. Fortunately your signal has some obvious characteristics. Which are:
- obeys some timing (i.e. a clock)
- has a limited transmission length (protocol frame)
- has a limited transmission rate (as can be seen from oscillograph)
The best way to keep as much of the signal information by reducing the amount of serial transmission is to record the time of every level change.
Updates: buffer used, buffered output after receiving timeout
#define RECVTIMEOUT 2000 // we think, more than 2000 usec is end of transmission
#define MAXEVENTS 100
uint8_t inpin=2;
volatile unsigned long timestart=0;
uint8_t transmitLevel=LOW;
volatile uint8_t state=0; // little state machine: 0=nothing happened yet, 1=receiving data, 2=receiving timeout
volatile uint16_t tstamps[MAXEVENTS]; // we store timestamps of received symbols here
volatile uint16_t levels[MAXEVENTS]; // we store levels of received symbols here
volatile uint8_t index=0; // we save index of data here.
uint8_t count=0; // counter for later use.
volatile bool conflict=false; // will be set, if transmission conflicts with receive function.
void pinchange() // the ISR (interrupt service routine)
{
switch(state)
{
case 0:
timestart=micros();
tstamps[index]=0;
levels[index]=digitalRead(inpin);
state=1;
++index;
break;
case 1:
tstamps[index]=micros()-timestart;
levels[index]=digitalRead(inpin);
++index;
break;
case 2:
conflict=true;
}
}
void setup()
{
Serial.begin(115200); // high serial rate. don't forget to set the same in your IDE
attachInterrupt(0, &pinchange, CHANGE); // the controller needs to know, where your ISR is.
}
void loop()
{
switch(state)
{
case 1:
if (index > 20)
{
if (micros()-timestart > RECVTIMEOUT)
{
state=2;
}
}
if (index >= MAXEVENTS)
{
state=2;
}
break;
case 2:
for (count=0; count<index; ++count)
{
Serial.print(tstamps[count]);
Serial.print(";");
Serial.println(levels[count]);
}
if (conflict)
{
Serial.println("too less time to send data");
}
index=0;
conflict=0;
state=0;
}
}
This should output a fine csv with all your signal edges in microseconds, which you can paste directly to your favourite spreadsheet application. This is only for one signal. For analysing both, you have to enhance it accordingly.
Update 1
part 2)
from the gained data of our previous code version (snippet for brevity)
time signal timedifference
2614592 0 468
2615056 1 464
2615524 0 468
2616496 0 972
2616960 1 464
2617956 0 996
2618960 1 1004
2620424 1 1464
2621352 1 928
2622324 1 972
2623320 0 996
we can see two things.
- The code in my first version of the answer didn't work properly. Every 1 should be followed by a 0 in column 2 and vice versa. This is apparently not true, which leads us to the conlusion, that we missed some events.
- time differences seem to be multiples of roughly 470 μs. We can consider this as the length of a symbol.
So what's wrong with the code? I used noInterrupts() to stop Interrupts for copying the data. I hoped, there won't be level changes in this short period of time, but apparently this was not true. How to fix it? We better find another way to register the events and transfer them.
I recommend sticking to the interrupt technique, but changing the way we store the events and reading it out. Let's use a buffer big enough for all events of a transmission. After a transmission we can send all data without hassle via serial to the PC.
What can we expect? 0s and 1s should be transmitted alternating, with reasonable timings. If we can prove this, we can change the main loop again for decoding code 39.
part 3)
- write code which stores a word of code 39 in a buffer
- another code which decodes that word into a byte when the buffer is full
- transmit that byte via serial
(many improvements possible).