Hello,
I am trying to run code written by Paul O'Dowd on my UNO. Basically code is meant to detect 38khz signals using a photodiode. I dont want to use TSOP ir receiver that is why I am interested in this code.
I sucessfuly uploded code to my Arduino UNO board. I have connected IR photodiode as the author suggested. But there is no response from the board to a remote controller or my other ir transmitter. The line in processing serialgraph is flat, so i opened serial monitor changed baud to 57600, and it gives me constant zero. The board is sending over serial port, tx diode is lit but all i get is lots of zeros.
My first guess was that there is a problem witch the board, as the creator of the code used Arduino Duemilanove atmega 168 to run it. I have made some research and found that there are no differences between atmega168 and 328p that cause a problem in timer setup procedure.
Any ideas on how to make it work?
LINK to Paul O'Dowd project.
#include <avr/interrupt.h>
// Using timer0 disables millis() and delay()
// Using timer2 disables PWM analogue output.
// Not sure about timer 1.
// I think timer0 is best.
//
// Our program will work with a timer interupt service
// routine anyway, so delay shouldn't be necessary.
// You can always add an unsigned int to count and roll over,
// to take a delay from.
// Timer0 -> see around page 106 in atmega368/168 datasheet
//
// The important parts for the timer are the setup() and ISR()
// code.
//
// The interupt routine reads the analog A0 pin at 100khz.
// Read the comments through the code!
// Once an input buffer is full, the filter is run to
// produce a variable analog output of signal strength.
// Then the process loops.
//
// Once you are happy, remove the Serial port commands for
// best performance.
//
// The filter is a recursive band-pass described in this
// incredibly awesome and free book:
// http://www.dspguide.com/ch19/1.htm
// Definitions.
const int BUFFER_SIZE = 45; // use an odd number
// Global variables.
double buf[BUFFER_SIZE]; // Analog readings at 100khz & stored here
double out[BUFFER_SIZE]; // output of filter stored here.
int buffer_index; // Interupt increments buffer
boolean buffer_full; // Flag for when complete.
double a0,a1,a2,b1,b2; // filter kernel poles
double f,bw; // frequency cutoff and bandwidth
double r,k; // filter coefficients
void setup() {
// Clear global variables before the timer
// is activated.
for( int i = 0; i < BUFFER_SIZE; i++ ) {
buf[i] = 0;
out[i] = 0;
}
buffer_index = 0;
buffer_full = false;
// Set our anolgue input and use
// internal pull up resistor.
pinMode(A0, INPUT);
digitalWrite(A0, HIGH);
// Configure the trigger and frequency of our timer.
cli(); // disable interupts.
// Clear the control registers so we can OR in bits safely
TCCR0A = 0; // initialise control register to 0
TCCR0B = 0; // initialise control register to 0
TCNT0 = 0; // initialise the counter to 0
// We set no prescaler, meaning the interupt is clocked at 16mhz
TCCR0B |= (1 << CS00);
// Set the max compare value so we achieve 100khz,
OCR0A = 159; // (16000000) / (100000) -1 max value is 256
// OR in a bit to WGM01, setting it as CTC
// CTC = Clear Timer on Compare match
TCCR0A |= ( 1 << WGM01);
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
// Activate!!
sei();
// Lets sort out the filter variables before we end setup.
// Cut-off frequency.
// We are looking for a 38khz IR TV remote.
// F is fraction of the sample frequency
// It has to be between 0 and 0.5. Therefore, the interupt
// needs to be at least *double* the bandpass frequency.
// I picked 100khz as a nice number to scale from.
// So, f = (100khz * 0.38) = 38Khz
f = 0.38;
// Bandwidth (allowance) of bandpass filter.
// Same principle as above (fraction of 100khz).
// We are using this filter to get rid of ambient environment
// noise. 20khz seems like a big band, but I wouldn't expect
// there to be much in the khz. You can fine tune downwards.
bw = 0.2;
// Maths. Read the book. Does the trick.
r = 1 - ( 3 * bw );
k = 1 - ( 2 * r * cos(2 * PI * f ) ) + ( r * r );
k = k / (2 - ( 2 * cos( 2 * PI * f ) ) );
a0 = 1 - k;
a1 = (2 * ( k -r ) ) * ( cos( 2 * PI * f ) );
a2 = ( r * r ) - k;
b1 = 2 * r * cos( 2 * PI * f );
b2 = 0 - ( r * r );
// Activate serial port.
Serial.begin( 57600 );
Serial.println("Reset");
}
void loop() {
float output;
// We only do something once the buffer is full.
if( buffer_full == true ) {
// Run the input buffer through the filter
output = doFilter();
// We are going to transmit as an integer
// Move up the decimal place
output *= 1000;
Serial.println( (int)output );
// Reset our buffer and interupt routine
buffer_index = 0;
buffer_full = false;
}
}
// This filter looks at the previous elements in the
// input stream and output stream to compound a pre-set
// amplification. The amplification is set by a0,a1,a2,
// b1,b2. Please see the linked book, above.
double doFilter() {
int i;
double sum;
// Convolute the input buffer with the filter kernel
// We work from 2 because we read back by 2 elements.
// out[0] and out[1] are never set, so we clear them.
out[0] = out[1] = 0;
for( i = 2; i < BUFFER_SIZE; i++ ) {
out[i] = a0 * buf[i];
out[i] += a1 * buf[i-1];
out[i] += a2 * buf[i-2];
out[i] += b1 * out[i-1];
out[i] += b2 * out[i-2];
}
// Bring all the output values above zero
// To get a well reinforced average reading.
for( i = 2; i < BUFFER_SIZE; i++ ) {
if( out[i] < 0 ) out[i] *= -1;
sum += out[i];
}
sum /= BUFFER_SIZE -2;
return sum;
}
ISR(TIMER0_COMPA_vect) { // called by timer0 automatically evey 100khz
// Fills our input buffer from analog pin A0 until full and reset
if( buffer_index >= BUFFER_SIZE ) {
buffer_index = 0;
buffer_full = true;
} else if ( buffer_full == false ){
buf[ buffer_index ] = (double)analogRead(A0);
buffer_index++;
}
}