Need AVR debugging/help

Here's my setup, I'm building an electronic car that needs to go a predetermined distance for a contest. We get the distance right before the challenge, and then my team is going to program it into the avr. We get distance feedback via an encoder wheel and a phototransistor with IR LED. The phototransistor pulls the pin (PB0) up. Do I need a pulldown resistor? The code powers a motor through a transistor via PB4. There is a calabrate function so that we can enter the distance on top, the calabrate function will turn it into a useful number, and then the code will run. The motor runs until the calabrated number is reached. Unfortuanteley the code doesn't work. Any help, please? I'm probably not specific enough in this little paragraph, so please leave a comment if this doesn't make any sense.
The target uController is the attiny13/attiny13a

code (this is one of the first AVR codes i've made, with the help of other team members):

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

#define mmDistance 5 // the required distance in millimeters

// For the aTTiny13a
/*
pinout:
1) PB5, RESET
2) PB3, CLK
3) PB4
4) GND
5) PB0 MOSI
6) PB1 MISO
7) PB2 SCK
8) VCC
*/

// Input from encoder wheel is PB0 (physical pin 5)
// Output to motor is PB4 (physical pin 3)

int Calibrate(int x) // Calibrate converts distance to set
{
int y;
y = x+3;
return y;
}

int main(void)
{
int clickDistance, setDistance, on = 0;

clickDistance = 0; // clickDistance is the distance travelled so far

DDRB = 0b00001000; // setting outputs and inputs 00001000

setDistance = Calibrate(mmDistance); // setDistance is set distance in clicks

PORTB = 0b00001000; // turn on motor

on = 1; //on tells if previous sense had button on or off

while(clickDistance < setDistance)

{ // while loop
if(PINB == 0b00000000 && on == 1) // button off, previous true
{
clickDistance = clickDistance+1;
// increments clickDistance by 1
on = 0;
}

if(PINB == 0b00001000)
{
on = 1;
}

}

PORTB = 0b00000000; // turn off motor
_delay_ms(5000);
return (0);
}

sort by: active | newest | oldest
1-10 of 29Next »
gmoon9 years ago
Does the program compile correctly? I'm not familiar with any "bit notation" for C (0b00000000). You'd be better off using the avrgcc bit macros and bit definitions.

Bit value 00001000 is PB3, not PB4 ( 00010000, count from zero.)

The _BV() macro is just a shift operation. _BV(4) is (1<<4), i.e., shift a "1" left, four times. 00000001 becomes 00010000.

To set the PB4 bit:
DDRB = _BV(4); // binary 00010000

Even better, use the predefined DDR bit values in the macro:
DDRB = _BV(DDB4); // Data Direction (port)B #4

To set multiple bits, OR them:
DDRB = _BV(DDB3) | _BV(DDB4);

As constants, AVRGCC will optimize all the shifts away, and just compile the # itself.


Setting all the bits of PORTB (instead of setting individual bits):

PORTB = 0b00001000; // turn on motor

Instead of bit PB4 only:
PORTB |= _BV(PB4);

Can potentially mess with the state of the input pin. Both DDRB and PORTB together are used to set the configuration of inputs (tri-state or internal pullup.)

Haven't really looked at the logic itself...

How exactly are the photo transistor and motor wired?
guyfrom7up (author)  gmoon9 years ago
okay, I kinda get what your saying, but I don't know everything to change in the code. This is how it's wired up: You have an axle with wheels on it that a motor is driving. Attached to the axle is an encoder wheel (a wheel with a bunch of wholes along the rim). On one side is an IR LED that's always on. On the other side is the phototransistor that is matched to the LED. for example, if there's 360 slits in the wheel, the phototransistor will turn on and off 360 times (using this data the uController knows how far the car has traveled). Once the number of on/off happen (which our group calls clicks) the uController turns off the motor at the calibrated distance so that the car coasts to a stop at a predetermined distance (called at the define at the beginning of the code). Things about the code: the delay at the end was just for experimental purposes, trying to get the code to work. The calibrate and the mmDistance are just random numbers to see if the code worked. I don't know much about reading inputs and such, I just tried to throw stuff together from various websites. Basically the code is a counter, once the counter reaches a number a pin (that was normally high) goes low. Very simple, yet our group can't figure it out (we all know limited C, very limited, and I'm the only person that knows anythinga bout uControllers, so we are in deep doody, lol)
guyfrom7up (author)  guyfrom7up9 years ago
should we just do a code overhall and start from scratch?
yeah ;-)
guyfrom7up (author)  zachninme9 years ago
haha, any place where I should start I don't get all of these reading pins and how to turn them on, am I close? haha
I'll get ya started, just with the ports. See if this helps...

Setting PORTB for output on PB4:

DDRB |= _BV(DDB4);

Setting PB4:

PORTB |= _BV(PB4); // HI
PORTB &= ~_BV(PB4); // LO


Setup PB0 for input:

DDRB &= ~_BV(DDB0); // clear bit 0

Set the input config with PORTB. Yeah, that's confusing. The same register does different things, depending on the data direction...

If you want the internal pull resistor:
PORTB |= _BV(PB0); // set bit 0, enable pull-up resistor
If you want the input to float:
PORTB &= ~_BV(PB0); // clear bit 0, HI-Z

( tri-state logic, important stuff once you start connecting active devices together...)

Read the input of PB0 (adjust the if statement for 0 or 1, depends on the pin setting, and your circuit ):

if(PINB & _BV(PB0))
{ Do something; }


Gonna crash now, feeling like I'm catching a cold...
gmoon gmoon9 years ago
My bad-- it's obvious what PORTB is... But not DDRB; that's the Data Direction Register for PORTB. It's primary function is setting PORTB pins to either input or output.
guyfrom7up (author)  gmoon9 years ago
don't catch a cold! Thatnks, that's a lot of good info can you explain the input a bit more? Thanks
Yeah, I'm a little under the weather. And I just lost my answer, and had to retype it.... #$@##

Nice bitwise operator tutoral, AVR oriented.

Initialization (only once in main())

Clearing the bits in DDRB sets pins for input. For PB0:

DDRB &= ~_BV(DDB0);

Configuring the inputs
It's weird, but the PORTB output register is used to configure the inputs.

If you have a simple push button input, internal pullup mode works fine. It pulls the pin HI by default, and the pin is "activated" by grounding it through the switch (pulled LO.) Set PORTB bit (PB0) for pullup:
PORTB |= _BV(PB0);

You might want a floating hi-impedance input instead for a photo transistor. Clear PORTB bit (PB0) for HI-Z:

PORTB &= ~_BV(PB0);

Reading the port

"B" pins are read with PINB registers. Bitwise AND (&) PINB and the desired pin (PB0).

read input status of PB0 = PINB & _BV(PB0)

In an if statement: (test for set bit)
if(PINB & _BV(PB0)){clickDistance = clickDistance+1;on = 0;} 

Use NOT (!), together with AND, to test for a cleared bit:
if( !(PINB & _BV(PB0)) ){clickDistance = clickDistance+1;on = 0;} 
dwj300 gmoon9 years ago
this is very good info, but it is very complicated.
i wrote this code (and replaced it with the old statements. would they work?

DDRB.3 = 0xFF; // setting pin 3 to output
DDRB.0 = 0x00; // setting pin 0 to input
PORTB.3 = 0xFF
if(PINB.0 == 0x00 && on == 1) // button off, previous true
PORTB.3 = 0x00 // turn off motor
1-10 of 29Next »