Help me getting started with AVRs

For Adafruit customers who seek help with microcontrollers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
mtbf0
 
Posts: 1645
Joined: Sat Nov 10, 2007 12:59 am

Re: Help me getting started with AVRs

Post by mtbf0 »

soggybag wrote:

Code: Select all

DDRB |= ( 1 << 2 ); // Set LED1 as output, pin #?
DDRB |= ( 1 << 0 ); // Set LED2 as output, pin #?
I added "pin #?", I was wondering which pins this would apply to.
PB2 and PB0. one could also code that as

Code: Select all

  DDRB = (1 << PB2) || (1 << PB0);
which has the benefit of being somewhat self documenting, at least for those who know how to use the data direction register.

Code: Select all

  DDRB = 5;
would also do the job, but is not very enlightening.

have you considered the arduino? it's a great learning tool and if, as i do, you dislike using all the little helper functions you don't have to.

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

Re: Help me getting started with AVRs

Post by soggybag »

Thanks for the reply. This is starting to make sense.

I have some programming experience with Flash, PHP. But this is sort of a lower level thing. I have an Arduino and a Basic Stamp. But I haven't used them much. I'm trying to work with this particular chip because I have project in mind that the Arduino is too larger to fit inside.

My goal is to make an LFO that will fit inside of guitar effect pedal. I want to output a random stepped voltage that will drive an LED and control the speed with a pot.

JohnOC
 
Posts: 9
Joined: Thu Apr 02, 2009 2:15 pm

Re: Help me getting started with AVRs

Post by JohnOC »

soggybag wrote: It appears the attiny13 has one port PORTB. PORTB connects to each of the 6 pins PB0 - PB5.

DDRB is the Data Direction Register. Setting this sets the port and the pins as outputs or inputs. My main confusion is how to set the each invidual pin as an input or output?
The register is represented as a 6 bit binary word, for example "001001" Each bit position in the word corresponds to a pin, and the 0 and 1 values correspond to the pin being set to input (0), or output (1).

The least significant bit in the word is pin 0.
soggybag wrote: I was looking at a block of code:

Code: Select all

DDRB |= ( 1 << 2 ); // Set LED1 as output, pin #?
DDRB |= ( 1 << 0 ); // Set LED2 as output, pin #?
I added "pin #?", I was wondering which pins this would apply to.
That code is startlingly opaque if you aren't familiar with bit shift operators (which I am not - I've been using this as a learning exercise too).

<< is the left shift operator.

Quote: "A simple way to think of the left-shift operator is that it multiplies the left operand by 2 raised to the right operand power."

So.. 1 << 2 == 4
4 is the same as 000100 .. which would set PB2 to be an output.

1<<0 is 1, which would affect PB0

In both these cases, the |= operator is doing a bitwise OR between the current contents of DDRB and the argument on the right. So if DDRB started out containing 000000, it would become 000100 and then 000101 through these two operations.

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

Re: Help me getting started with AVRs

Post by soggybag »

Thanks for the help. I have the blinking LED working. I'm trying to read the value of a pot to set the rate of a blink.

I have an LED connected to pin 3 and the center pin of a B10K pot connected to pin 2. With the other two leads of the pot connected to Vcc and GND.

Here's the code that I have been using, below. When I use _delay_ms( 300 ), everything compiles loads and runs and the LED blinks. When I change this to, _delay_ms( val ), where val is what I'm hoping is the value read from my pot, I get a compile error.

Code: Select all

/*

blinky for the attiny13 

     ___ ___
 PB5=|   V   |=VCC
 PB3=|	    |=PB2
 PB4=|	    |=PB1
GND=|_______|=PB0


ISP---MISO-PB1
	  MOSI-PB0
	  SCK-PB2
	  RESET-PB5

LED on PB4
ADC on PB3

use PB0 or PB1 for PWM output 
will work on other attiny's

*/

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

int ReadADC();	// Function to read ADC
int val = 0; 	// Holds value from ADC

int main( void ) {
	/* port setup */

	DDRB |= ( 1 << DDB4 ); 	//PORTB4 output pin
	PORTB = 0x00; 		//clear PORTB

	/*
	ADC setup - free running mode 
	1MHz clock / 8 = 125KHz sample rate 
	*/

	ADCSRA |= ( 1 << ADPS0 ) | ( 1 << ADPS1 ); 		//ADC prescaler to 8 
	ADMUX  |= ( 1 << ADLAR ) | ( 1 << MUX0 ) | ( 1 << MUX1 ); //left adjust for 8-bit result in ADCH, PORTB3 ADC input
	ADMUX  |= ( 0 << REFS0 ); 				// VCC as Reference  
	ADCSRA |= ( 1 << ADEN  ) | ( 1 << ADSC ); 		//enable, start converting
	
	// do something with ADC ( ADCH? )

	while( 1 ) {
		val = ReadADC();
		_delay_ms( val ); 		// delay 300ms
		PORTB ^= ( 1 << PORTB4 ); 	// toggle the LED
	}
	
	return 1;
}



int ReadADC() {
     ADMUX  |= ( 0 << REFS0 ); 	// VCC as Reference
     ADMUX   = 2;		// ADC2 PB.4
     ADCSRA |= ( 1 << ADSC ); 	// Start Converstion

     while( ( ADCSRA & 0x40 ) != 0 ) { }; // wait for conv complete

     return ADC;
} 



The_Don125
 
Posts: 373
Joined: Tue Mar 06, 2007 11:51 pm

Re: Help me getting started with AVRs

Post by The_Don125 »

try changing val from an int to a uint8_t variable type

Also, return ADCH, not ADC

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

Re: Help me getting started with AVRs

Post by soggybag »

Thanks for the reply. I tried your suggestion without luck. I looked up _delay_ms here

The documentation shows:

void _delay_ms ( double __ms )

I'm guessing the problem is that _delay_ms is expecting a double.

I found another code example which was successful. This example seems to use a loop to execute a 10ms delay a number times equal to the value of ADCH.

Code: Select all

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

#define F_CPU 9600000               // Define software reference clock for delay duration
#define LED PB2                     // Define led ext output pin on PB2
 
int i;                              // 8 bits integer
 
 
int main( void ) {
 
    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 (BP 4)
 
    while (1) {
 
    	ADCSRA |= ( 1 << ADEN );          // Analog-Digital enable bit
    	ADCSRA |= ( 1 << ADSC );          // Discarte 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 reaches ADCH value
    		_delay_ms( 10 );                   // Loop delay
	}
 
	PORTB ^= ( 1 << LED );                  // Invert led bit and show it
}
return 0;
}

sirket
 
Posts: 128
Joined: Fri Oct 26, 2007 8:46 pm

Re: Help me getting started with AVRs

Post by sirket »

Code: Select all

int val = 0; 	// Holds value from ADC

int main( void ) {
You are defining val as a global variable- bad practice- define it within the main function to avoid problems- val might be defined in some other module and giving you trouble.

As for the bit about it being the wrong type- C compilers will automatically type cast between certain fundamental types- for example- int to long or int to double.

Code: Select all

int ReadADC() {
     ADMUX  |= ( 0 << REFS0 ); 	// VCC as Reference
     ADMUX   = 2;		// ADC2 PB.4
     ADCSRA |= ( 1 << ADSC ); 	// Start Converstion

     while( ( ADCSRA & 0x40 ) != 0 ) { }; // wait for conv complete

     return ADC;
} 
I can only assume ADC is a global definition as well. Are you sure it's been defined in one of your headers?

Can you tell us what the _exact_ compiler error is? Believe it or not most of the compiler errors are pretty accurate.

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

Re: Help me getting started with AVRs

Post by soggybag »

Thanks for the tip. I have some experience programming with Actionscript and PHP. So I recognize the syntax. But, many elements are new or used to me.

Is it best practice to define all variables and functions within your main function with only constants defined outside of main? For example:

Code: Select all

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

#define F_CPU 9600000

int main( void ) {
	int ReadADC();		// Function to read ADC
	uint8_t val = 0; 	// Holds value from ADC
	/* port setup */

	DDRB |= ( 1 << DDB4 ); 	//PORTB4 output pin
	PORTB = 0x00; 		//clear PORTB
...

sirket
 
Posts: 128
Joined: Fri Oct 26, 2007 8:46 pm

Re: Help me getting started with AVRs

Post by sirket »

soggybag wrote:Thanks for the tip. I have some experience programming with Actionscript and PHP. So I recognize the syntax. But, many elements are new or used to me.

Is it best practice to define all variables and functions within your main function with only constants defined outside of main? For example:
Variables should be defined within the function where they're used- whether it's main or another function.

Functions should be defined before they are used- so generally at the same level, but before, main. You wouldn't define a function within main.

Constants should generally be defined globally.

There are exceptions to every rule, but unless you have a specific reason, don't make one.

Do you have the exact compiler error you were seeing? It should be available in one of the logs and it will probably let us know what the issue is.

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

Return to “Microcontrollers”