After actually working through your code I noticed a few mistakes. You seemed to be mixing up UART and ADC registers. Just so we’re on the same page, I brought Ben’s sonar reading code back in to your receiver code. Also reading the UDR0 register multiple times was causing a few things to get loopy. I added a variable called beaconState to holds the value of the incoming serial byte, so we only have to read the register once.
So, here’s a starting point with the big Orangutan receiving just the beacon state from the baby O over the radio, and directly reading and displaying (in approximate inches) the Sonar analog output on PC4:
#define F_CPU 20000000//CPU clock
#define BAUD 2400//baud rate for UART
#define MYUBRR (F_CPU/16/BAUD-1)//baud rate variable for UART hardware
#include <avr/io.h>
#include <avr/interrupt.h>
#include "device.h"
#include "lcd.h"
unsigned char newBeaconState=0;
unsigned char beaconState;
ISR(USART_RX_vect){//USART Byte reieved
newBeaconState=1;
beaconState=UDR0;
}
void USART_Init(unsigned int ubrr){//Initialize USART hardware & settings for Serial Radio
UBRR0H=(unsigned char)(ubrr>>8);//set buad rate
UBRR0L=(unsigned char) ubrr;
UCSR0B=(1<<RXEN0);//enable reciever
UCSR0B|=(1<<RXCIE0);//enable recieve complete interrupt
UCSR0C=(3<<UCSZ00);//Set frame format for 8bit with 1 stop
}
void delay_ms(unsigned int time_ms) // delay for time_ms milliseconds
{
while (time_ms--)
delay_ms(1); // defined in <util/delay.h>, argument must be < 13
}
int main(){
lcd_init(); // this function must be called before any other LCD command
USART_Init(MYUBRR);//Initialize serial USART
// ***** ADC INITIALIZATION *****
ADCSRA = 0x87; // bit 7 set: ADC enabled
// bit 6 clear: don't start conversion
// bit 5 clear: disable autotrigger
// bit 4: ADC interrupt flag
// bit 3 clear: disable ADC interrupt
// bits 0-2 set: ADC clock prescaler is 128
ADMUX = 0x04; // bit 7 and 6 clear: voltage ref is Vref pin
// bit 5 set: right-adjust result (10-bit ADC)
// bit 4 not implemented
// bits 0-3: ADC channel (channel 4)
sei();//enable global interrupts
while (1){ // loop forever
long sum = 0;
unsigned int avg, i;
// Here we accumulate 512 conversion results to get an average ADC.
// According to the mega168 datasheet, it takes approximately 13
// ADC clock cycles to perform a conversion. We have configured
// the ADC run at IO clock / 128 = 20 MHz / 128 = 156 kHz, which
// means it has a conversion rate of around 10 kHz. As a result,
// it should take around 50 ms to accumulate 500 ADC samples.
for (i = 0; i < 512; i++){
ADCSRA |= ( 1 << ADSC ); // start conversion
while ( ADCSRA & ( 1 << ADSC )) // wait while converting
;
sum += ADC; // add in conversion result
}
avg = sum >> 9; // a.k.a. avg = sum / 2^9 = avg / 512
// typically, bitshifting is faster than division
lcd_gotoxy(0, 0);
lcd_string("DIST:");
lcd_int(avg>>1); // display average ADC as an integer, divided by 2 for aprox inches
if(newBeaconState){
newBeaconState=0;
lcd_gotoxy(0, 1); // go to the start of LCD line 2
if(!(beaconState&(1<<PC1))){//east detected, do something
lcd_string("<-- "); // write a character
}
if(!(beaconState&(1<<PC2))){//south detected, do something
lcd_string(" <> "); // write a character
}
if(!(beaconState&(1<<PC3))){//west detected, do something
lcd_string(" -->"); // write a character
}
else{
lcd_string("NOSIGNAL"); // write a space
}
}
}
return 0;
}
I just tried this out on my original Orangutan (with a 20MHz clock, just like your LV Orangutan) and it seems to work fine.
Now, to transmit all this information you’re going to need more than just one byte of data. I moved the sonar ADC code over to the transmitter program (still on PC4), and rewrote it a little to send bytes in sets of 3. First is a ‘start’ byte, with a value of 255 (the maximum number one byte can hold). No other byte will be 255, so the receiver knows that it should begin listening for new beacon and sonar information after seeing a 255 byte. Next the transmitter sends the beacon state, but instead of sending all of PORTC, it sends (PINC&0x0F), which is only the lower four bits. This way the byte value can only be 0 to 127, and can never be 255 (i.e. a false start byte). Last, the transmitter sends the sonar reading, in approximate inches, between 0 and 254.
Code for the Baby Orangutan Transmitter:
#define F_CPU 20000000//CPU clock
#define BAUD 2400//baud rate for UART
#define MYUBRR (F_CPU/16/BAUD-1)//baud rate variable for UART hardware
#include <util/delay.h>
#include <avr/io.h>
void USART_Init(unsigned int ubrr){//Initialize USART hardware & settings for Serial Radio
UBRR0H=(unsigned char)(ubrr>>8);//set buad rate
UBRR0L=(unsigned char) ubrr;
UCSR0B=(1<<TXEN0);//enable transmitter
UCSR0C=(3<<UCSZ00);//Set frame format for 8bit with 1 stop
}
void USART_Trans (unsigned char data){//Transmit a byte of data over USART
while(!(UCSR0A&(1<<UDRE0)));//wait for transmition to complete
UDR0=data;
}
int main(){
DDRC&=~((1<<PC0)|(1<<PC1)|(1<<PC2)|(1<<PC3));//Configure PortC IO
USART_Init(MYUBRR);//Initialize serial USART
// ***** ADC INITIALIZATION *****
ADCSRA = 0x87; // bit 7 set: ADC enabled
// bit 6 clear: don't start conversion
// bit 5 clear: disable autotrigger
// bit 4: ADC interrupt flag
// bit 3 clear: disable ADC interrupt
// bits 0-2 set: ADC clock prescaler is 128
ADMUX = 0x04; // bit 7 and 6 clear: voltage ref is Vref pin
// bit 5 set: right-adjust result (10-bit ADC)
// bit 4 not implemented
// bits 0-3: ADC channel (channel 4)
while(1){
long sum = 0;
unsigned int i;
unsigned char dist;
// Here we accumulate 512 conversion results to get an average ADC.
// According to the mega168 datasheet, it takes approximately 13
// ADC clock cycles to perform a conversion. We have configured
// the ADC run at IO clock / 128 = 20 MHz / 128 = 156 kHz, which
// means it has a conversion rate of around 10 kHz. As a result,
// it should take around 50 ms to accumulate 500 ADC samples.
for (i = 0; i < 512; i++){
ADCSRA |= ( 1 << ADSC ); // start conversion
while ( ADCSRA & ( 1 << ADSC )) // wait while converting
;
sum += ADC; // add in conversion result
}
dist = sum >> 10; // a.k.a. dist = sum / 2^9 = avg / 512, divided again by 2 for aprox inches
// typically, bitshifting is faster than division
if(dist==255){
dist=254;//only start byte can be 255
}
USART_Trans(255);//transmit start byte
USART_Trans(PINC&0x0F);//Transmit lower four bits of pinc (beacon state)
USART_Trans(dist);
_delay_ms(10);
}
return 0;
}
Finally, here is some code for the big Orangutan receiver. It waits until it receives a start byte, then stores the next two bytes in an array. When it has received the two data bytes, it displays them on the screen.
Code for the Big Orangutan Receiver:
#define F_CPU 20000000//CPU clock
#define BAUD 2400//baud rate for UART
#define MYUBRR (F_CPU/16/BAUD-1)//baud rate variable for UART hardware
#include <avr/io.h>
#include <avr/interrupt.h>
#include "device.h"
#include "lcd.h"
unsigned char newBeaconState=0,beaconIndex=0,UDRGrab;
unsigned char buff[2]={0,0};
ISR(USART_RX_vect){//USART Byte reieved
UDRGrab=UDR0;//read the byte right away
if(UDRGrab==255){//new beacon state
beaconIndex=0;//reset the index
return;//exit and wait for more bytes
}else if(beaconIndex<2){
buff[beaconIndex]=UDRGrab;//store the byte
beaconIndex++;//increase the index
if(beaconIndex==2){//received both bytes
newBeaconState=1;
}
}
}
void USART_Init(unsigned int ubrr){//Initialize USART hardware & settings for Serial Radio
UBRR0H=(unsigned char)(ubrr>>8);//set buad rate
UBRR0L=(unsigned char) ubrr;
UCSR0B=(1<<RXEN0);//enable reciever
UCSR0B|=(1<<RXCIE0);//enable recieve complete interrupt
UCSR0C=(3<<UCSZ00);//Set frame format for 8bit with 1 stop
}
void delay_ms(unsigned int time_ms){ // delay for time_ms milliseconds
while (time_ms--)
delay_ms(1); // defined in <util/delay.h>, argument must be < 13
}
int main(){
lcd_init(); // this function must be called before any other LCD command
USART_Init(MYUBRR);//Initialize serial USART
sei();//enable global interrupts
while (1){ // loop forever
if(newBeaconState){
newBeaconState=0;
lcd_gotoxy(0, 0);
lcd_string("DIST:");
lcd_int(buff[1]); // display average ADC as an integer
lcd_gotoxy(0, 1); // go to the start of LCD line 2
if(!(buff[0]&(1<<PC1))){//east detected, do something
lcd_string("<-- "); // write a character
}
if(!(buff[0]&(1<<PC2))){//south detected, do something
lcd_string(" <> "); // write a character
}
if(!(buff[0]&(1<<PC3))){//west detected, do something
lcd_string(" -->"); // write a character
}
else{
lcd_string("NOSIGNAL"); // write a space
}
}
}
return 0;
}
There are some big code changes in here, so feel free to ask questions if any of this doesn’t make sense. Also, I generally try not to post code I haven’t completely tested, but I only have one Orangutan that isn’t embedded in a project right now, so I tested the two programs separately. I’m fairly sure they’ll work together though, but I guess you’ll have to answer that question.
-Adam