Offline
Newbie
Karma: 0
Posts: 2
|
 |
« on: November 17, 2012, 02:51:55 pm » |
when I read the code in multiwii source (got from ' http://code.google.com/p/multiwii/downloads/list'). there exist such code in the def.h file: ..... #define LEDPIN_PINMODE pinMode (13, OUTPUT); #define LEDPIN_TOGGLE PINB |= 1<<5; //switch LEDPIN state (digital PIN 13) #define LEDPIN_OFF PORTB &= ~(1<<5);
...... at them same time, there exist below statements in MultiWii_1_9.pde file: ... for (r=0;r<repeat;r++) { for(i=0;i<num;i++) { LEDPIN_TOGGLE; //switch LEDPIN state BUZZERPIN_ON; delay(wait); BUZZERPIN_OFF; } delay(60); }
.... my question is: the PB13 is output mode, why the LEDPIN_TOGGLE macro is valid? thank you.
|
|
|
|
« Last Edit: November 17, 2012, 04:01:47 pm by flyingyizi »
|
Logged
|
|
|
|
|
Leeds, UK
Offline
God Member
Karma: 35
Posts: 987
Once the magic blue smoke is released, it won't go back in!
|
 |
« Reply #1 on: November 17, 2012, 02:55:03 pm » |
Writing a logic 1 to a bit in the PINx register of many atmegas results in the corresponding output toggling its state.
In this case, arduino pin 13, corresponds to the atmega PORTB bit 5. So writing a 1 to PINB bit 5 toggles the pin.
|
|
|
|
|
Logged
|
~Tom~
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 2
|
 |
« Reply #2 on: November 17, 2012, 03:42:11 pm » |
thank for your answer firstly.
as you said :Writing a logic 1 to a bit in the PINx register of many atmegas results in the corresponding output toggling its state.
how to understand "output toggling its state"? below understanding is right or not? the PINB13 keeps output mode, the LEDPIN_TOGGLE marco reverse the value in the PINB13?
|
|
|
|
« Last Edit: November 17, 2012, 03:57:09 pm by flyingyizi »
|
Logged
|
|
|
|
|
Leeds, UK
Offline
God Member
Karma: 35
Posts: 987
Once the magic blue smoke is released, it won't go back in!
|
 |
« Reply #3 on: November 17, 2012, 03:53:03 pm » |
I believe your understanding is correct.
A bit of background (I am using I/O to mean a physical pin on the chip to avoid confusion with the PIN register).
There are 3 registers that control any given I/O on the chip:
PIN = input register PORT = output register DDR = direction register.
The direction register controls whether an I/O is an input or an output. Behind the scenes pinMode(pin); uses this register. The input register is what you use to read the current state of the I/O. If the I/O is an input PIN returns the value of whatever is connected, if it is an output, PIN returns the value in PORT. The output register is what you use to set the state of an I/O. If the I/O is an output, PORT sets it to be a 1 or a 0. If the I/O is an input, PORT sets whether or not the internal pullup is enabled.
If the DDR register is set to Output, and you try to write to the PIN register, the I/O toggles such that if the output state is a 1, it becomes a zero and vice versa.
|
|
|
|
|
Logged
|
~Tom~
|
|
|
|
Offline
Edison Member
Karma: 114
Posts: 2205
|
 |
« Reply #4 on: November 17, 2012, 05:12:55 pm » |
Writing a logic 1 to a bit in the PINx register of many atmegas results in the corresponding output toggling its state. So what happens if you execute "PINx |= (1<<5);", vs. "PINx = (1<<5);"? 
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Tesla Member
Karma: 73
Posts: 6631
Arduino rocks
|
 |
« Reply #5 on: November 17, 2012, 07:56:51 pm » |
The latter would be correct I think, the former will toggle the pin you want and any others that read HIGH. Or am I missing something? Figure 13.2 in the datasheet seems to imply this.
|
|
|
|
|
Logged
|
|
|
|
|
Online
Sr. Member
Karma: 23
Posts: 446
|
 |
« Reply #6 on: November 17, 2012, 08:33:06 pm » |
[That smiley makes me somewhat suspicious that dhenry has written that as a trick question knowing full well the answer, if so I shall attempt to spoil his fun]
What happens depends on what the compiler does. Under some circumstances it can compile PINx |= 1<<y into an SBI instruction, and then clause 13.2.2 of the datasheet applies - only the single pin will be toggled. Otherwise it gets compiled into a ld/ori/st sequence, and the pin gets toggled, other output pins get cleared, and goodness knows what happens to the inputs. This is particularly relevant to the Mega - PINB |= 1<<7 gets compiled to an SBI but PINH |= 1<<7 doesn't.
My advice would be to only use PINx = 1<<y and never to use PINx |= 1<<y unless you really know what you are doing. I don't think it's any faster, at best it is shorter by a couple of bytes.
|
|
|
|
|
Logged
|
|
|
|
|
Left Coast, CA (USA)
Online
Brattain Member
Karma: 279
Posts: 15315
Measurement changes behavior
|
 |
« Reply #7 on: November 17, 2012, 08:45:14 pm » |
So for a overly simplistic example (and to do away with bitwise logic so as to just show the usage and purpose of the three I/O registers associated with a specific PORT of the two totally different and independent usage of a PINx register, in a specific sequence as shown. DDRD = B11111111; // all 8 bits in port D set to output mode (arduino pin numbers 0 to 7) PORTD = B00000000; // all 8 output bits in output port D set to 0 (arduino pins numbers 0 to 7 all go to 0) PIND = B11111111; // all 8 output bits in port D toggle (arduino pins 0 to 7 all change to 1) PIND = B11111111; // all 8 output bits in port D toggle (arduino pins 0 to 7 all change back to 0) PIND = B11111111; // all 8 output bits in port D toggle (arduino pins 0 to 7 all change back to 1) PIND = B11111111; // all 8 output bits in port D toggle (arduino pins 0 to 7 all change back to 0) PORTD = B11111111; // all 8 output bits in output port D set to 1 (arduino pins numbers 0 to 7 all set to 1) DDRD = B00000000; // all 8 bits in port D set to input mode (arduino pin numbers 0 to 7) PORTD = B11111111; // all 8 input bits in PIND will have weak pull-ups turned on (arduino pins numbers 0 to 7) PORTD = B00000000; // all 8 input bits in PIND will have weak pull-ups turned off (arduino pins numbers 0 to 7) Variable = PIND; // read value of input pins D.0 to D.7 and write them into Variable (arduino pins 0 to 7)
So clearly there is error in the arduino reference documentation for Port Registers: http://www.arduino.cc/en/Reference/PortManipulationWhere it states that registers PINx are read only as clearly there is a useage for both reading and writing to a PINx register if one wants to. PIND - The Port D Input Pins Register - read only //wrong! Lefty
|
|
|
|
« Last Edit: November 17, 2012, 08:56:54 pm by retrolefty »
|
Logged
|
|
|
|
|
Offline
Edison Member
Karma: 114
Posts: 2205
|
 |
« Reply #8 on: November 17, 2012, 09:01:04 pm » |
What happens depends on what the compiler does... Here is what a famous compiler did: PINB |= (1<<7); 00009A 9A1F SBI 0x3,7 PINB = (1<<7); 00009C E800 LDI R16,0x80 00009E B903 OUT PINB,R16
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Edison Member
Karma: 114
Posts: 2205
|
 |
« Reply #9 on: November 17, 2012, 09:06:14 pm » |
To make it more interesting, here is what the same compiler did to a slightly different code: PINB |= (1<<7) | (1<<6); 00009A B103 IN R16,PINB 00009C 6C00 ORI R16,0xC0 00009E B903 OUT PINB,R16 PINB = (1<<7) | (1<<6); 0000A0 EC00 LDI R16,0xC0 0000A2 B903 OUT PINB,R16
Stuff like this would be a nightmare to debug. That's probably something like this is rarely seen - the authors of the arduino reference made the right call. For the record, I always use PORTx ^= (1<<7); for something like this.
|
|
|
|
« Last Edit: November 17, 2012, 09:08:21 pm by dhenry »
|
Logged
|
|
|
|
|
Global Moderator
Melbourne, Australia
Offline
Shannon Member
Karma: 219
Posts: 13896
Lua rocks!
|
 |
« Reply #10 on: November 18, 2012, 11:20:24 pm » |
Well you learn something new every day. You can rewrite the Blink sketch like this: void setup () { pinMode (13, OUTPUT); } // end of setup void loop () { PINB |= _BV (5); delay (1000); } // end of loop
I tested it, that toggles pin 13. Also this, so it doesn't matter how the compiler outputs the 1: void setup () { pinMode (13, OUTPUT); } // end of setup void loop () { PINB = _BV (5); delay (1000); } // end of loop
Of course it's not as portable, but that is a quick way of toggling a pin. From the datasheet for the Atmega328, page 77: Toggling the Pin
Writing a logic one to PINxn toggles the value of PORTxn, independent on the value of DDRxn. Note that the SBI instruction can be used to toggle one single bit in a port.
|
|
|
|
|
Logged
|
|
|
|
|
Global Moderator
Melbourne, Australia
Offline
Shannon Member
Karma: 219
Posts: 13896
Lua rocks!
|
 |
« Reply #11 on: November 18, 2012, 11:23:42 pm » |
The latter would be correct I think, the former will toggle the pin you want and any others that read HIGH. Or am I missing something? Figure 13.2 in the datasheet seems to imply this.
I would read that as, if the byte you output has 1 bits, any pins corresponding to the 1 bit will be toggled and the others not. In other words, you could toggle up to 8 pins.
|
|
|
|
|
Logged
|
|
|
|
|
Global Moderator
Melbourne, Australia
Offline
Shannon Member
Karma: 219
Posts: 13896
Lua rocks!
|
 |
« Reply #12 on: November 18, 2012, 11:27:15 pm » |
This test confirms that hypothesis: void setup () { DDRB = 0xFF; PORTB = 0xAA; } // end of setup void loop () { PINB = 0xFF; delay (1000); } // end of loop
6 lots of pins toggle on and off (3 on and 3 off).
|
|
|
|
|
Logged
|
|
|
|
|
|