command digitalWrite ();

Hi Brothers :slight_smile:

I would like to understand if it is possible to activate two leds simultaneously in the ‘digitalWrite ();’ command. For example, digitalWrite (led1, led2, & HIGH & HIGH);
Is this possible?

Gostaria de entender se é possível acionar dois leds simultaneamente no comando ‘digitalWrite()’. Por exemplo, digitalWrite(led1, led2, &HIGH &HIGH);
Isto seria possível?

no, do
digitalWrite(led1, HIGH);
digitalWrite(led2, HIGH);
for human eye it will be “simultaneously”

See answer above.

But if you really need them to be simultaneously, have a look at Arduino - Port manipulation. Be aware that this is only for AVRs and can break compatibility between e.g. Uno and Leonardo.

sterretje:
See answer above.

But if you really need them to be simultaneously, have a look at Arduino - Port manipulation. Be aware that this is only for AVRs and can break compatibility between e.g. Uno and Leonardo.

led1.png

1. digitalWrite(arg1, arg2); function cannot be used to ignite two LEDs simultaneously as the function has syntax limitation in respect of taking only two arguments. But, the OP has four arguments -- two LEDs and two values.

2. Register level instructions, as mentioned in Post#2, allow simultaneous activation of two LEDs.

PORTB = 0b000011;//assume that the port-pin directions are already set as output

led1.png

GolamMostafa:
//assume that the port-pin directions are already set as output

Not relevant. digitalWrite does not affect the data direction register.

More to the point, to emulate digitalWrite, you must read the output register first and mask in the bits - and only those bits - you wish to define anew.

And by the way, digitalWrite(...) is a function, not a command.

GolamMostafa:

PORTB = 0b000011;//assume that the port-pin directions are already set as output

That also sets all the other pins low. It should be:

PORTB |= 0b00000011;

GolamMostafa:
led1.png
2. Register level instructions, as mentioned in Post#2, allow simultaneous activation of two LEDs.

PORTB = 0b000011;//assume that the port-pin directions are already set as output

Does the above instruction really activate the two LEDs simultaneously?

After compilation, the above single line instruction is broken down into the following assembly codes (as an intermediate language before going to have transformation into machine codes) which clearly indicate that the LEDs are activated one after another:

sbi PORTB, PB0
sbi PORTB, PB1

Are you absolutely positive that line gets broken into two separate instructions? I think it just writes the value to the port register all in one go.

Compile it and show us some output.

Delta_G:
Are you absolutely positive that line gets broken into two separate instructions? I think it just writes the value to the port register all in one go.

Compile it and show us some output.

1. I am not absolutely sure; however, my opinion has been based on the following reasoning:
(a) Whatever might be the high level form of an instruction, it has to be active at the register level. Therefore, the MCU must execute the following sbi instruction for two times as the sbi instruction handles only 1-bit location of an IO Port and there are two bits to activate.


Figure-1: Template of sbi instruction

2. I have no tool to dump the assembly codes that might have been generated by the gcc of the IDE.

3. I have made a dump of the hex file of the following sketch containg PORTB = 0b000011; instructions. The machine codes (8 times done purposely so that I can spot them) are marked bold. The instruction (opcode+operand) is 85B9 -- a single 16-bit code that, most likely, has activated both PB0 and PB1 simultaneously; but, how? I have difficulties to derive this code following instruction of Fig-1.

void setup() 
{
  PORTB = 0b000011;
  PORTB = 0b000011;
  PORTB = 0b000011;
  PORTB = 0b000011;
  PORTB = 0b000011;
  PORTB = 0b000011;
  PORTB = 0b000011;
  PORTB = 0b000011;
}

void loop() 
{
  
}

  1. No way. It's way more efficient just to write one value to the port. I don't know the assembly cause I don't, but I know it's all one write to one register. You can only write one byte at a time.

  2. Yes you do. I believe it is objdump. I don't know about it but others around here do. Maybe it's time for me to learn.

  3. bitwise OR is byte wide so it writes both bits at once. The asignments you have in this code aren't done with sbi. Even sbi has to read the register, or in the bit, and write the register. The RIGHT code here (#6) does the same thing but it sets both bits at once with a single bitwise OR.

Delta_G:
3. bitwise OR is byte wide so it writes both bits at once. The asignments you have in this code aren't done with sbi. Even sbi has to read the register, or in the bit, and write the register. The RIGHT code here (#6) does the same thing but it sets both bits at once with a single bitwise OR.

When I assemble sbi PORTB, PB0 using Atmel Studio 7 for ATmega328P, I get this machine code: 9A28 (1001 1010 0010 1000 ---> 10011010 00101 000 = opcode + PORTB_address(0x05) + PBO_bit_address (0x00) which agrees with the following instruction template--

The machine code (85B9 = 1000 0101 1011 1001) generated by the gcc of IDE for the instruction PORTB = 0b000011; certainly activates both PB0 and PB1 in one clock cycle; it would be a great learning if someone can figure out the mechanism of how gcc has produced this machine code?

GolamMostafa:
The machine code (85B9 = 1000 0101 1011 1001) generated by the gcc of IDE for the instruction PORTB = 0b000011; certainly activates both PB0 and PB1 in one clock cycle; it would be a great learning if someone can figure out the mechanism of how gcc has produced this machine code?

I tried in response to your earlier post - and gave up. It is unbelievably obscure. The instruction appears to load register 0x1B from the Y register offset by nine.

The point is again though, that your instruction not only sets PB0 and PB1, but also clears PB2 to PB7.

Paul__B:
I tried in response to your earlier post - and gave up. It is unbelievably obscure. The instruction appears to load register 0x1B from the Y register offset by nine.

It is here; the LDD Rd, Y+q instruction, perhaps, activates PB0 and PB1 bits simultaneously; the instruction could be taken as the assembly equivalent of PORTB = 0b000011; instruction. The binary code 85B9 of PORTB = 0b000011; can be deduced from the following instruction template of LDD instruction.
ldd.png

PORTB = 0b000011; -----> 85B9 = 1000 0101 1011 1001

LDD Rd, Y+q -----> 10q0 qq0d dddd 1qqq
Rd's address : d dddd = 1 1011 = 0x1B (27) //What is this register with address 1B?
q (offset) : q qq qqq = 0 01 001 = 0x09

ldd.png

The point is that these writes ALL happen a byte at a time. Under no circumstances are you ever restricted to writing only one bit at a time. Everything works on byte wide quantities.

And the REAL point is STILL that to set those two pins, this line:

PORTB = 0b00000011;

is wrong and it should be

PORTB |= 0b00000011;

GolamMostafa:
Rd's address : d dddd = 1 1011 = 0x1B (27) //What is this register with address 1B?

Well, that's the absurd bit. Register 0x1B is the PCIFR – Pin Change Interrupt Flag Register

Delta_G:
And the REAL point is STILL that to set those two pins, this line:

PORTB = 0b00000011;

is wrong and it should be

PORTB |= 0b00000011;

Yeah, well you keep pointing that out, I keep pointing that out ... :roll_eyes:

Paul__B:
Well, that's the absurd bit. Register 0x1B is the PCIFR – Pin Change Interrupt Flag Register. [...].

We are expecting PORTB Register with address 0x05 to have been covered by ddddd bits of the LD Rd, Y+q instruction; but, it is not obvious in the code 85B9 which the IDE has produced against the PORTB = 0b000011; instruction.

LD Rd, Y+q instruction loads the Rd Register (address range: 0x00 - 0x1F) with an 8-bit value which resides in a RAM location whose address is being pointed by Y (+q) Register. This instruction is almost to support the validity of the code 85B9 except that we have not yet been able to trace the address of PORTB Register in this code.

O.P. if you want pretty much simultaneous activation of the LED pair..... then use port manipulation methods.... where you can set the states of a bunch of pins in one hit. Otherwise .... if you just want relatively nearly simultaneous turn-on of two leds..... then just do what some people suggested..... use digitalWrite two times in succession. To your eyes....... the functioning LEDs will always look like they light up at the same time.

Also ... you can even make your own sub function that invovles digitalWrites.... where your function accepts two different pin numbers ... plus another number to be as a codeword for the states.... eg. binary 0 or 00 would mean both of.... and 10 would mean first led on and second led off..... etc.

The machine code 85B9 generated by IDE for the instruction PORTB = 0b000011; could be validated by the following assembly instructions under Atmel Studio 7.

                               start:
                                 #define PORTB r27
000000 e013                      ldi r17, 0b000011 ; data for PB0 and PB1
000001 9310 0129                 sts $0129, r17    ; data saved in RAM location 0x0129
000003 e0d1                      ldi r29, 0x01
000004 e2c0                      ldi r28, 0x20     ; Y register contains 0x0120
000005 85b9                      ldd r27, Y+9      ; r27 holds 000011 which eneters into PORTB throgh #define directive?
000006 cff9                      rjmp start

Now, the PORTB register could be seen in the LDD r27, Y+9 instruction provided that the r27 register has been equated to PORTB register using #define directive?

This really has you worried, hasn't it?

The trouble seems to be that PORTB is in fact, register 0x25, not 27.

And why the compiler would do all of that is difficult to comprehend. :astonished: