0

i have 25 relays which has min 15 different configurations, which have to be stored in a "array" or something simple...i have to switch those relays on/off (HiGH/LOW).

to use as less memory as possible i want to do it with a "trick" using bit's like:

char two = B1011011;
int mask = 1;
for(int i=0; i<7; i++){
if((mask & two) == 0) digitalWrite(pins[i], LOW); else  
digitalWrite(pins[i], HIGH);
mask = mask << 1;
}

but char has only 8 bits and I NEED min 25 bits... so now it the question NR.1, can i use uint32_t just in the same way as char just with 32 bits's? or something else?

uint32_t BIG1 = B10110110111011011111101101101
uint32_t BIG2 = B10110110111011011011101101101
uint32_t BIG3 = B10110110111111011011101101101
...
uint32_t BIG = B10110110111011011011101101101;//B... and 31 0s and 1s
uint32_t mask = 1;//????? not right???
for(int i=0; i<31; i++){
  if((mask & two) == 0) digitalWrite(pins[i], LOW); else  
digitalWrite(pins[i], HIGH);
mask = mask << 1;
};

what would be the mask then? or is there a better/easyer/faster way to set OUTPUTS to the needed value?

Thank you in davance!

Max
  • 33
  • 1
  • 8
  • do you want to set pins in a sequence, or also allow random pin setting? – Erobrere Jan 12 '16 at 09:25
  • @Erobrere it should be a random setting possible, it will depend on value of temperature sensors... – Max Jan 12 '16 at 09:27
  • http://stackoverflow.com/questions/19626652/how-to-read-specific-bits-of-an-unsigned-int and http://stackoverflow.com/questions/11815894/how-to-read-write-arbitrary-bits-in-c-c should answer you. in case you still need an explanation, post a comment – Erobrere Jan 12 '16 at 09:48

1 Answers1

2

As I already told you in the other thread, the easiest and fastest way to do this is to deal with PORTS rather than individual pins.

For example, on the arduino UNO pins 0..7 map to port D pins 0..7, so when you do something like

uint8_t the_value_i_want = 0b01001000;
PORTD = the_value_i_want;

you write the pins 0..7 in a single instruction. Now, again with the uno, the complete mapping is

  • PORTD maps to Arduino digital pins 0 to 7
  • PORTB maps to Arduino digital pins 8 to 13. The two high bits (6 & 7) map to the crystal pins and are not usable
  • PORTC maps to Arduino analog pins 0 to 5. Bit 6 is the reset pin, so it's not usable, while bit 7 does not exist.

So things are a bit more complicated for the other ports. Well, the easiest way to handle this is making a function to mask the relevant bits. Just note that the masking is the same for port B and C, but this is just a coincidence.

#define PORT_B_C_MASK = 0x3F;
void write_with_mask(volatile uint8_t *p_register, uint8_t mask, uint8_t value)
{
    *register = (*register | (value & mask)) & (value | ~mask);
}

Now you can write easily the instructions to write the value you want on the port. For instance, if you want to turn on pins 3, 6, 8 and 10, you just have to provide two values (one for port D, i.e pins 0..7, and one for port B, pins 8..13):

uint8_t the_value_i_want_8_13 = 0b000101;
uint8_t the_value_i_want_0_7 = 0b01001000;

write_with_mask(&PORTB,PORT_B_C_MASK,the_value_i_want_8_13);
PORTD = the_value_i_want_0_7;

Now, if you want to make a const matrix with all the possible values (again, this applies for the UNO only), you can just make a three-columns uint8_t matrix. Something like

int allvalues[][3] = { {0b001000, 0b001010, 0b00000001},
                    ...};

In this case, with the first configuration (the reported one) pins A3, 0, 9, 11 will be turned on, the others will be off.

A possible function to apply this is

void apply_configuration(uint8_t index)
{
    write_with_mask(&PORTC,PORT_B_C_MASK,allvalues[index][0]);
    write_with_mask(&PORTB,PORT_B_C_MASK,allvalues[index][1]);
    PORTD = allvalues[index][2];
}

This way you just have to provide the index for the configuration (the row) you want to apply.

If, for some reasons, you want to exclude some pins (e.g. pin 0 and 1, since they are the serial interface) you just have to include it in the mask. For instance:

#define PORT_B_MASK = 0x3F;
#define PORT_C_MASK = 0x0F;
#define PORT_D_MASK = 0xFC;
void apply_configuration(uint8_t index)
{
    write_with_mask(&PORTC,PORT_C_MASK,allvalues[index][0]);
    write_with_mask(&PORTB,PORT_B_MASK,allvalues[index][1]);
    write_with_mask(&PORTD,PORT_D_MASK,allvalues[index][2]);
}

This way I excluded pins 0 and 1 (serial interface) and pins A4 and A5 (I2C interface).

Just one remark: I used the UNO as example, but you can use any board. Just look at the pin mapping to understand what is the association between ports and arduino pins.

frarugi87
  • 2,826
  • 1
  • 20
  • 41
  • NOW i got you... i tried the matrix you did talked about in the last thread, and i understood matrix-library and tried to solve it with that... but i was unfortunately not successful.. I use an Arduino mega2560 so will have to update your SUPERB description to MEGA... – Max Jan 12 '16 at 10:49
  • Just the question on MASKing...`write_with_mask(&PORTC,PORT_C_MASK,allvalues[index][0]);` here you write ALL pins on Port C with mask `#define PORT_C_MASK = 0x0F;` ... and in the MASK is "00001111"? But you say "A4 and A5 (I2C interface)." Did i miss something? – Max Jan 12 '16 at 10:56
  • What do you mean by matrix library? Matrices are handled natively by C ;) Anyway I thought you used the mega (in the end, you need 44 pins) but this is perfectly fine also with that board. Just look at the [ATmega2560-Arduino Pin Mapping](https://www.arduino.cc/en/Hacking/PinMapping2560) page to discover which pins are attached to which port. – frarugi87 Jan 12 '16 at 10:57
  • In the mask you put a 1 for each bit you want to affect. I mean, with a mask 0x0F (which is 0b00001111) you will only overwrite bits 0, 1, 2 and 3; the others are left untouched. So if you want to write some values to pins PORTC 0, 2 and 4, for instance, just use a mask 0b00010101. In the example I wanted to use every pin except A5 and A4 (I2C interface); moreover pins 6 and 7 cannot be used (6 is reset, 7 is missing). So I can only write pins 0 to 3, which leads to a mask 0b00001111 (only bits 0 to 3 are set), i.e. 0x0F – frarugi87 Jan 12 '16 at 11:00
  • Thank you! the part i missed was that MASK and allvalues are compared like `MASK | allvalues` so both have to be 1 to switch! When one of Mask or allvalues is 0, it WILL NOT AFFECT the pin! Right? – Max Jan 12 '16 at 12:29
  • No, when mask is 0 it will not affect the pin. If mask is 1 and allvalues is 0 the pin will be shut down (that's what the `& (value | ~mask)` part is for) – frarugi87 Jan 12 '16 at 13:31
  • since last answer trying to get i working. but no luck yet with MEGA 2560 R3 :-( mask does not work `#define PORT_A_MASK 0x00 #define PORT_C_MASK 0x0F ` void is the same as yours just with `*p_register = (*p_register...}` not `*register` typo? and void `apply_configuration` is the same. So with `int relay_scenes[][2] = { {0b11111111, 0b11111111}, //...};` the output with `digitalRead(pin);` is `0000 0000 0000 1111` so it seems, that is only write the mask and not the scene :-? – Max Jan 16 '16 at 14:15
  • First of all the p_register was a typo, yes ;) I fixed it now. As for the other behavior, maybe you did not understand what masks are for. A 0 in the mask means "don't consider that bit". So if you write 0b11111111 with a mask 0b00001111 you will get 0xXXXX1111, where X is the state of the pin before the instruction. Usually it is 0, but not always. If you try to write `int relay_scenes[][2] = { {0b01010101, 0b01010101}, //...};` I bet you will get `0000 0000 0000 0101`. Seen? The bytes made as 0 in the mask don't matter – frarugi87 Jan 16 '16 at 16:22
  • Anyway, I don't think that you can reliably use the digitalRead with output pins... You should read directly from the PORTx registers (see [this answer](http://stackoverflow.com/a/6171551/3368201)) – frarugi87 Jan 16 '16 at 16:24