简体   繁体   中英

How to initiate two arrays storing 16 bits each and creating a third array by XOR on the first two in C?

I am in the process of building a drum machine and I want to have two 16 bit arrays defining the state of the machine. One array "current_led" which has a 1 set at the index corresponding to the current 16th note being played.

When the user programs a sound to be played, for instance at step 1 and 4, I want one 16 bit array "selected_steps" to have a 1 set at index 0 and 3.

So I want, at each step update defined by the beats per minute, the "current_led" to shift the bit but the "selected_steps" is static.

I want a final array "led_array" which is constructed by

led_array = XOR(selected_steps,current_led)

This is such that I can use a shift register to light up the correct LED's at each step update.

But since I have some trouble defining and working with bits and arrays in CI do not understand how to initialize the arrays correctly and work with them.

What I would want it something like

  int current_led[16];
  int selected_steps[16];
  int led_array[16];

  //Function is called every 0.5 s if BPM 120.
  void step(void) {
  step_number = step_number < 15 ? step_number +1 : 0;
  }

I am using 2 PISO shift registers to take the input from 16 buttons to my micro controller. I have the parallell load pin set to high constantly, such that whenever the user pushes a button, that corresponding pin on the shift register is set to 1. Therefore I am reading each 16 pins every time to see if the user has pushed down any buttons.

  //Check which steps are selected by the user. This function is called every 1 ms
  void scan_buttons() {
  for (int j = 0; j<16 ; j++) {
      if (PIND & 0b01000000){
            selected_steps[j] = 1;
            } else {
            selected_steps[j] = 0;
        }


  void update_led(void) {
     current_led = (1 << step_number);
     led_array = current_led^selected_steps;

     for (int j = 15; j>=0 ; j--) {
        if (led_array[j] == 1) {
           do something...
        } else {
           do something else...
        }
     }
  } 

So for clarity, here is an example of how the LED's should represent that state. If the BPM is set to 120, and we have 16 steps (4 beats), the step should increment every 60/BPM seconds (0.5 seconds). The current step is indicated by a bright LED. I also indicate to the user which step he/she has programmed a sound on by always having the LED light up at that current step.

Step 1: step_number = 0

LED: [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

Step 2: step_number = 1

LED: [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

Step 3: step_number = 2, selected_step[7] = 1, selected_step[11] = 1,

(User has chosen to input a sound on step 8 and 12 by pressing button 8 and 12)

LED: [0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0]

Step 4: step_number = 3, selected_step[7] = 1, selected_step[11] = 1,

(User has not pressed any buttons since last step)

LED: [0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0]

But I do not understand how to declare the arrays, and write the correct code to set the bits correctly and perform XOR operations.

Here is how you may set and clear bits in a uint16_t (the same goes for any unsigned ints, just change the types accordingly)

It is a long time since i have done any bit-manipulations, so you should double check this before you use it, don't have any time to do it myself.

/* 
   `set_bits`, `unset_bits` and `flip_bits` modifies multiple bits in v.

    The bits you want to modify are selected by setting the corresponding bit
    in `mask` to 1.
*/

uint16_t set_bits(uint16_t v, uint16_t mask)
{
   return v | mask;
}

uint16_t unset_bits(uint16_t v, uint16_t mask)
{
   return v & ~mask;
}

uint16_t flip_bits(uint16_t v, uint16_t mask)
{
   return v | ((~v) & mask)
}

/* 
 `set_bit`, `unset_bit`, `flip_bit`, `overwrite_bit` modifies a single bit in `v`.
 The bit to modify is given by the index `i`
*/

uint16_t set_bit(uint16_t v, int i)
{
   return set_bits(v, 1 << i);
}

uint16_t unset_bit(uint16_t v, int i)
{
   return unset_bits(v, 1 << i);
}

uint16_t flip_bit(uint16_t v, int i)
{
   return flip_bits(v, 1 << i);
}

uint16_t overwrite_bit(uint16_t v, int i, int new_val)
{
   /* ensure `new_val` is either 0 or 1 */
   new_val = new_val ? 1 : 0;

   uint16_t mask = 1 << i;
   uint16_t mask_x = ~mask; 

   uint16_t nv = new_val << i;

   return v & (mask_x | nv);
}

int read_bit(uint16_t v, int i)
{
   uint16_t mask = 1 << i;
   return (v & mask) ? 1 : 0;
}  


/* How to initialize all the bits in `selected_steps` to zero */
selected_steps = 0;

/* How to initialize all the bits in `selected_steps` to 1 */
selected_steps = 0xffff;  /* or  = 0b1111111111111111 */ 


/* How to read the value of bit 8 in `selected_step` */

int val = read_bit(selected_steps, 8);

/* How to set the value of bit 8 to 1 */
selected_steps = set_bit(selected_steps, 8);
/* or */
selected_steps = overwrite_bit(selected_steps, 8, 1);
/* or */
selected_steps = set_bits(selected_steps, 0b100000000);


/* How to set the value of bit 8 to 0 */
selected_steps = unset_bit(selected_steps, 8);
/* or */
selected_steps = overwrite_bit(selected_steps, 8, 0);
/* or */
selected_steps = unset_bits(selected_steps, 0b100000000);

/* Setting bits 1 and 4 to 1 */
selected_steps = set_bits(selected_steps, 0b10010);
/* or */
selected_steps = set_bits(selected_steps, (1<<4) | (1<<1));

/* Calculating xor of two bitsets */
uint16_t xor_a_b = a ^ b;

Depending of your use case, you may choose to define these functions as static inline . It may also make sense to turn step_number into a mask rather than index.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM