not getting output
Moderators: adafruit_support_bill, adafruit

not getting output

by Prashanth on Fri Jun 08, 2012 6:57 am

[Edit - moderator - moved to appropriate forum]

I'm using atmega8 and L293D. when i give input to the atmega, i don't get any output. below is my code. i'm just learning how to code, so i don't know if its perfect.
inputs d0-forward, d1-reverse, d2-turn left, d3-turn right.
outputs b6 In1 and In4,b7 In2 and In3,d5 enable left of H bridge,d6 enable right of H bridge

void forward()
{
PORTD = 0b01100000;
PORTB = 0b01000000;
}

void reverse()
{
PORTD = 0b01100000;
PORTB = 0b10000000;
}

int main()
{
DDRD = 0b01100000;
DDRB = 0b11000000;
PORTB = 0b00000000;
PORTD = 0b00000000;
while(1)
{
if(PORTD == 0b00000001) // move forward
forward();

else if(PORTD == 0b00000010) // reverse
reverse();

else if(PORTD == 0b00000101) // turn left forward
{
forward();
_delay_ms(100);
PORTD = 0b01000000;
PORTB = 0b01000000;
_delay_ms(100);
}

else if(PORTD == 0b00001001) // turn right forward
{
forward();
_delay_ms(100);
PORTD = 0b00100000;
PORTB = 0b01000000;
_delay_ms(100);
}
}
return 0;
}
Prashanth
 
Posts: 1
Joined: Wed Jun 06, 2012 8:03 am

Re: not getting output

by stinkbutt on Fri Jun 08, 2012 12:12 pm

OK, first of all, I'm going to assume you're using avr-gcc here. Which I think you are, but it's not impossible this is just butchered Arduino code. But if it's avr-gcc code, I see a few places you could be getting tripped up:

1. Double check to see if you're getting your pins correct. Are you perhaps thinking that DDRB = 0b11000000 is setting the first two pins to output and the last 6 to input? In binary I think you're setting the LAST two pins to output, but I can't be certain since I don't know where these input pins actually are on the device. I'm just saying make sure you've got that bit right. It's an easy mistake to make.

2. Don't use PORTx for input. It's there for OUTPUT, and checking the PORTx values for pins that are configured for input isn't doing what you think it's doing. It's instead mucking about with the internal pull-up resistors. Setting DDRx to 0 (input) and PORTx to 1 turns on an internal pull-up resistor:

Image

So really all you're testing there is what the current pull-up values for the internal resistors are. NOT what you care about, huh?

3. For input use PINx. There's a third variable available to you, called PINB or PIND which is what you should be using for reading values.

4. We're not done yet. Your if/then tests are all messed up. You DON'T want to ever test the entire value of the PINB variable. You don't necessarily know what your program has been doing to muck about with the values of the output pins and more importantly you don't care. Instead of the code:

Code: Select all | TOGGLE FULL SIZE
if(PORTD == 0b00000001) // move forward
forward();


You want to do this:

Code: Select all | TOGGLE FULL SIZE
if( (PIND & 0b00000001) == 0b00000001 ) // Just testing bit zero
forward();


Note I've made two changes to your code. First I used PIND instead of PORTD. Second this bit here:

(PIND & 0b00000001)

That bit does a bitwise AND operation. Because the first bit is 1 and the rest are 0, then the last 7 bits of the output will ALWAYS be zero. And the first bit will be a if the value of pin D0 is 1, and 0 if it's 0. Then I can use comparison properly.

Anyway, try making those changes. Also, you really shouldn't be using 0b00000001 and such for your variables all over the place. Strictly speaking it's accurate, but it's ugly as all hell. There are better options:

Instead of 0b00000001 you could use the bitshift operator and write:

1<<0

That shifts the number 1 down zero bits. Which isn't impressive, but look at where that's going:

0b00000001 == 1<<0
0b00000010 == 1<<1
0b00000100 == 1<<2
0b00001000 == 1<<3

Now let's say you want to make 0b00000101? You just use a bitwise OR:

0b00000101 == (1<<0) | (1<<2)

Even better, you can use the _BV() macro, which does exactly the same thing with slightly more readable code:

1<<0 == _BV(0)
1<<1 == _BV(1)
etc. etc. etc...

Finally, you can use the global constants available in avr-gcc so you don't worry as much about what the exact position of the pin is. For example to set DDRB you could write this code:

Code: Select all | TOGGLE FULL SIZE
DDRB = 0;  // Sets all 8 registers to zero.  Probably not necessary, but included for clarity.
DDRB |= _BV(PB6)  // Sets PB6 high for output
DDRB |= _BV(PB7) // Sets PB7 high for output


Note the operator: |=
That does an OR operation on the item to the left with the item to the right and ASSIGNS it to the item on the left. It's like += and *=, if you've ever seen those.

If you insist on using avr-gcc to compile code for ATMegas (a bad idea, IMO, for new programmers - Arduino's got a much less imposing learning curve) then you're going to need to get up to speed on bitwise operations lickety-split. GL
Red M&M, Blue M&M: They all wind up the same color
stinkbutt
 
Posts: 590
Joined: Wed Feb 17, 2010 1:40 am