Массив bool в EEPROM

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

  1. postal2201

    postal2201 Нерд

    Здравствуйте! Помогите понять что делает данный код(в частности секция оператора for). Я так понимаю 3 массива (SCEE, SCEI, SCEA) постоянны и не изменяются в процессе работы программы? Можно ли хранить эти 3 массива в EEPROM размером 64 байта?
    Код (C++):

    void inject_SCEE()
    {
      //SCEE-array                                                                                                              
      FLASH_ARRAY (boolean, SCEEData, 1,0,0,1,1,0,1,0,1,0,0,1,0,0,1,1,1,1,0,1,0,0,1,0,1,0,1,1,1,0,1,0,0,1,0,1,0,1,1,1,0,1,0,0);
     
      int bit_counter;
     
      for (bit_counter = 0; bit_counter < 44; bit_counter = bit_counter + 1)
      {
        if (SCEEData[bit_counter] == 0)
        {      
          pinMode(data, OUTPUT);
          digitalWrite(data, 0);
          delay(delay_between_bits);
        }
        else
        {
          pinMode(data, INPUT);  
          delay(delay_between_bits);
        }
      }
     
      pinMode(data, OUTPUT);
      digitalWrite(data, 0);
      delay(delay_between_injections);
    }

    void inject_SCEA()
    {
      //SCEE-array                                                                                                                  
      FLASH_ARRAY (boolean, SCEAData, 1,0,0,1,1,0,1,0,1,0,0,1,0,0,1,1,1,1,0,1,0,0,1,0,1,0,1,1,1,0,1,0,0,1,0,1,1,1,1,1,0,1,0,0);
     
      int bit_counter;
     
      for (bit_counter = 0; bit_counter < 44; bit_counter = bit_counter + 1)
      {
        if (SCEAData[bit_counter] == 0)
        {      
          pinMode(data, OUTPUT);
          digitalWrite(data, 0);
          delay(delay_between_bits);
        }
        else
        {
          pinMode(data, INPUT);    
          delay(delay_between_bits);
        }
      }
     
      pinMode(data, OUTPUT);
      digitalWrite(data, 0);
      delay(delay_between_injections);
    }

    void inject_SCEI()
    {
      //SCEE-array                                                                                            
      FLASH_ARRAY (boolean, SCEIData, 1,0,0,1,1,0,1,0,1,0,0,1,0,0,1,1,1,1,0,1,0,0,1,0,1,0,1,1,1,0,1,0,0,1,0,1,1,0,1,1,0,1,0,0);
     
      int bit_counter;
     
      for (bit_counter = 0; bit_counter < 44; bit_counter = bit_counter + 1)
      {
        if (SCEIData[bit_counter] == 0)
        {      
          pinMode(data, OUTPUT);
          digitalWrite(data, 0);
          delay(delay_between_bits);
        }
        else
        {
          pinMode(data, INPUT);
          delay(delay_between_bits);
        }
      }
     
      pinMode(data, OUTPUT);
      digitalWrite(data, 0);
      delay(delay_between_injections);
    }
     
  2. Unixon

    Unixon Оракул Модератор

  3. rkit

    rkit Гуру

    Что написано в коде, то и делает. Переключает режим пина, выставляет значения, ставит задержку. Не понял, в чем ваш вопрос.

    Для этого надо взять всю программу и посмотреть, наверное. Скорее нет.

    Можно.
     
    Последнее редактирование: 16 янв 2017
  4. postal2201

    postal2201 Нерд

    Последнее редактирование: 16 янв 2017
  5. postal2201

    postal2201 Нерд

    Код (C++):
    for(bit_counter =0; bit_counter <44; bit_counter = bit_counter +1)
    {
       if(SCEEData[bit_counter]==0)
    что конкретно делает этот участок кода?
    Как? Пример можно, пожалуйста.
    P.S. Я всегда занимался только hawdware и только недавно начал изучать программирование, так что не ругайтесь если мои вопросы на уровне второклассника.
     
  6. rkit

    rkit Гуру

    Почитайте книжку по C++, это базовые конструкции языка. Я не объясню лучше, чем в книжке.
     
  7. postal2201

    postal2201 Нерд

    А по поводу хранения массива в EEROM, подскажите?
    С for в принципе разобрался,
    Код (C++):
    for(bit_counter =0; bit_counter <44; bit_counter = bit_counter +1)
    , четкик ситает до 44(выполняет 44 итерации),
    Код (C++):
    if(SCEEData[bit_counter]==0)
    , и сравнивает занчения из массива с нулем, далее уже изменяет состояние HIGH или LOW на соответствующей ноге мс.
    Вот как-бы мне этои массивы по компактнее хранить в Attiny13a.
     
  8. Tomasina

    Tomasina Сушитель лампочек Модератор

    компактнее вот так: один байт, это 8 бит - 0x01010101. В двоичной логике бит может иметь состояние либо 0, либо 1.
    Тип boolean тоже может иметь только два состояния: false или true, это синонимы 0 и 1.
    Получается, в одном байте мы можем хранить 8 переменных псевдотипа boolean. Для хранения 45 логических элементов понадобится 45:8=6 байт. Для сравнения - хранение массива из 45 элементов boolean займет 45 байт.
    То есть получаем экономию памяти в 39 байт, для Attiny13a это весомая величина.
    Ну понятно, что код будет немного сложнее, чем просто для записи массива из boolean.
    Для понимания как записать и прочитать один определенный бит в байте, все равно придется читать доки, если конкретно, то это называется битовые маски. Подсказка: в Arduino есть функции readByte, writeByte для работы с битовыми масками.
     
  9. Unixon

    Unixon Оракул Модератор

    Вы всю ветку по ссылке прочитали?
     
  10. postal2201

    postal2201 Нерд

    Попробовал разобраться с функциями чтения\записи Unixon.
    Код (C++):
    #include <EEPROM.h> // подключаем библиотеку EEPROM

    void setup() {
      Serial.begin(9600); // инициализация послед. порта
    }

    bool readBit(int index)
    {
      int byte_index = index >> 3;
      byte bits = EEPROM.read(byte_index);
      int bit_index = index & 0x7; // same as (index - byte_index<<3) or (index%8)
      byte mask = 1 << bit_index;
      return (0 != (bits & mask));
    }

    void writeBit(int index, bool value)
    {
      int byte_index = index >> 3;
      byte bits = EEPROM.read(byte_index);
      int bit_index = index & 0x7; // same as (index - byte_index<<3) or (index%8)
      byte mask = 1 << bit_index;
      byte new_bits = (bits & ~mask) | value << bit_index;
      EEPROM.write(byte_index, new_bits);
    }

    void loop() {
      for (char i = 0; i < 4; i++) writeBit(i, 1);

      {
        bool val = readBit(0);
        Serial.print(0);
        Serial.print("\t");
        Serial.println(val);
      }
    }
    Поверил на Ардуинке, биты пишутся и считываются. Теперь 2 проблемы. Как используя функцию writeBit записать одновременно 48 бит. Понимаю что с помощью цикла for но знаний пока не хватает правильно составить цикл записи. И второе, вытекает из первого,как считать массив из 48 бит с помощью readBit.
    P.S. В принципе writeBit будет использоваться в моей прошивке только один раз для заполнение EEPROM полезными данными, а далее фьюз EESAVE, поможет сэкономить место и продлить жизнь eeprom`ке. Жду Вашей помощи :)
     
  11. Unixon

    Unixon Оракул Модератор

    Если вам нужно всю битовую карту записать разом, тогда имеет смысл использовать буфер, особенно при записи. Для операции чтения это не так актуально, можно EEPROM и перечитать несколько раз, а для операции записи это будет значимой оптимизацией. Т.е. вы в некоторый массив uint8_t buf[BUF_SZ] записываете данные побитно, а потом сам буфер сбрасываете в EEPROM уже побайтно.
     
  12. postal2201

    postal2201 Нерд

    Продвигаюсь шагами младенца. :) Сегодня получилось правильно сбрасывать битовую карту в EEPROM. С чтением из EPROM тоже все ОК. Но есть проблема с заполнением массива uint8_t data[18]. Как мне его заполнить за один раз полезными данными. Не писать же мне 144 раза writeBit для каждого бита в массиве.
    Код (C++):
    #include <EEPROM.h> // подключаем библиотеку EEPROM

    void setup() {

      Serial.begin(9600); // инициализация послед. порта

    }

    uint8_t data[18];

    bool readBit(int index)
    {
      int byte_index = index>>3;
      byte bits = EEPROM.read(byte_index);
      int bit_index = index & 0x7; // same as (index - byte_index<<3) or (index%8)
      byte mask = 1<<bit_index;
      return (0!=(bits & mask));
    }

    void writeBit(int index, bool value)
    {
      int byte_index = index>>3;
      byte bits = data[byte_index];
      int bit_index = index & 0x7; // same as (index - byte_index<<3) or (index%8)
      byte mask = 1<<bit_index;
      byte new_bits = (bits & ~mask) | value<<bit_index;
      data[byte_index] = new_bits;
    }

    void loop() {

      writeBit(0, 0);
      writeBit(1, 1);
      writeBit(2, 1);
      writeBit(3, 0);
      writeBit(4, 1);
      writeBit(5, 0);
      writeBit(6, 1);
      writeBit(7, 0);
      writeBit(8, 1);
      writeBit(9, 0);

      int addr = 0;
      EEPROM.put(addr, data);
      for (char i=0;i<10;i++){
        Serial.print(readBit(i));
      }
      delay(60000);
     
    }
     
  13. Unixon

    Unixon Оракул Модератор

    Код (C++):

    uint8_t packByte(bool b7, bool b6, bool b5, bool b4, bool b3, bool b2, bool b1, bool b0)
    {
      return ((b7&1)<<7) | ((b6&1)<<6) | ((b5&1)<<5) | ((b4&1)<<4) | ((b3&1)<<3) | ((b2&1)<<2) | ((b1&1)<<1) | (b0&1);
    }

    EEPROM.put(addr+0, packByte(0,1,0,1,0,1,1,0));
    EEPROM.put(addr+1, packByte(0,0,0,0,0,0,0,1));
     
     
  14. Unixon

    Unixon Оракул Модератор

    Если заполняете константами, пишите сразу
    Код (C++):

    EEPROM.put(addr+0, B01010110);
    EEPROM.put(addr+1, B00000001);
     
     
  15. postal2201

    postal2201 Нерд

    Unixon, Спасибо! Ни разу не слышал о packByte
     
  16. rkit

    rkit Гуру

    Ерундой не надо страдать.
    0b01010110
     
  17. Unixon

    Unixon Оракул Модератор

    Конечно, ведь я ее только что написал. :D
     
  18. postal2201

    postal2201 Нерд

    Биты только почему-то пишутся зеркально.
     
  19. Unixon

    Unixon Оракул Модератор

    LSB_FIRST, не? Или вы про параметры функции? Сначала написал с 0 до 7, как в памяти, потом развернул, чтобы было в одном порядке с константами.
     
  20. postal2201

    postal2201 Нерд

    Добрый день! С записью и чтением в EEPROM разобрался, спасибо Unixon за помощь :) Уже в готовом коде осталось решить 2 проблемы: В упор не вижу когда будут вызваться функции SECA() и SECI(). Ну и самая главная, как все это дело впихнуть в 1кб памяти. Для начала заменю все pinMode и digitalWrite на прямое управление портами через регистры, но боюсь этого будет мало...
    Код (C++):
    //--------------------------------------------------
    //                  Pinouts!
    //--------------------------------------------------
    //FOR ARDUINO UNO (WITH ATMEGA328):
    // - Arduino pin 8  = data    = ATMega pin 14
    // - Arduino pin 9  = gate    = ATMega pin 15
    // - Arduino pin 10 = lid     = ATMega pin 16
    // - Arduino pin 11 = biosA18 = ATMega pin 17
    // - Arduino pin 12 = biosD2  = ATMega pin 18

    //FOR ATTINY25/45/85:
    // - Arduino pin 0 = data    = ATTiny pin 5
    // - Arduino pin 1 = gate    = ATTiny pin 6
    // - Arduino pin 2 = lid     = ATTiny pin 7
    // - Arduino pin 3 = biosA18 = ATTiny pin 2
    // - Arduino pin 4 = biosD2  = ATTiny pin 3

    //--------------------------------------------------
    //                    Includes!
    //--------------------------------------------------
    #include <EEPROM.h>


    //--------------------------------------------------
    //               Arduino selection!
    //--------------------------------------------------
    #define ARDUINO_UNO        //Make that "#define ARDUINO_UNO" if you want to compile for Arduino Uno instead of ATTiny25/45/85

    #ifdef ARDUINO_UNO
    //Pins
    int data = 8;         //The pin that outputs the SCEE SCEA SCEI string
    int gate = 9;         //The pin that outputs the SCEE SCEA SCEI string
    int lid = 10;         //The pin that gets connected to the internal CD lid signal; active high
    int biosA18 = 11;     //Only used in SCPH-102 PAL mode
    int biosD2 = 12;      //Only used in SCPH-102 PAL mode
    int delay_ntsc = 2350;
    int delay_between_bits = 4;
    int delay_between_injections = 74;
    #endif

    #ifdef ATTINY
    //Pins
    int data = 0;        //The pin that outputs the SCEE SCEA SCEI string
    int gate = 1;
    int lid = 2;         //The pin that gets connected to the internal CD lid signal; active high
    int biosA18 = 3;     //Only used in SCPH-102 PAL mode
    int biosD2 = 4;      //Only used in SCPH-102 PAL mode
    int delay_ntsc = 2400;
    int delay_between_bits = 4;
    int delay_between_injections = 68;
    #endif

    bool readBit(int index)
    {
      int byte_index = index >> 3;
      byte bits = EEPROM.read(byte_index);
      int bit_index = index & 0x7; // same as (index - byte_index<<3) or (index%8)
      byte mask = 1 << bit_index;
      return (0 != (bits & mask));
    }

    void NTSC_fix()
    {
      //Make sure all pins are inputs
      DDRB = 0x00;
     
      //Wait until just before the pulse on BIOS A18 arrives
      delay(delay_ntsc);
     
      //...And wait here until it actually happened
      while(!(PINB & B00001000))
      {
        ;  //Wait
      }
      delayMicroseconds(12);
      PORTB = B00000000;
      DDRB = B00010000;
      delayMicroseconds(5);
      DDRB = 0x00;
    }

    void inject_SCEE()
    {
        for (unsigned char i = 0; i < 44; i++) {
        if (readBit(i) == 0)
        {  
         
          pinMode(data, OUTPUT);
          digitalWrite(data, 0);
          delay(delay_between_bits);
        }
        else
        {
         
          pinMode(data, INPUT);            
          delay(delay_between_bits);
        }
      }
     
      pinMode(data, OUTPUT);
      digitalWrite(data, 0);
      delay(delay_between_injections);
    }

    void inject_SCEA()
    {
      for (unsigned char i = 44; i < 89; i++) {
        if (readBit(i) == 0)
        {      
          Serial.println(0);
          pinMode(data, OUTPUT);
          digitalWrite(data, 0);
          delay(delay_between_bits);
        }
        else
        {
          Serial.println(1);
          pinMode(data, INPUT);            
          delay(delay_between_bits);
        }
      }
     
      pinMode(data, OUTPUT);
      digitalWrite(data, 0);
      delay(delay_between_injections);
    }

    void inject_SCEI()
    {
    for (unsigned char i = 89; i < 134; i++) {
        if (readBit(i) == 0)
        {      
          pinMode(data, OUTPUT);
          digitalWrite(data, 0);
          delay(delay_between_bits);
        }
        else
        {
          pinMode(data, INPUT);              
          delay(delay_between_bits);
        }
      }
     
      pinMode(data, OUTPUT);
      digitalWrite(data, 0);
      delay(delay_between_injections);
    }

    void inject_multiple_times(int number_of_injection_cycles)
    {
      int cycle_counter;
     
      for(cycle_counter = 0; cycle_counter < number_of_injection_cycles; cycle_counter = cycle_counter + 1)
      {
        inject_SCEE();
        inject_SCEA();
        inject_SCEI();
      }
    }

    void inject_playstation()
    {
      //Variables
      int loop_counter;
     
      //Code
    // NTSC_fix();
     
      delay(6900);
      digitalWrite(data, 0);
      pinMode(data, OUTPUT);
      delay(100);
      pinMode(gate, OUTPUT);
      digitalWrite(gate, 0);
     
      for (loop_counter = 0; loop_counter < 25; loop_counter = loop_counter + 1)
      {
        inject_SCEE();
      }
     
      pinMode(gate, INPUT);
      pinMode(data, INPUT);
      delay(11000);
     
      pinMode(gate, OUTPUT);
      digitalWrite(gate, 0);
     
      for (loop_counter = 0; loop_counter < 60; loop_counter = loop_counter + 1)
      {
        inject_SCEE();
      }
     
      pinMode(gate, INPUT);
      pinMode(data, INPUT);
    }


    void setup()
    {
       Serial.begin(9600); // инициализация послед. порта
      unsigned char addr = 0;
      EEPROM.update(addr + 0, 0b01011001);
      EEPROM.update(addr + 1, 0b11001001);
      EEPROM.update(addr + 2, 0b01001011);
      EEPROM.update(addr + 3, 0b01011101);
      EEPROM.update(addr + 4, 0b11101010);
      EEPROM.update(addr + 5, 0b00000010);
      EEPROM.update(addr + 6, 0b01011001);
      EEPROM.update(addr + 7, 0b11001001);
      EEPROM.update(addr + 8, 0b01001011);
      EEPROM.update(addr + 9, 0b01011101);
      EEPROM.update(addr + 10, 0b01011101);
      EEPROM.update(addr + 11, 0b00000010);
      EEPROM.update(addr + 12, 0b01011001);
      EEPROM.update(addr + 13, 0b11001001);
      EEPROM.update(addr + 14, 0b01001011);
      EEPROM.update(addr + 15, 0b01011101);
      EEPROM.update(addr + 16, 0b11011010);
      EEPROM.update(addr + 17, 0b00000010);
      inject_playstation();
    }

    //----------------------------------------------------------------
    //   Loop function - executes after the initial injection cycle
    //----------------------------------------------------------------
    void loop()
    {
    if(lid == 0)
      {
      while(lid != 1);      //Wait until the lid is closed again (after being opened) to initiate a new injection cycle
        inject_playstation();
      }
    }