Baby Orangutan analogue inputs

Hello there.

I am trying to build a Maze exploration robot from scratch and have purchased the Baby Orangutan 328P and USB programmer. I am reasonably new to C programming and have never attempted a build from completely new before and i am struggling to understand how to read the anologue inputs.

I am using AVR Studio 4 and have read all of the documentation i can find on both the baby O and the ATmega328. So far i have used:
A. Baby Orangutan user guide
B. ATmega datasheet section 23
C. Pololu AVR command library reference

I am trying to create the lines of code required to read the anologue input which should be between the 5VCC and 0V. Utilise the Anologue to digital converters then read the 8 or 10bit word so that i can decide what my robot should do next.

So far, my approaches have been as follows:

  1. The Pololu AVR command library reference states that I can use simple lines of code as below,but i have been unable to compile this code as it is unrecognised.Do i require an additional #include to get this to work? As this looks like a very easy way to achieve my goal.
unsigned int analog_read(unsigned char channel)
  1. The ATmega datasheet makes the job look more complicated, but I managed to find some code posted on this forum by ‘Ben’ that helped me out tremendously.
	unsigned int read(unsigned char channel)
    {
       // Channel numbers greater than 31 are invalid.
       if (channel > 31)
       {
          return 0;
       }

       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
                   //  128 prescaler required for 10-bit resolution when FCPU = 20 MHz

       ADMUX &= ~(1 << 7);
       ADMUX |= 1 << 6;   // use AVCC as voltage reference

       ADMUX &= ~0x1F;   // clear channel selection bits of ADMUX
       ADMUX |= channel;   // we only get this far if channel is less than 32
       ADCSRA |= 1 << ADSC;   // start the conversion

       while (ADCSRA & (1 << ADSC));   // wait while ADC is converting

       if (ADMUX & (1 << ADLAR))   // if in 8-bit mode, result is left-adjusted
          return ADCH;         // so just return high byte of 16-bit ADC result register
       return ADC;            // else right-adjusted 10-bit result; return entire 16 bits
    }

I then added in a few lines of code of my own to attempt to use the read function.

void main(void)
{
unsigned int sense;
DDRD = (1<<DDD1);             //Sets LED to output
DDRC &= ~(1 << DDC0);	//Sets PortC pin 0 as input
PORTC = (1<<PC0);		//Drives PortC pin0 High

set_analog_mode(MODE_10_BIT);
while(1)
{
read(PINC0);         //utilise the read function with PINC0
sense = ADCH;       //Load the ADC value in the variable sense
if (sense>200);      //compare with set value
{
Blink();
}
}
}

This should compare the value of sense to a set value then blink the onboard LED if this is true. At the moment, all that happens is the LED blinks when i place a 0 or 1 as a comparison, or does nothing with any other value, and never seems to vary depending on the voltage applied to the input so I think I am doing something severely wrong here. I have tried whole numbers, HEX and Binary.

Hopefully i have been clear enough in my desciption but my head is a bit mushy after smashing it into the keyboard for about a week now.

Thanks in advance.

Apologies.

Here is my entire code.

// F_CPU tells util/delay.h our clock frequency
//#define F_CPU 8000000UL	// Orangutan frequency (8MHz)
#define F_CPU 20000000UL	// Baby Orangutan frequency (20MHz)
#include <avr/io.h>
#include <Stdio.h>
#include <stdlib.h>
#include <util/delay.h>
#include <pololu/orangutan.h>
	
	
void delayms( uint16_t millis ) {
	while ( millis ) {
		_delay_ms( 1 );
		millis--;
	}
}
	
	unsigned int read(unsigned char channel)
    {
       // Channel numbers greater than 31 are invalid.
       if (channel > 31)
       {
          return 0;
       }

       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
                   //  128 prescaler required for 10-bit resolution when FCPU = 20 MHz

       ADMUX &= ~(1 << 7);
       ADMUX |= 1 << 6;   // use AVCC as voltage reference

       ADMUX &= ~0x1F;   // clear channel selection bits of ADMUX
       ADMUX |= channel;   // we only get this far if channel is less than 32
       ADCSRA |= 1 << ADSC;   // start the conversion

       while (ADCSRA & (1 << ADSC));   // wait while ADC is converting

       if (ADMUX & (1 << ADLAR))   // if in 8-bit mode, result is left-adjusted
          return ADCH;         // so just return high byte of 16-bit ADC result register
       return ADC;            // else right-adjusted 10-bit result; return entire 16 bits
    }


void Blink(void)
{
		PORTD &= ~( 1 << PORTD1 );	// LED off
		delayms( 900 );				// delay 900 ms
		PORTD |= 1 << PORTD1; 		// LED on
		delayms( 100 );				// delay 100 ms
		PORTD &= ~( 1 << PORTD1 );	// LED off
	return 0;
}

void main(void)
{

int sense;
DDRD = (1<<DDD1); //Sets LED to output
DDRC &= ~(1 << DDC0);	//Sets PortC pin 0 as input
PORTC = (1<<PC0);		//Drives PortC pin0 High

set_analog_mode(MODE_10_BIT);
while(1)
{
read(PINC0);
sense = ADCH;
if (sense>1)
{
printf("%d",sense);
Blink();
}
}
}

Hello.

Have you tried following the advice in the Using the Pololu AVR Library for your own projects section of Pololu AVR C/C++ Library User’s Guide? With that, you should be able to compile a program that uses our analog read, delay and LED functions, making your code a lot simpler.

- Ryan

Hello.

Before making your own programs as Ryan is suggesting, you should really start by loading our example projects that you downloaded along with the Pololu AVR library. Specifically, you should look at the analog1 and analog2 example projects, which are very simple and should compile as is if you have the library installed properly. Once you understand how these examples work, I suggest your next step be to modify them for your own program (working off a copy of the example project will be easier than trying to create one from scratch because the copy will already be properly configured to use the Pololu AVR Library).

You can find out more about the analog1 and analog2 example programs in the Pololu AVR Library user’s guide.

- Ben

Thanks guys!!! Thats amazing. Believe me when i say i thought i had looked everywhere for that information you guys just linked but i must have ignored that one page that tells you which #includes to use and how to set up the library.

I had read the anolog1 and analog2 programs mulitple times to try and understand them and have managed to get it to work on my baby O now which is great! However from reading the library, it states that the “analog_read(unsigned char channel)” performs a single ADC, so can i not just use this function to do something like this? Or am i being too hopeful? My plan would be to activate the sensor on PINB by sending a bit high, reading the result then deactivating the sensor and utilising the result to get blink the LED.

set_analog_mode(MODE_8_BIT);

while(1)
{
PINB=1;
sense = analog_read(PINC0);
PINB=0;
if (sense>150)
{
Blink();
}
}
}

The answer to your question depends a lot on your sensor. For example, are you sending a signal to it with your I/O line or are you powering it through the I/O line. If the latter, are you sure the I/O line can deliver the necessary current, and is there a good reason for complicating things by turning it off after every reading? Will the sensor output be available immediately after powering it or do you need to wait? The analog_read() function reads and returns the voltage on the specified analog input. It is up to you to make sure the proper voltage is on that channel when you try to read it!

Note that the PINC0 argument you used for your analog_read() function is intended for digital I/O and is not appropriate for use as an analog channel. It happens to work on the Baby Orangutan’s AVR, but it is not guaranteed to work on all AVRs. The argument to this function should be an integer representing the analog channel you want to read. On the Baby Orangutan, PC0 is channel 0, PC1 is channel 1, …, and PC5 is channel 5 (ADC6 and ADC7 are channels 6 and 7, respectively). Therefore, this line should read:

sense = analog_read(0);

or you could generalize it as:

sense = analog_read(SENSOR_CHANNEL);

where SENSOR_CHANNEL is a constant defined as an integer from 0 to 7 elsewhere in your program.

Also, note that PINB = 1 is probably not doing what you think it is, and PINB = 0 doesn’t do anything at all as far as I know (I don’t have time to verify this in the datasheet right now, so hopefully someone will correct me if I’m wrong about this). If you want to do digital I/O, I suggest you look at our digital I/O functions in the Pololu AVR library command reference and the library’s digital1 example program.

- Ben

Thanks very much for your help.

Thats given me a lot to work with and hopefully i can get somewhere on my own now…although i think i might have just fried a sensor :smiley:

I got it working!!! Well…you got it working for me. And the sensor wasn’t fried, it just didn’t like being turned off and on again. :laughing:

Thanks so much for your help.

I’m very glad to hear things are working for you. Good luck with your project!

- Ben