| Author |
Message |
|
|
Posted: Jan 20, 2009 - 10:30 PM |
|

Joined: Dec 23, 2008
Posts: 25
|
|
My first tutorial:
A philosophy of mine for programming is eliminating repeated code as much as possible. Because of this I've always been "annoyed" at code like this for use in generalized functions:
Code:
// Defines like this
#define LED_PORT PORTB
#define LED_DDR DDRB
#define LED_PIN PINB
#define LED_BIT 1
// To make this code more general
LED_DDR |= 1<<LED_BIT; // Set output
LED_PORT |= 1<<LED_BIT; // Turn on
LED_PIN |= 1<<LED_BIT; // Toggle
This may not look repetitive, but I wanted to make it look like this using a macro:
Code:
#define LED_PORT B
#define LED_PIN 1
DDR(LED_PORT) |= 1<<LED_PIN;
PORT(LED_PORT) |= 1<<LED_PIN;
PIN(LED_PORT) |= 1<<LED_PIN;
This simplifies the defines that need to be adjusted for different boards but makes the actual code a little different.
If anyone else has tried to do this, the knee-jerk is to use these macros:
Code:
#define PORT(port) PORT ## port
#define DDR(port) DDR ## port
#define PIN(port) PIN ## port
Unfortunately, this does not work. You get errors saying something to the effect of PORTLED_PORT undefined that will force most to give up and use the standard of a separate define for PORT, DDR, and PIN. What happens is the compiler actually appends the literal LED_PORT to PORT instead of taking the value we defined LED_PORT to be.
Fortunately, there is a workaround for this. You just need an extra macro step:
Code:
#define PORT_(port) PORT ## port
#define DDR_(port) DDR ## port
#define PIN_(port) PIN ## port
#define PORT(port) PORT_(port)
#define DDR(port) DDR_(port)
#define PIN(port) PIN_(port)
I hope someone likes & uses this! |
|
|
| |
|
|
|
|
|
Posted: Jan 22, 2009 - 10:21 AM |
|

Joined: Sep 24, 2007
Posts: 5
|
|
hi, i got a nice code to define i/o port. The author is Tomasz Ostrowski so all credit belong to this man.
Code:
// define electric connections according to your circuit, DATA line
#define DATA_PORT PORTB
#define DATA_DDR DDRB
#define DATA_PINPORT PINB
#define DATA_PIN 0
#define SWITCH_DATA_IN DATA_DDR &= ~_BV(DATA_PIN)
#define SWITCH_DATA_OUT DATA_DDR |= _BV(DATA_PIN); NOP ///< \todo is NOP needed?
#define CLEAR_DATA DATA_PORT &= ~_BV(DATA_PIN)
#define SET_DATA DATA_PORT |= _BV(DATA_PIN)
#define DATA (DATA_PINPORT & _BV(DATA_PIN))
and i add 'toggle' function to the code
Code:
#define TOGGLE_DATA DATA_PORT ^= _BV(DATA_PIN)
i usually write this in ionames.h then i included this file to my main program.
hope you like it. |
|
|
| |
|
|
|
|
|
Posted: Dec 20, 2011 - 12:56 AM |
|

Joined: Aug 01, 2011
Posts: 13
|
|
hey cinderblock,
very very clean code, I only wish I knew what your macros are actually doing, your code makes the most sense... once you get to use it in your code.
Thanks for your help. |
|
|
| |
|
|
|
|
|
Posted: Dec 20, 2011 - 02:11 AM |
|

Joined: Jun 19, 2002
Posts: 983
Location: SF Bay area
|
|
|
Quote:
You just need an extra macro step
Warning: there are a bunch of things in the area of macro expansion and stringification and concatenation and the performance order thereof that are NOT DEFINED in the C standard, and therefore subject to change when you switch compilers or versions of a compiler...
In fact, we had a grand old time when the behavior changed between gcc 3.4.5 and 4.1 (or something like that.) |
|
|
| |
|
|
|
|
|
Posted: Dec 20, 2011 - 02:56 PM |
|


Joined: Nov 11, 2003
Posts: 4040
Location: Chicago Illinois USA
|
|
Now I've always wondered why we don't define our bits this way:
Code:
#define BLUE_LED 1
#define RED_LED 2
#define GREEN_LED 4
So we could just set:
DDRB = BLUE_LED | RED_LED | GREEN_LED
|
_________________ Discursive design,
Torby
Some days, it's just not worth chewing through the restraints.
|
| |
|
|
|
|
|
Posted: Dec 20, 2011 - 03:17 PM |
|

Joined: Feb 12, 2005
Posts: 16544
Location: Wormshill, England
|
|
|
Code:
#define BLUE_LED_bm 1
#define RED_LED_bm 2
#define GREEN_LED_bm 4
So we could just set:
DDRB = BLUE_LED_bm | RED_LED_bm | GREEN_LED_bm
It would be far more natural to use bit_masks instead of bit_positions. However the Atmel data sheets chose bit_positions.
I have always assumed that this was because some ASM ops use bit_positions e.g.
Code:
SBRS r16,3
There are many different schemes for describing special_bits in special function registers. Personally, I like the bitfield_structure used by PIC (and others).
It is a historic thing. I suspect that the early compilers were not clever enough. Hence we are stuck with the bit_position scheme.
David. |
|
|
| |
|
|
|
|
|
Posted: Dec 20, 2011 - 03:18 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
Now I've always wondered why we don't define our bits this way:
Funny I gave the answer to this very question yesterday.
http://www.avrfreaks.net/index.php?name ... 923#903923
Nothing stops you defining bit masks rather than bit numbers if you prefer. In fact if you are willing to live without io.h (or whatever it's called in your compiler) you can redefine the entire set of SFRs and bit names if you like except that it would hugely confuse anyone else trying to use the code if they assumed registers/bits defined the "normal" way. One possibility is to use a case change to avoid name pollution such as:
Code:
#define Txen 0x08
#define Rxen 0x10
UCSRB = Txen | Rxen;
Another alternative is:
Code:
typedef struct {
uint8_t Txb8:1;
uint8_t Rxb8:1;
uint8_t Ucsz2:1;
uint8_t Txen:1;
uint8_t Rxen:1;
uint8_t Udrie:1;
uint8_t Txcie:1;
uint8_t Rxcie:1;
} UB_t;
#define Ucsrb (*(volatile UB_t *)0x2A)
Ucsrb.Txen = 1;
|
_________________
|
| |
|
|
|
|
|
Posted: Jun 27, 2012 - 05:02 PM |
|


Joined: Oct 26, 2011
Posts: 29
|
|
Hey guys,
I'm a bit of a C noob, but this seems like the correct thread. Any chance you could help me out here a bit? Currently I'm doing this in my code:
Code:
#define LED0 PA0 // assign LED names to output ports on the attiny84
#define LED1 PA1
#define LED2 PA2
#define LED3 PA3
#define LED4 PA4
#define LED5 PA5
#define LED6 PA6
#define LED0_CLEAR (pin_level &= ~(1 << LED0))
#define LED1_CLEAR (pin_level &= ~(1 << LED1))
#define LED2_CLEAR (pin_level &= ~(1 << LED2))
#define LED3_CLEAR (pin_level &= ~(1 << LED3))
#define LED4_CLEAR (pin_level &= ~(1 << LED4))
#define LED5_CLEAR (pin_level &= ~(1 << LED5))
#define LED6_CLEAR (pin_level &= ~(1 << LED6))
// Set bits corresponding to pin usage above
#define PORT_MASK (1 << PA0)|(1 << PA1)|(1 << PA2)|(1 << PA3)|(1 << PA4)|(1 << PA5)|(1 << PA6)
It seems silly to me, can you guys recommend a way to condense this? Note: This is for a led fader project, and the amount of LEDs is variable (based on chip selection and well, how many LEDs you want to hook up) so I would like to write code that based on a CHMAX variable will automatically set things up correctly.
Thanks in advance for your advice and help! |
|
|
| |
|
|
|
|
|
Posted: Jun 27, 2012 - 05:11 PM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
Note that the XMEGA and UC3 device headers *do* contain bit masks as well as (in some cases) bit positions. They also contain group masks, so code for them usually looks quite clean.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jun 27, 2012 - 07:03 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
Any chance you could help me out here a bit?
What is "pin_level" in the code you show?
(BTW not entirely sure a tutorial thread is the right place for this - usually the following thread is just to suggest improvements to the tutorial). |
_________________
|
| |
|
|
|
|
|
Posted: Jun 28, 2012 - 12:24 AM |
|


Joined: Oct 26, 2011
Posts: 29
|
|
| Hmm. OK I will re post to another thread. Sorry folks! |
|
|
| |
|
|
|
|
|