Циклический сдвиг битов

Тема в разделе "Arduino & Shields", создана пользователем Eragon, 23 апр 2017.

  1. mcureenab

    mcureenab Гуру

    Циклически бегущие огни без ассемблера.



    Код (C++):
    inline uint8_t ROL(uint8_t x)
    {
        return((x&0x80)>>7)|(x<<1);
    }

    static const uint8_t bit_pin [] = {3, 4, 5, 6, 7, 8, 9, 10 };

    void setup() {
    //    Serial.begin(250000);
    //    while(!Serial){};
    //    Serial.println("Staring...");
    //    DDRD = 0b11111111;  
        for( int8_t i = sizeof(bit_pin); i--; ) {
            pinMode(bit_pin[i], OUTPUT);
        }
    }

    void loop() {
      static uint8_t MyVar = 0b00001011;
    //  PORTD = MyVar;
      uint8_t v(MyVar);
      for( int8_t i = sizeof(bit_pin); i--; ) {
          digitalWrite(bit_pin[i], v & 0b1 ? HIGH : LOW );
          v >>= 1;
      }
      MyVar = ROL(MyVar);
      delay(200);
    }
     
     
  2. mcureenab

    mcureenab Гуру

    Код (C++):
     // Arduino UNO pins 0 - 7
    inline uint8_t ROL(uint8_t x)
    {
        return((x&0x80)>>7)|(x<<1);
    }
     
    обзову каждый бит буквой (буква может принимать значение 0 или 1), чтобы видно было куда какой бит попадает:
    пусть x = abcdefgh;
    x&0x80 = a0000000; побитовое и. оставили старший бит, который нужно закольцевать
    (x&0x80)>>7 = 0000000a; сдвиг вправо на 7 бит, закольцевали старший бит
    (x<<1) = bcdefgh0; собственно сдвиг влево. младший бит замещен 0, старший потерян
    ((x&0x80)>>7)|(x<<1) = bcdefgha; побитовое или воссоединяет закольцованный бит a со сдвинутой цепочкой bcdefgh
     
  3. Eragon

    Eragon Нерд

    Спасибо:) Буду думать как это к своему проекту применить!
     
  4. serg_admin

    serg_admin Гик

    Я так понял в конечном счете двигать нужно будет символы а не битики. Следовательно это код вообще не подойдет. Вам нужен "кольцевой буфер".
     
  5. Eragon

    Eragon Нерд

    Ну да, есть двумерный массив с данными температуры и времени его то мне и хочется сдвигать. Примерно вот так сделать планирую, если получится...) https://goo.gl/photos/uh8BhSByTi6hGJ4x8
     
  6. serg_admin

    serg_admin Гик

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

    Сдвигать элементы массива то же не целесообразно так как это вызывает большую нагрузку на процессор. Например если у Вас в строке 20 символов - нужно будет 20 перемещений.
    Гораздо эффективнее хранить номер элемента массива которой будет выводится в самой левой позиции дисплея. Аналогичная технология переменятся в кольцевых буферах:
    - буфер клавиатура
    - буфер данных RS232
     
  7. mcureenab

    mcureenab Гуру

    Обычно не массив двигают, а точку входа в него.
    Каждый раз отправляя данные на экран вы начинаете чтение массива с индекса j = i+1. Только нужно позаботится о том, чтобы после чтения последнего элемента, итератор переходил на элемент 0.
     
  8. Eragon

    Eragon Нерд

    Чую, зря я в этот сдвиг полез)) :D
     
  9. Eragon

    Eragon Нерд

    Можно даже и не запоминать, просто сдвинуть по очереди все 4 символа, а потом по такому же принципу отобразить температуру, только теперь символы должны появляться.
     
  10. mcureenab

    mcureenab Гуру

    Примерно так:

    Код (C++):
    class Iterator {
    public:
        Iterator( uint8_t i_start): pos(i_start) { if ( size <= pos ) pos = 0;  }
        Iterator& operator++() { if ( size <= ++pos ) pos = 0; return *this; }
    //    Iterator operator++(uint8_t) { Iterator res(*this); operator++(); return res; }
        operator uint8_t() const { return pos; }
    private:
        static const uint8_t size;
        uint8_t pos;
    };

    const uint8_t Iterator::size = ASZ;

    .... arr[ASZ]; // Строка для вывода в окно.

    loop {
        static Iterator pos(0); // Позиция окна вывода в строке arr.
        SetPos(0); // позиция печати
        for ( Iterator i(pos), uint8_t n(5); --n; ++i ) { // Выводим в окно из (5-1)=4х символов
            PrintCell(arr[i]); // печать символа и сдвиг в следующую позицию
        }
        ++pos; // Продвигаем окно
        delay(500);
    }
     
  11. Eragon

    Eragon Нерд

    Да, всё сложнее чем я думал...
     
  12. serg_admin

    serg_admin Гик

    Нет это просто подход такой. Можно реализовать и без итераторов. Просто кому то так быстрее.
     
  13. serg_admin

    serg_admin Гик

    Проверить не начем
    Код (C++):
    #define LEN 10

    char st[] = {'LCD 123456789'};
    int pos;
    void setup()
    {
      pos = 0;
      Serial.begin(9600);
    }



    void loop()
    {
      for(int i = pos; i++ ; i < LEN)
        Serial.print(st[i]);
      Serial.println(' ');

      pos++;

      if (pos >= LEN)
        pos = 0;
     
      delay(500);
    }
     
  14. mcureenab

    mcureenab Гуру

    Так проще, но это не циклический сдвиг. И логика циклического счётчика размазана по коду, а не собрана в классе.

    В цикл
    for(int i = pos; i++ ; i < LEN)
    нужно добавить размер "окна".
    На реальном экране "лишние" символы могут печататься и засорять изображение.

    Имитацию цикла можно получить повторением начала строки в конце.

    К стати еще вопрос, нужно чтобы строка выползала на пустой экран?
    Между циклами должен быть пустой экран?
     
  15. Eragon

    Eragon Нерд

    Ну да, срорее всего нужен. Там ещё такой нюанс есть... В момент чтения температуры с датчика индикатор заметно мерцал, Решил, я эту проблему считыванием показаний раз в минуту
    Код (C++):
    if (sec==0)dps.getTemperature(&Temperature);
    И отключением всех разрядов на момент чтения
    Код (C++):
    if (switchTime==0) PORTB |= B00001111
    Вот и получается, когда последний символ скроется нужно будет отключить разряды, а потом начинать выводить температуру... Я вот уже думаю, может зря я это затеял.....?:confused:
     
  16. serg_admin

    serg_admin Гик

    Вопрос в степени упрямства. При самообучении вещь необходимая.
     
  17. Eragon

    Eragon Нерд

    Согласен, всё таки основной скетч хоть переписывал несколько раз подряд, всё таки добился нужного функционала)) Конечно, надо пытаться задумку реализовать - может чего и получится...
     
  18. Igor68

    Igor68 Гуру

    Внутри цикла вывод значение MyVar в порт побитно... или как Вам больше подходит.
     
  19. Eragon

    Eragon Нерд

    Вывел значения MyVar в порт там - 2,4,8,16,32,64,128 и, что мне с этими цифрами делать???
     
  20. serg_admin

    serg_admin Гик

    Теперь вы умеете возводить двойку в степень :)

    Этот код только для бегущих огней подходит.
    Код (C++):
    DDRD = 0xFF;
    PORTD = MyVar;
     
    Последнее редактирование: 28 апр 2017