Easy way to set and read one pin in WinAvr ?

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

Hi

/*******************************************************************
Is there no easy way to set and read one pin in WinAvr.
And label a pin by name ?
********************************************************************/

Like with CodeVision you can do it simply by doing this :

#define	RED	PORTB.0	/* definitions to actual outputs */
#define	YEL	PORTB.1	/* used to control the lights */

#define	SWITCH	PINB.5

int main (void)
{
	//set PORTB for input and output
	DDRB = 0x0F;

	while (1)
	{
		YEL = 1;

		If(SWITCH)		//Read if switch is pressed
		{
			RED = 1;
			YEL = 0
		}
		else
		{
	  		RED = 0;
			YEL = 1
		}

	}
	return 1;
}

How can I do this in WinAvr ?

I now that I can do this as follows in WinAvr and for any C compiler:

#define SET_B(x) |= (1<<x) 
#define CLR_B(x) &=~(1<<x) 
#define INV_B(x) ^=(1<<x) 


PORTB SET_B(5); 		//set PORTB.5
PORTB CLR_B(2); 		//clear PORTB.5
PORTB INV_B(6); 		//invert PORTB.5

But it seems a bit complicated to use this when I need to define many ports by name:

Please tell, what is the easy way to this in WinAvr !

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

... PORTB.0

> How can I do this in WinAvr ?

You cannot, as this violates the C syntax.

This entire issue has been discussed ad nauseum.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

Hi Jorg

I now this is not possible in WinAVR and it violates C syntax!

Please read my problem above!

What is the easy way to define single pin by name and write/read its value?

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

toti,

Exactly what is so complicated about:

	PORTB |= _BV(PB3); // set bit 3
	PORTB &= ~_BV(PB3); // clear bit 3
	x = ((PORTB & _BV(PB3) == _BV(PB3)); //x gets state of  bit 3

It's hardly the most complicated C ever is it?!?

But if you want to dress it up so you can write "noddy" C then how about something like:

/*
** Bitfield structure for accessing individual SFR bits.
*/
typedef struct {
	unsigned	b0	:1;
	unsigned	b1	:1;
	unsigned	b2	:1;
	unsigned	b3	:1;
	unsigned	b4	:1;
	unsigned	b5	:1;
	unsigned	b6	:1;
	unsigned	b7	:1;
} SFR_BITFIELD;

#define	SFR_BIT_RW(name, bit_no)	(((volatile SFR_BITFIELD*) (void *) &(name))->b##bit_no)

#define SFR_UINT8_RW(addr)			*((volatile uint8 *) (addr))

#define MYPORTB SFR_UINT8_RW(0x05)

#define PB_BIT3		SFR_BIT_RW(MYPORTB, 3)

#define LOGIC_1     	((bool) 1)
#define LOGIC_0     	((bool) 0)

#define ON          	LOGIC_1
#define OFF         	LOGIC_0

#define LED_GREEN		PB_BIT3

void fn(void)
{
	LED_GREEN = ON;
	LED_GREEN = OFF;
}

Except this won't actually work on the AVR because I've taken this example from an ARM project where the SFRs are in memory, not IO space. But something similar could be the basis for doing it on AVR and, indeed, I think the CodeVision header files must do something similar to allow your "RED = 1" above.

But the AVR is so simple, why not just "hit the bits" anyway?

Cliff

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

> Except this won't actually work on the AVR because I've taken this
> example from an ARM project where the SFRs are in memory, not IO
> space.

The AVR SFRs are also accessible through memory space.

As I said, this has all been discussed ad nauseum, and solutions have
been posted. It's even possible to drive the bitfield approach into
the same compiler optimization level so the more effective SBI/CBI
instructions will be used where appropriate.

Of course, it's highly debatable whether that would eventually still
count as a ``simpler solution'' compared to the standard C bit
manipulation operators. In general, I'd rather make the people think
about their problems a bit more, and add one more level of abstraction
so a mini-HAL (hardware abstraction layer) will result. So why invent
crap like

#define PB_SET(x) (PORTB |= (1 << (x)))

when all you want is actually driving LEDs on PORTB (perhaps even
active low, so the logic inverts again), and you could rather write

#define LED(nr,onoff) do { \
	if (onoff) { \
		PORTB &= ~(1 << (x)); \
	} else { \
		PORTB |= (1 << (x)); \
	} \
} while(0)
#define ON  1
#define OFF 0
#define LED_ALARM 0
#define LED_RUN   1
#define LED_FAIL  2

which is a bit more to type initially, but then allows for things like

...
LED(LED_ALARM, ON);
LED(LED_RUN, OFF);

However, if the OP really doesn't like the C way, why not have a look
at Ada? AVR-Ada has recently been announcing a new version.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

Thanks Jorg

I realy like C programmering, but I'm traying to learn to use WinAvr compiler.

Can you advise how to read status on one pin!

This works in CodeVision:

If(PINB.5)	//Read if switch is pressed
{
     ...;
}
    else
{
     ...;
}

How do is it done in WinAvr ?

Regards Toti

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

Standard C, please read any book about C for this:

if (PINB & (1 << 5)) {
...
}

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

Go look in the AVR Forum, at the sticky post describing C books and references, and go down to the link going to the "Programming 101" post. It's a tutorial on how to use the C language bit operators.

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

I was just looking at some generated assembly for a line like this:

bool pind3 = PIND & _BV(3);

This is what it generated:

IN R24,0x10
CLR R25
LDI R19,0x03
LSR R25
ROR R24
DEC R19
BRNE PC-0x03
ANDI R24,0x01

Wouldn't this be a much more efficient way to do it?

LDI R24, 0
SBIC 0x10, 3
LDI R16, 1

Would it be "good C" to make a macro that does exactly that with inline asm? Or should I just stick with the "real" way of manipulating bits in C?

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

What optimization level?

Also, `bool' might not be the best to use.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

optimisation level 's'. I'm using WinAVR20050214.

bool was the easiest way to compare the state of two pins, since non zero values always become 1.

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

Normally, this kind of optimization works, and results in close to
optimal assembly code. However, there are occasional corner cases
where the optimizer starts to make weird things. There's been another
thread recently, and one of the posters mentioned that returning a
literal 0 causes the optimizer to go make surprising decisions. This
is all with GCC 3.4.x, I hope these things have been sorted out in GCC
4.x (but haven't checked yet).

It's quite possible that your bool variable has about the same effect
as returning a literal 0 from a function. Normally, you don't need
this kind of variables, you just store PIND & _BV(3) in some uint8_t
variable and use that one directly in an if() statement. There's no
need to force the compiler to generate a literal 0/1 value for a
Boolean.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

Clearly the compiler has chosen to make 'bool' an 'int' and generate 16 bit code for it. It might be best to do something like:

typedef unsigned char BOOL;

BOOL pind3 = PIND & _BV(3); 

and use 'BOOL' rather than 'bool' in future.

Actually, I guess 'bool' (or 'BOOL') is only really supposed to hold one of two values, 'TRUE' or 'FALSE' (whatever *that* actually means) so setting the variable to 'PIND & _BV(3)' it might be argued that this isn't a valid boolean value anyway (except that most compilers treat 0=FALSE and anything !=0 as TRUE). Perhaps it should be 'pind3 = (PIND & _BV(3)) == _BV(3);' ? But I'm not sure if this would make the compiler generate more or less efficient code!

Cliff

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

microchip wrote:
I was just looking at some generated assembly for a line like this:

bool pind3 = PIND & _BV(3);

This is what it generated:

IN R24,0x10
CLR R25
LDI R19,0x03
LSR R25
ROR R24
DEC R19
BRNE PC-0x03
ANDI R24,0x01

Wouldn't this be a much more efficient way to do it?

LDI R24, 0
SBIC 0x10, 3
LDI R16, 1

Well, you've identifed that the compiler can make a mess sometimes but as you've already got a good idea how to do it efficiently then why not give the compiler a "helping-hand" and write your code with the assembly in mind.

This code is optimal and does what you want.

#include 

bool PinTest (void)
{
bool result;

result=false;
if (PIND & _BV(3))
	result=true;
return (result);
}

It produces:

ldi r24,lo8(0)
sbic 41-0x20,3
ldi r24,lo8(1)
clr r25
ret

PS I think that instead of dealing directly with hardware pins, writing a simple #define makes the code so much more readable especially when you re-visit the code several weeks later.

e.g.

#define KEYPRESSED() (PIND & 1<<3)

result=false;
if (KEYPRESSED())
	result=true;

PPS

clawson wrote:
Clearly the compiler has chosen to make 'bool' an 'int' and generate 16 bit code for it.

This is not correct as my code example above demonstrates. GCC however always returns an extended 8-bit value to 16-bits.

Regards

Nigel

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

N.Winterbottom wrote:

This is not correct as my code example above demonstrates. GCC however always returns an extended 8-bit value to 16-bits.

Oops, my bad, I guess it was not seeing the code in context that misled me - it wasn't clear this was actually being returned out of a function - and it was that which caused the promotion to 16 bits.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// structure to allow bit field operations, name conversions: PORTA.0 -> PORT_A.b0  PORTB.7 -> PORT_B.b7
typedef struct{ uint8_t b0:1;
                uint8_t b1:1;
                uint8_t b2:1;
                uint8_t b3:1;
                uint8_t b4:1;
                uint8_t b5:1;
                uint8_t b6:1;
                uint8_t b7:1; } bits;
 
// define all the ports of your microcontroller, add more ports depending on the available mcu ports
#define PORT_A (* (volatile bits *) &PORTA)
#define PIN_A (* (volatile bits *) &PINA)
#define DDR_A (* (volatile bits *) &DDRA)
 
#define PORT_B (* (volatile bits *) &PORTB)
#define PIN_B (* (volatile bits *) &PINB)
#define DDR_B (* (volatile bits *) &DDRB)
 
// then you can use specific bits like this to write or read specific bits
PORT_A.b0=1;   // write value to PORTA bit 0
PIN_B.b4=0;   // write value to PINB bit 4

v2

// add this defines
#define SETBIT(ADDRESS,BIT) (ADDRESS |= (1<<BIT)) 
#define CLEARBIT(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT)) 
#define FLIPBIT(ADDRESS,BIT) (ADDRESS ^= (1<<BIT)) 
#define CHECKBIT(ADDRESS,BIT) (ADDRESS & (1<<BIT)) 
#define WRITEBIT(RADDRESS,RBIT,WADDRESS,WBIT) (CHECKBIT(RADDRESS,RBIT) ? SETBIT(WADDRESS,WBIT) : CLEARBIT(WADDRESS,WBIT))
 
// and then you can use
SETBIT(PORTX,2);  // set bit2 of portx (set to 1)
SETBIT(PORTY,0);  // set bit0 of porty
 
CLEARBIT(PORTX,5); // clear bit5 of portx (set to 0)
 
FLIPBIT(PORTX,2);  // invert bit2 of portX, if it was 1 it becomes 0, and if 0 becomes 1
                    // example for portx 0x10101010 the result is 0x10101110
                    
if (CHECKBIT(PORTX,4)) {} else {} // result is true if bit4 of portx is 1, false if it is 0
if (!CHECKBIT(PORTX,4)) {} else {} // result is true if bit4 of portx is 0, false if it is 1
 
 
WRITEBIT(PORTX,0,PORTY,2);   // copy the bit0 of portx to bit2 of porty
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

http://www.nongnu.org/avr-libc/u... wrote:
Return values: 8-bit in r24 (not r25!),
Perhaps bool is 16 bits.

Iluvatar is the better part of Valar.

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

skeeve wrote:
http://www.nongnu.org/avr-libc/u... wrote:
Return values: 8-bit in r24 (not r25!),
Perhaps bool is 16 bits.
Actually you mean "Perhaps bool was 16 bits 7.5 years ago", don't you? ;-)

Stefan Ernst

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

Anyone got any idea why script22 resurrected this thread after 8 years?

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

Because it actually took him 8 years to type in those 22 lines with just numbers before the copies of solutions already posted here at AVRfreaks several times (i.e. why not just link to the appropriate threads)?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

JohanEkdahl wrote:
Because it actually took him 8 years to type in those 22 lines with just numbers before the copies of solutions already posted here at AVRfreaks several times (i.e. why not just link to the appropriate threads)?

Actually he only typed two characters, "v2". :D
http://www.edaboard.com/entry861...

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

sternst wrote:
skeeve wrote:
http://www.nongnu.org/avr-libc/u... wrote:
Return values: 8-bit in r24 (not r25!),
Perhaps bool is 16 bits.
Actually you mean "Perhaps bool was 16 bits 7.5 years ago", don't you? ;-)
Possibly. I don't remember the last time I used bool.

Iluvatar is the better part of Valar.

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