A common task in most home electrical engineering projects is to reverse engineer a signal from a device. This could be an IR receiver, a serial connection or in my case a radio receiver. What is needed is a way to record this signal and send the data to a computer so it can be analysed for patterns and eventually decoded.
Whilst specialised hardware does exist, or obscure hacks using the soundcard for input, I didn't fancy doing that.
In essence what is required is the following:
loop
{
wait for pin to change
{}
send the time of this event to the serial port
}
The problem with this is that sending data to the serial port is a very slow operation, the RF signals I was trying to capture were alternating high and low with gaps of around 200 microseconds. The processor will take a while to send data out to the serial port and osciallations get missed.
The solution I found was to buffer the data, and then send the data and then send this data to the serial port once a reasnoble sample had been collected. This provided enough data to analyse without missing any gaps. The ATMega has a data storage area of 1Kb, given an int takes two bytes we can have an array of the pulse length of 450 of these oscillations. The output is a list of the time the processor with the pin low, followed by the time the pin was high, then back to low and so forth.
Another problem that had to be avoided was noise. Particularly dealing with AM radio signals small blips would appear in my data. Whilst most engineers would solve this was clever hardware, I'm a code hacker and decided to filter this into my code. Any pulse of data under 20 microseconds is treated as noise. That pulse is thrown away and it acts as though the previous pulse never ended.
Without further waffling, here is the code I used:
boolean currentState = LOW;
unsigned long timeStart;
unsigned int times[450];
unsigned int index = 0;
void setup() // run once, when the sketch starts
{
pinMode(12, INPUT);
Serial.begin(9600);
timeStart = micros();
}
void loop() // run over and over again
{
while(digitalRead(12) == currentState) //wait for state change
{}
//make it wait for the next type of state change next run
if (currentState)
{
currentState = LOW;
}
else
{
currentState = HIGH;
}
unsigned long duration = micros() - timeStart;
if ( duration > 20 || index == 0)
{
times[index] = duration;
timeStart = micros();
index++;
}
else
{
//the last pulse was really tiny, probably just noise. That means we should just revert the add we did last time, and pretend it never happened
//next pulse change replaces the last recorded entry (entry before this one)
index--;
//set timeStart back to the time the pulse without noise started
timeStart = micros() - times[index] - duration;
}
//if we're out of storage space send all the data.
if(index >=450)
{
printResult();
}
}
void printResult(void)
{
for(unsigned int i = 0 ; i < index ; i++)
{
Serial.println(times[i]);
}
index = 0;
}
No comments have been left