Convert ADC value from Potentiometer to INT

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hey all,

I'm working on a project where I have my LCD display attached to one port of my ATmega32, one LED
to the OC1A on PD5 and a linear potentiometer to one ADC pin.

I've got some code that I modified to work with my uC so that I can read the value of the pot and output it
to the led, in the result of varying the brightness.

So far all good, works like a charm :D

Question 1;
However, on the LCD display I want to show the value that I'm sending to the OC1A and the result I get by
showing it directly on the LCD screen is that when I turn the pot, the LCD scrolls through all the chars
that is programmed to the LCD by default.

This is obviously not the result I'm after so, I'm wondering if someone could help me out with understanding
how to convert the uint8_t value to for example either "1-255" or "1-100"..

Question 2;
Also, please comment the while() and if() part of the code, would you do like this or would you do in any other way?

At first I let the LCD go on the main while() and just updated hundreds of times per second which in result
gave a flickering screen, I put some delay to the update and sure I got it better (non flickering),
but the resolution on the reading of the pot got worse, that was ok I guess (it got delayed).

Question 3;
But now I'm only updating the display if the pot value has changed and it looks like it's better as I can't see
any flickering at all on the screen. Not even while turning the pot, so that's good right?

Question 4;
Final question, I'm using a linear variable resistor / potentiometer as I was told to use. I know what this
piece does and that is to change the resistance between two outer legs compared to the middle pin,
that's simple and easy to understand.

It's so easy to understand that I'm wondering if this is such a good idea to use, because if I'm turning the
pot the LCD display shows the difference ( by showing all these crazy and normal characters ) flickering
through and if I stop turning the pot it seems to be flickering between one character and another as if
the ADC gets a value from "in between" two characters, does anyone understand what I'm saying?

The only time the "character" stays solid is if I turn it all the way to one or the other side so the pot
is pointing in the end of the pot.

I do want a high resolution pot, like this seems to be, but would an encoder be better or would I get less
"positions", if you get what I mean?

I think that's all that I have for now, below are the output on my LCD display and the code.

EDIT: OOh, I just remembered.. any better solution to the Wait() function I got?
I'd like a delay on like 1-2 seconds or the like.. emulated or real doesn't really matter..
just "around" 1 or 2 seconds would be nice, it there are any such solutions ;)

/**********************************************************************************
Thanks:	Peter Fleury    http://jump.to/fleury
		LCD Library

		Aki Korhonen, article on MetkuMods 2009-05-06
		http://metku.net/index.html?path=articles/microcontroller-part-2/index_eng

		Parts taken from both parties and some code written by Chris Fredriksson.
***********************************************************************************/
#ifndef F_CPU
	#define F_CPU 1000000UL // 1 MHz
#endif

#include 
#include 
#include 
#include "lcd.h"

#include 
#include 

void Wait()
{
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
 _delay_loop_2(32000);
}


int main(void)
{
	DDRD = 0x20;

    DDRD &=~ (1 << PD2);        /* Pin PD2 input              */
    PORTD |= (1 << PD2);        /* Pin PD2 pull-up enabled    */

	// Value for the register, placeholder
	uint8_t value = 0;
	uint8_t valuecompare = 0;

	// -------------------------
	// Initialize PWM

	// 8-bit PWM, Phase correct
	// 8 bits give us 256 levels of brightness
	TCCR1A |= (1<<WGM10);

	// Clear OC1A/OC1B on Compare Match
	// Set OC1A/OC1B at BOTTOM (non-inverting mode)
	TCCR1A |= (1<<COM1A1);

	// Set prescaler to 8
	// 1 MHz / 8*256 = ~490 Hz PWM frequency
	TCCR1B |= (1<<CS11);

	// -------------------------
	// Initialize ADC
	
	// Enable ADC
	ADCSRA = (1<<ADEN);

	// Select ADC0
	ADMUX |= (0<<MUX0);

	// Use Vcc as voltage reference
	ADMUX &= ~(1<<REFS1) | ~(1<<REFS0);
	
	// Select divider factor 8, so we get 1 MHz/8 = 125 kHz ADC clock
	ADCSRA |= (1<<ADPS1) | (1<<ADPS0);


    /* initialize display, cursor off */
    lcd_init(LCD_DISP_ON);

	lcd_clrscr();
	lcd_puts("Startup message\nHello World?!");
	Wait();
	Wait();
	Wait();
	Wait();

    // Clear display and cursor position
    lcd_clrscr();
    
    // Put string to display
    lcd_puts("Controller\n");

    while (1)                           // loop forever
	{

		// Write the value to the Output Compare Register A
		OCR1A = value;

		// what happens here??
		value = (uint8_t)(ADCW/4);
		
		// Start ADC conversion
		ADCSRA |= (1<<ADSC);
		
		// has the value changed? if so, update the LCD display
		if ( value != valuecompare )
		{
			// Goto this position; Character 1, Line 2
			lcd_gotoxy(0,1);

			// Put string to display
			lcd_puts("Volume: \n");
			
			// Goto this position; Character 9, Line 2
			lcd_gotoxy(8,1);

			// Write single character to display
			lcd_putc(value);
			
			// Set the value to compare with, to see if value has changed
			// if it has changed it will update the LCD display
			valuecompare = value;
		}
    }
}

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I'm wondering if someone could help me out with understanding
how to convert the uint8_t value to for example either "1-255" or "1-100".

Use atoi().
Quote:
But now I'm only updating the display if the pot value has changed and it looks like it's better as I can't see any flickering at all on the screen. Not even while turning the pot, so that's good right?

So you answered #2 yourself. :)

Quote:
as ifthe ADC gets a value from "in between" two characters,

You probably do not have a stable source, so there is error creeping in.

Quote:
EDIT: OOh, I just remembered.. any better solution to the Wait() function I got?

Use _delay_ms().

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

wonderful answers, will look that up! :)
however, that's tomorrows story, going to bed now ;) hehe

thanks for helping out!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

well I searched for atoi and found some info about that, but when I tried I got a complete corrupted display
showing all sorts of crazy characters I also got a compile error;

"../main.c:117: warning: passing argument 1 of 'atoi' makes pointer from integer without a cast"

I searched that and found out that someone was trying to feed atoi an integer instead of a string.
Somehow I found the itoa function and tried that and I actually got it to work :D

However, I still get these compile errors;

../main.c:111: warning: assignment makes integer from pointer without a cast
../main.c:117: warning: passing argument 1 of 'lcd_puts' makes pointer from integer without a cast

on line 111 I got the following code;

intstr = itoa(value,buffer,10);

value = value from the ADC ( value = (uint8_t)(ADCW/4); )
buffer = is set in the top as "char buffer [33];", without quotes
10 = and this number I found out to be the decimal base according to the following site;

http://www.cplusplus.com/referen...

the decimal base gives me from 0 to 255 which is what I'm looking for :D
but I still get an compile error on the itoa line, so what may be wrong?

on line 117 I got the following code;

lcd_puts(intstr);

meaning, this is where I print the converted value string to the LCD display..
also an error, what may that be?

I searched for it on Google and I didnt really find any consistent answer to the problem
or am I wrong, maybe I'm too tired to find it? bit early in the morning here ;)

the _delay_ms() did great =)

talking about the stable source, meaning the +5 power supplied or the pot itself?
probably the +5 supplied, I'm running it on the STK500, perhaps it's not stable enough?

I really need to make an own board for this project.. so I wont stress the STK500 as well
as getting it more stable perhaps on its own board..

any quick and dirty solution to get a more stable supply?
this I'm not so good about, so using a 7805 would help or adding a capacitor perhaps?

final question for now before I finally go to bed ;)
I'm looking for another delay function, not to stall the uC like the _delay_ms function
which I needed for the start of the uC..

but now I need a delay that when I stop turning the pot it should activate this timer,
count to say "1-2 seconds" and then execute a display clear command and then show a "ready" message..

I tried with defining a uint16_t variable, then when the "timer" got activated this timer
would count up to 32000 and then clear the screen.

This however, sure it worked, but didn't really give me the time I wanted, while it still made
the uC accessible if I started turning the pot again, which _delay_ms would have prevented..

so, is there any such function available or will I have to write an own function that will
count to 32000 like 5 times or so, maybe that will give me the 1-2 seconds before reset that I want?

I hope anyone feel like reading through my post, I dont even feel like reading it myself..
I'm too sleepy.. *yawn*

anyway, I hope that I'm on the right track, otherwise help me to face the right direction! :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
lcd_puts(intstr);

You don't say how intstr is declared (it should be a char*), but you don't need it anyways. Just use the buffer you sent in to itoa:

itoa(value, buffer, 10);
lcd_puts(buffer);
value = value from the ADC ( value = (uint8_t)(ADCW/4); ) 

Check out the left adjust functionality of the ADC. With that you can just use ADCH and skip the divide.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I tried with defining a uint16_t variable, then when the "timer" got activated this timer
would count up to 32000 and then clear the screen.

This is what the on board timers are for.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

a great, more great answers :D
I will have a look and see what I can manage to do, thank you! :D