Give me some tips to improve my program

For Adafruit customers who seek help with microcontrollers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
soggybag
 
Posts: 35
Joined: Sat Mar 01, 2008 3:28 am

Give me some tips to improve my program

Post by soggybag »

I have a small program that generates a random PWM output, that changes at a rate determined by a pot. The program I have works, but not as well as it could.

I used a loop, looping a number of times determined by value read from the ADCH from the pot. Within the loop I call _delay_ms(10). I see that this is a crude system, and I could live with it. But, it has a few problems.

First, the main thing is the timing as set by the rotation of the pot feels non-linear. Most of the change is bunched up at one end of the pot rotation.

Second, at the slow end I notice a lag in response, as the loop needs to finish before the pot is read again.

Last, I know there must be a better way. I need a few suggestions to point me in the right direction. Your input is greatly appreciated!

I'm using an attiny13, avr-gcc and avrdude.

Here's a sample of the code I'm using at the moment.

Code: Select all

while ( 1 ) { // Main program 
 
    		ADCSRA |= ( 1 << ADEN );          // Analog-Digital enable bit
    		ADCSRA |= ( 1 << ADSC );          // Discard first conversion
        	while ( ADCSRA & ( 1 << ADSC ) ); // wait until conversion is done
    		ADCSRA |= ( 1 << ADSC );          // start single conversion
        	while ( ADCSRA & ( 1 << ADSC ) )  // wait until conversion is done
    		ADCSRA &= ~( 1 << ADEN );         // shut down the ADC
		//----------Set rate of blinking based on ADCH byte---------
 		for ( i = 0 ; i < ADCH ; i++ ) { // Loop x time until i reach ADCH value
    			_delay_ms( 10 );                   // Loop delay
		}
		brightness = (uint8_t) rand();	// Need a random number from 0 - 255
		OCR0A = brightness;
	}


Here's the entire application in case it's relevant:

Code: Select all

/* 
* Sample and Hold Demo. Flashes an LED at a random brightness at a rate set by a pot
* LED anode connected to pin 5, cathode to ground through a 470 ohm resistor
* B10K Pot center lug to pin 3, outer lugs to +5v and ground 
* LED PB0 connected to pin 5
* Pot AD2 (PB4) connected to pin 3
*
*/

#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>

#define LED PB0 		// Define led ext output pin on PB0 pin 5
 
int main( void ) {
	int i;     			// 8 bits integer - should be set in main?
	uint8_t brightness = 0x00;	// Holds the random value applied to OCR0A

	// ******************************************************************
	// 	*** Set up PWM ***
	TCCR0A |= (1<<COM0A1) | (1<<WGM00); // PWM Phase correct mode 1
	TCCR0B |= (1<<CS00);// --no prescale
	TCNT0  = 0x00;	// Timer/Counter Register
	OCR0A  = 0x12;	// Output Compare Register A
	
	DDRB   |= (1<<PORTB0);	// Set PB0 (Pin 5) as output
	// ******************************************************************
 
    	// *******************************************************************
   	// 	*** Set up ADC ***
    	DDRB   |= ( 1 << LED );           // Set output direction on LED
    	ADCSRA |= ( 1 << ADEN  ) |        // Analog-Digital enable bit
		( 1 << ADPS1 ) |          // set prescaler to 8 ( clock / 8 )
		( 1 << ADPS0 );           // set prescaler to 8 ( clock / 8 )
 
    	ADMUX |=  ( 1 << ADLAR ) |        // AD result store in ( more significant bit in ADCH )
		( 1 << MUX1  );           // Choose AD input AD2 ( PB4 ) pin 3
    	// *******************************************************************

    	while ( 1 ) { // Main program 
 
    		ADCSRA |= ( 1 << ADEN );          // Analog-Digital enable bit
    		ADCSRA |= ( 1 << ADSC );          // Discard first conversion
        	while ( ADCSRA & ( 1 << ADSC ) ); // wait until conversion is done
    		ADCSRA |= ( 1 << ADSC );          // start single conversion
        	while ( ADCSRA & ( 1 << ADSC ) )  // wait until conversion is done
    		ADCSRA &= ~( 1 << ADEN );         // shut down the ADC
		//----------Set rate of blinking based on ADCH byte---------
 		for ( i = 0 ; i < ADCH ; i++ ) { // Loop x time until i reach ADCH value
    			_delay_ms( 10 );                   // Loop delay
		}
		brightness = (uint8_t) rand();	// Need a random number from 0 - 255
		OCR0A = brightness;
	}
	return 0;
}

User avatar
adafruit_support_bill
 
Posts: 88097
Joined: Sat Feb 07, 2009 10:11 am

Re: Give me some tips to improve my program

Post by adafruit_support_bill »

First, the main thing is the timing as set by the rotation of the pot feels non-linear. Most of the change is bunched up at one end of the pot rotation.
What kind of pot are you using: Linear or Audio ( logrithmic)?
Second, at the slow end I notice a lag in response, as the loop needs to finish before the pot is read again.
Put the analog read code inside the loop. If the value goes down, the loop will end earlier.

User avatar
soggybag
 
Posts: 35
Joined: Sat Mar 01, 2008 3:28 am

Re: Give me some tips to improve my program

Post by soggybag »

Thanks for the reply. I'm using a linear taper pot, B10K. Now that you point it out. Seems that a log taper pot might give a linear feel since the time is based on 10ms * x.

I'm curious about the value for ADCH. I'm guessing this is defined in one of the includes. How can I look up the documentation for this?

The code I'm using to read the analog input I took from another example. I wonder about the reasons for reading the value then discarding the first read and then reading the value a second time. Is this the standard way to do this? Do need to read this twice every time you want to read an analog input, or do you need to discard only the very first time you read it?

For example could I read the analog input once, just above the while loop, then just read once inside the while loop?

User avatar
adafruit_support_bill
 
Posts: 88097
Joined: Sat Feb 07, 2009 10:11 am

Re: Give me some tips to improve my program

Post by adafruit_support_bill »

The A/D is multiplexed between all the analog pins and it takes some time for things to settle when switching between inputs. So, when reading from multiple inputs it is a good idea to throw away the first one. In your case, (1) you are only reading one input and (2) the accuracy of the reading is not very critical. So I don't think you need that extra read.

No need to change out your pot to change the response. There is a 'log()' function in the Arduino library.

User avatar
soggybag
 
Posts: 35
Joined: Sat Mar 01, 2008 3:28 am

Re: Give me some tips to improve my program

Post by soggybag »

Thanks for the reply arduwino, I'll give log() a try. I'm consulting the documentation here: http://www.nongnu.org/avr-libc/user-man ... 647c152126

log() accepts a double and returns a double, I think I also need an int for OCR0A. How would I convert an int to a double?

I'll guess that the attiny13 will shut down the un-used pins, and that I don't need to ground them, as you might with other logic type IC's?
Last edited by soggybag on Wed Aug 25, 2010 11:07 am, edited 1 time in total.

User avatar
adafruit_support_bill
 
Posts: 88097
Joined: Sat Feb 07, 2009 10:11 am

Re: Give me some tips to improve my program

Post by adafruit_support_bill »

No need to ground the unused analog pins.

User avatar
soggybag
 
Posts: 35
Joined: Sat Mar 01, 2008 3:28 am

Re: Give me some tips to improve my program

Post by soggybag »

Thanks again, do I need to convert the double returned rand() and log() to an int for OCR0A?

User avatar
adafruit_support_bill
 
Posts: 88097
Joined: Sat Feb 07, 2009 10:11 am

Re: Give me some tips to improve my program

Post by adafruit_support_bill »

Yes, OCR0A won't take a double. You can convert by casting as in:
(unit8_t)log(x)

User avatar
soggybag
 
Posts: 35
Joined: Sat Mar 01, 2008 3:28 am

Re: Give me some tips to improve my program

Post by soggybag »

Thanks again for the help. I have been programming internet stuff (Actionscript and Javascript) for some years. The ideas make sense. But, it's taking me a while to wrap my head around this lower level stuff.

I'm guessing I can do this:

Code: Select all

brightness = (unit8_t)log( rand() );
OCR0A = brightness;

User avatar
adafruit_support_bill
 
Posts: 88097
Joined: Sat Feb 07, 2009 10:11 am

Re: Give me some tips to improve my program

Post by adafruit_support_bill »

Should work. Don't be afraid to experiment!

User avatar
soggybag
 
Posts: 35
Joined: Sat Mar 01, 2008 3:28 am

Re: Give me some tips to improve my program

Post by soggybag »

Hmmm... I seem to be getting an error when I use log().

Code: Select all

wait = (uint8_t) log( ADCH );

Code: Select all

avr-gcc -Wall -Os -DF_CPU=9600000   -mmcu=attiny13 -c main.c -o main.o
main.c: In function 'main':
main.c:51: warning: implicit declaration of function 'log'
main.c:51: warning: incompatible implicit declaration of built-in function 'log'
avr-gcc -Wall -Os -DF_CPU=9600000   -mmcu=attiny13 -o main.elf main.o
/usr/local/AVRMacPack-20090319/lib/gcc/avr/4.3.2/../../../../avr/lib/avr25/libc.a(floatsisf.o): In function `__floatunsisf':
(.text.fplib+0x0): multiple definition of `__floatunsisf'
/usr/local/AVRMacPack-20090319/lib/gcc/avr/4.3.2/avr25/libgcc.a(_usi_to_sf.o):/Users/cs/Developer/Hardware/AVR-USB/AVRMacPack/buildtmp.nobackup/gcc-4.3.2/build-objects/avr/avr25/libgcc/../../.././gcc/fp-bit.c:1391: first defined here
make: *** [main.elf] Error 1

User avatar
adafruit_support_bill
 
Posts: 88097
Joined: Sat Feb 07, 2009 10:11 am

Re: Give me some tips to improve my program

Post by adafruit_support_bill »

Might be a limitation of the attiny. That line compiles fine with an Arduino target.

uhe
 
Posts: 178
Joined: Mon Sep 03, 2007 4:50 pm

Re: Give me some tips to improve my program

Post by uhe »

Did you include math.h?

Locked
Please be positive and constructive with your questions and comments.

Return to “Microcontrollers”