ez1 code for Orangutan LV-168

Does anyone have code for the ez1 and the Orangutan LV-168 written with AVR Studio?

What are you hoping to do with the ez1? Like, say, display the range to the LCD? You should be able to modify the AVR Studio Demo Project 3 for the LV-168 Orangutan to read the analog output of the ez1.

Well, actually, if you just connect the analog output of the ez1 to the ADC7 pin (looks like it’s the pin farther away from the potentiometer of the “ADC7=POT” pair) and leave the RX pin of the ez1 unconnected (for continuous operation) the code should work as is. It will display the sonar range scaled to a 10-bit number, so if my math is right it will be reading out approximately in half inches. Throw in a little extra math and you can get it to display in whatever units you want. Watch out, the demo code also runs the motor ports. Actually, you might want to plug some motors in, that would be cool.

If you’re looking for something a little simpler I should have some old code at work for interfacing the ez1 to an Orangutan (classic, I don’t have an LV yet). Were you hoping to use one of the ez1 interfaces in particular?

-Adam

Wow, I was so close to trying project 3 with the ez1, but thought I would check first.

I am going to try this tonight to play, however, the motor thing is something I am not interested at this time so if you [Adam] have code with LCD display of measurement and without motor drive that would be very helpful.

Thanks,
Tony

Hello.

The following code is a modified version of demo project 3. I cut out the motor portion and changed the ADC channel from 7 (the trimpot) to 5 (the left-most I/O pin in the 8x3 I/O header). On the back of the board this pin is labeled “C5”. Connect the analog voltage output of your EZ1 to this pin and the LCD will display the result of the conversion (you’ll see a number between 0 and 1023, where 0 corresponds to 0 V and 1023 corresponds to 5 V. You can speed up the conversion process by averaging fewer samples, and you can do some math on the result to convert the voltage to a distance (the EZ1 datasheet might be able to give you more information on this, or maybe you can work out the conversion empirically).

- Ben

#include <avr/io.h>
#include "device.h"		// pinout definitions for the Orangutan LV-168
#include <util/delay.h>	// F_CPU is defined in "device.h" above
#include "lcd.h"		// provides routines for using the LCD


int main()
{
	lcd_init();	// this function must be called before any other LCD command


	// ***** 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 = 0x05;		// 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 5)


	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);				// go to the start of LCD line 1
		lcd_string("EZ1");
		lcd_gotoxy(0, 1);				// go to the start of LCD line 2
		lcd_int(avg);					// display average ADC as an integer
		lcd_string("   ");				// overwrite any LCD character remnants
	}


	return 0;
}

Ben,

I can’t get this to run without errors. Even the Project 3 runs with errors. Before you ask, yes I did put LCD.C, LCD.H and Device.h in the correct folder. When I don’t do that it give a total different error.

Any tougths?

Tony

It would help me if you could tell me what errors you are getting. Did you remember to add lcd.c to your AVR Studio project? It’s not enough for it to be in the same directory, you need to explicitly add it to the project. Also, do you have the most recent versions of WinAVR and AVR Studio?

- Ben

Ben,

I am putting lcd.h and so on into the folder that keeps the AVR studio .c file I create. That would be the project correct?
Here is the errors I get when I click build,

EZ1_1.o: In function main': ../EZ1_1.c:9: undefined reference tolcd_init’
…/EZ1_1.c:47: undefined reference to lcd_gotoxy' ../EZ1_1.c:48: undefined reference tolcd_string’
…/EZ1_1.c:49: undefined reference to lcd_gotoxy' ../EZ1_1.c:50: undefined reference tolcd_int’
…/EZ1_1.c:51: undefined reference to `lcd_string’
make: *** [EZ1_1.elf] Error 1
Build failed with 6 errors and 0 warnings…

As I said, putting the file in the project directory is not sufficient; you need to actually add the file to the AVR Studio project.

On the left side of your AVR Studio window you should see a docked panel titled “AVR GCC”. This panel shows you an expandable list view of all the files in your project (Source Files, Header Files, External Dependencies, and Other Files). Right click on “Source Files” in this list and choose “Add Existing Source File(s)…”. Select lcd.c and click “Open”. This will add lcd.c to your project. If you expand the Source Files list by clicking on the + to the left of it, you should now see two files: “EZ1_1.c” and “lcd.c”. Please let me know if this fixes the problem.

- Ben

Ben,

You are the man!!

Thanks so much for your extra effort helping me.

I am getting a reading, not sure yet what, but I am getting something and it changes when I put my hand over it. So I will play with it so see what I can do.

Tony

That’s great! Feel free to post if you have any more questions.

- Ben

Ben,

Been playing with the code you wrote me. If I set "avg = sum >> 9; to zero (0) instead of 9 it seem to be more accurate. Does that make sense to you? Also, would like the EZ1 to “not” loop continuosly. I know if I omit “while (1)” out of the code it wont loop continously and then I can hit the reset on the Orangutan and it will take another measure. Doing this I found that I can catch different wave lengths which is kind of cool, but not what I actualy need. Can the “While (1)” be codeed in such a way that the EZ1 will cycle a set amount then stop for so many ms then start another cycle and so on?

Tony

Hi, Tony.

If you change the 9 to a 0, you’re now displaying the lower two bytes of the the sum of 512 consecutive ADC values rather than the average, which is not what you want. If you want to decrease the number of samples in your average, change the code to something like:

int num_samples = XX;  // replace XX with the number of samples you want to average
for (i = 0; i < num_samples; i++) 
{ 
    ADCSRA |= ( 1 << ADSC );         // start conversion 
    while ( ADCSRA & ( 1 << ADSC ))      // wait while converting 
        ; 
    sum += ADC;                     // add in conversion result 
}
avg = sum / num_samples;
_delay_ms(10);  // defined in <util/delay.h>, argument must be < 13

If you just want to display the ADC values without any averaging, set num_samples to 1.

I’m not sure I understand what you’re trying to do. At the moment your Orangutan isn’t controlling the operation of your EZ1 at all; you have your EZ1 running continuously because you’re leaving its RX pin unconnected. If you want to control the operation of your EZ1, you need to connect its RX pin to your Orangutan and change your code to tell the EZ1 when to send out its sonar pings. The EZ1 instruction manual/datasheet should give you information on how to do this. Why don’t you want the EZ1 running continuously?

- Ben

Ben,
Let me try to clarifi, the numbers on the lcd are flipping so fast I can’t read them. I want it to continuosly measure, but I want to be able to read the numbers. So I thought slowing down the EZ1 by only displaying every 5th or 6th read instead of every single read would help. I’m not ready to revial what exactly I am doing yet, however, I will say this, I am basicaly wanting the device to give me a measuerment on the LCD in feet(example 1.5 feet). When I move the Orangutan closer or farther to an object it gives me a measurement. I have looked at the data sheet of the EZ1 but, that makes little sense to me. You have been of better help.

Tony

You don’t need to alter the behavior of the EZ1 to make the LCD output more readable. Probably the simplest solution would be for you to implement a delay in the display portion of your code. Create the following function:

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
}

And modify your existing code to read:

int num_samples = 100;  // number of samples you want to average 
for (i = 0; i < num_samples; i++) 
{ 
    ADCSRA |= ( 1 << ADSC );         // start conversion 
    while ( ADCSRA & ( 1 << ADSC ))      // wait while converting 
        ; 
    sum += ADC;                     // add in conversion result 
} 
avg = sum / num_samples; 
delay_ms(250);  // delay for .25 seconds
lcd_gotoxy(0, 0);            // go to the start of LCD line 1 
lcd_string("EZ1"); 
lcd_gotoxy(0, 1);            // go to the start of LCD line 2 
lcd_int(avg);               // display average ADC as an integer 
lcd_string("   ");            // overwrite any LCD character remnants

You can increase the value of the delay_ms function’s argument to slow down the LCD update rate until it’s something you’re happy with. In my code example above I use 250, which will mean the LCD updates approximately every 250 ms (4 times a second).

Or, you could change the code so that the LCD only updates when you push one of the user buttons. Have the program constantly compute a running average in the background and if a user button is pressed, update the LCD with the current average.

Or, instead of delays, you could use one of the AVR’s timers to determine when the LCD gets updated (demo 2 uses gives an example of how to use pushbuttons and timers).

- Ben

Ben,

I have been playing with the EZ1, trying to understand what it is telling me. Looking at the data sheet it states (Vcc/512) per inch and at 5V yeilds 9.8mV/in. Can you tell if the code you wrote for me above is outputing in mV? I wonder if the integers on the LCD are in need of a conversion to inches. It just does not make sense looking at the display in relation to distance measure.

Tony

My code is not displaying millivolts, it is displaying the ADC conversion value, which ranges from 0 at 0 V to 1023 at Vcc (5 V). If you want to convert this number to millivolts, you will need to multiply the output by 5000 and then divide by 1023 (or multiply by 4.89). If you want to convert to inches, you can apparently then divide that by 9.8 mV/in, or you can just multiply your conversion result by 4.89/9.8 = .499, which is quite close to 1/2. Therefore, you might get pretty accurate results by just bitshiftin the conversion result once to the right, which is the same as dividing by two.

- Ben