I/O question in programming

Correct. Could you help me in achieving that? The IR beacon works great in this code and displays correctly using PC0,1,2,3. I want to use PC4 on the transmitter (baby-o) side and display DIST: on the recieve side.

Tony

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

Adam,

loaded the Orangutans with your new code. The result on the LCD is odd. Information is oreiented correctly however, data just flips and does not seem to be working with the sensors, both beacon and EZ1. Rather a random pattern of DIST: numbers and my directional arrows are flipping all around not connected to the beacon. I have proven the radio is working because if I turn off the baby the data on the big stops. FYI, the input for the EZ1 of course is my hand waving in front of it and the beacon input is the paired second beacon moving in front of the beacon attached to the baby.

Have I explained this enough for you, if not let me know and I can take another stab at it.

Tony

Very odd. I’m going to bring my baby-Orangutan into work tomorrow so I can try this out between the two at once.

The number jumping around alone doesn’t surprise me that much though, sonar readings can be pretty erratic. Does the number stabilize, or maybe just jump back and forth between two adjacent numbers, if you leave the sonar sitting on a table aimed at a flat wall, or the ceiling?

In any case that shouldn’t be affecting the beacon readout.

-Adam

That code works perfectly for me. The sonar reading (on PC4) varies properly as I move my hand closer and farther away from the sonar, and the directional readings stay put. I don’t have an IR beacon, but I’m faking one by pulling PC0-PC3 high with resistors than pulling one low at a time. The other thing I don’t have handy is a set of serial radios, so I’m wiring ground and TX->RX between the baby and big Orangutans. I know you had the radio working already, but you might want to try wiring your two Orangutans together again and seeing what happens.

-Adam

Adam,

I will try your suggestion of wiring direct when I get a chance.

I do know if I load your starting point code on the big and put the EZ1 there and then load my original code on the baby, it works together perfectly, the EZ1 is just not wireless. I could not run the EZ1 and the beacon on the LCD of the big together until your starting point code. I am going to look at them both a little closer and see if see where I can hack them.

Tony