Как инициировать два массива, хранящих 16 бит каждый и создание третьего массива XOR на первых двух в C? - PullRequest
0 голосов
/ 18 апреля 2019

Я нахожусь в процессе сборки драм-машины и хочу иметь два 16-битных массива, определяющих состояние машины.Один массив "current_led", который имеет 1, установленный в индексе, соответствующем текущей 16-ой ноте, которую играют.

Когда пользователь программирует звук для воспроизведения, например, на шагах 1 и 4, я хочу, чтобы один 16-битный массив selected_steps имел 1, установленный в индексах 0 и 3.

Поэтому я хочу, чтобы на каждом шаге обновления, определяемом числом ударов в минуту, «current_led» сдвигал бит, но «selected_steps» был статическим.

Мне нужен конечный массив «led_array», который строится из

led_array = XOR(selected_steps,current_led)

Это так, что я могу использовать сдвиговый регистр для подсветки правильных светодиодов при каждом шаге обновления.

Но так как у меня есть некоторые проблемы с определением и работой с битами и массивами в CI, я не понимаю, как правильно инициализировать массивы и работать с ними.

Что бы я хотел, что-то вроде

  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;
  }

Я использую 2 сдвиговых регистра PISO для передачи ввода с 16 кнопок на мой микроконтроллер.У меня постоянный высокий нагрузочный вывод Parallell, так что всякий раз, когда пользователь нажимает кнопку, соответствующий вывод на регистре сдвига устанавливается на 1. Поэтому я читаю каждые 16 контактов каждый раз, чтобы увидеть, нажал ли пользователь какой-либокнопки.

  //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...
        }
     }
  } 

Итак, для ясности, вот пример того, как светодиоды должны представлять это состояние.Если BPM установлен на 120, и у нас есть 16 шагов (4 удара), шаг должен увеличиваться каждые 60 / BPM секунд (0,5 секунды).Текущий шаг обозначен ярким светодиодом.Я также указываю пользователю, на каком этапе он / она запрограммировал звук, постоянно включая светодиод на этом текущем шаге.

Шаг 1: step_number = 0

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

Шаг2: step_number = 1

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

Шаг 3: step_number = 2, selected_step [7] = 1, selected_step [11] = 1,

(пользователь выбрал ввод звука нашаги 8 и 12 нажатием кнопок 8 и 12)

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

Шаг 4: номер_шага = 3, выбранный_шаг [7] = 1, выбранный_шаг [11] = 1,

(у пользователя естьне нажимал ни одной кнопки с момента последнего шага)

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

Но я не понимаю, как объявлять массивы и писать правильный код для правильной установки битов и выполнения операций XOR.

1 Ответ

0 голосов
/ 18 апреля 2019

Вот как вы можете устанавливать и очищать биты в uint16_t (то же самое относится и к любым беззнаковым целым, просто измените типы соответственно)

Прошло много времени с тех пор, как я выполнял какие-либо битовые манипуляции, поэтому вы должны дважды проверить это прежде чем использовать его, у меня нет времени, чтобы сделать это самому.

/* 
   `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;

В зависимости от вашего варианта использования вы можете определить эти функции как static inline. Также может иметь смысл превратить step_number в маску, а не в индекс.

...