Отправка пакета через ИК

Тема в разделе "Проводная и беспроводная связь", создана пользователем ser24alm, 4 авг 2014.

  1. ser24alm

    ser24alm Нерд

    Всем привет. Хочу сделать пульт для управления тагером в лазертаге, документацию по протоколу нашел(Miles tag 2)(http://www.lasertagparts.com/mtformat-2.htm)(отправка команд). Собственно вопрос. Как отправлять байты через ик?
    Например :
    [Header]-[0x83]-[0x00]-[0xE8]
     
  2. ser24alm

    ser24alm Нерд

    Всем привет. Хочу сделать пульт для управления тагером в лазертаге, документацию по протоколу нашел(Miles tag 2)(http://www.lasertagparts.com/mtformat-2.htm )(отправка команд). Собственно вопрос. Как отправлять байты через ик?
    Например :
    [Header]-[0x83]-[0x00]-[0xE8]
     
  3. acos

    acos Официальный гик Команда форума

    нужен модулятор (36 или 38 кГц.. или сколько там вам нужно - зависит от ИК-приёмника), который будет модулировать излучение светодиода, и ножка, которая будет управлять им (по вашему протоколу) Такое можно сделать на паре таймеров. Один таймер будет отвечать за модуляцию, второй - за сигналы. Можете попробовать сделать такое на двух библиотеках: Timer1 и Timer3 http://playground.arduino.cc/code/timer1
     
  4. acos

    acos Официальный гик Команда форума

    Вот мой скетч, который отправлял байтики через ИК но по Serial-порту. Одна нога быстро включает и выключает светодиод, производя манипуляцию, вторая нога формирует протокол

    Код (C):

    #include <TimerOne.h>

    #define MANIPULATE 5
    #define FREQ 36000
    #define MAN_FREQ (1000000.0/(FREQ*2)) // миллион микросекунд в секунде, должен быть float


    int transmitInterval = 25; // ИК-приёмник не любит много данных без пауз
    unsigned long time;

    void setup() {
      pinMode(MANIPULATE, OUTPUT);

      Timer1.initialize(MAN_FREQ); // 72000 Hz, 14 microseconds, 36 kHz*2
      Timer1.attachInterrupt( timerIsr ); // attach the service routine here

      Serial.begin(1200); // ИК приёмник быстро не умеет работать.
      time = millis();
    }

    void loop() {
      // put your main code here, to run repeatedly:

      if ((millis() - time) > transmitInterval)
      {

        Serial.write(100); // лень заморачиваться, пусть мы шлём цифру 100
        time = millis();
      }

    }

    void timerIsr()
    {
      //работаем быстро - напрямую с портами
      if ((PIND & _BV(5)) == _BV(5))
        PORTD &= ~_BV(5); //pin 5 LOW
      else
        PORTD |= _BV(5); //pin 5 HIGH
    }

     
     
    Последнее редактирование: 5 авг 2014
  5. ser24alm

    ser24alm Нерд

    А можно просто через digitalWrite и delay?
     
  6. ser24alm

    ser24alm Нерд

    И я немного не понял твой код
     
  7. geher

    geher Гуру

    Суть кода в следующем.
    Создается таймерное прерывание, функция которого задает тактовую частоту для ИК передатчика на 5-м пине.
    Данные на ИК передатчик посылаются через последовательный порт. Полагаю, что. ИК светодиод подключен к TX, земле и пятому пину с использованием транзистора для модуляции высокочастотным сигналом данных последовательного порта.
    Передаются данные побайтно с задержкой между передачей отдельных байт.
    Таймерное прерывание работает напрямую с регистрами пинов, вместо того, чтобы пользоваться более медленной функцией digitalWrite;
    PIND - все пины от 0 до 7, собранные в один регистр - вход.
    PORTD - все пины от 0 до 7, собранные в один регистр -выход.
    _BV(5) - единица, сдвинутая влево на 5.
    Соответственно при помощи битовой арифметики проверяется, взведен ли в общем регистре пинов бит, соответствующий пятому пину. В зависимости от его значения он изменяется на противоположное значение.
    Кстати, а
    PORTD ^= _BV(5);
    не проще?
     
    Последнее редактирование: 6 авг 2014
    acos нравится это.
  8. ser24alm

    ser24alm Нерд

    Код (Text):
    #include <TimerOne.h>

    #define MANIPULATE 5
    #define FREQ 36000
    #define MAN_FREQ (1000000.0/(FREQ*2)) // миллион микросекунд в секунде, должен быть float


    int transmitInterval = 25; // ИК-приёмник не любит много данных без пауз
    unsigned long time;

    void setup() {
      pinMode(MANIPULATE, OUTPUT);

      Timer1.initialize(MAN_FREQ); // 72000 Hz, 14 microseconds, 36 kHz*2
      Timer1.attachInterrupt( timerIsr ); // attach the service routine here

      Serial.begin(1200); // ИК приёмник быстро не умеет работать.
      time = millis();
    }

    void loop() {
      // put your main code here, to run repeatedly:

      if ((millis() - time) > transmitInterval)
      {

        Serial.write(100); // лень заморачиваться, пусть мы шлём цифру 100
        time = millis();
      }

    }

    void timerIsr()
    {
      //работаем быстро - напрямую с портами
      if ((PIND & _BV(5)) == _BV(5))
        PORTD &= ~_BV(5); //pin 5 LOW
      else
        PORTD |= _BV(5); //pin 5 HIGH
    }
    Тоесть
    Serial.write(Тут байт)
    int transmitInterval = Задержки между байтами?
     
  9. ser24alm

    ser24alm Нерд

    А если нужно отправлять по этой схеме, то код какой будет?
    [Header]-[0x83]-[0x00]-[0xE8]
     
  10. geher

    geher Гуру

    Конструкция
    Код (Text):
    if ((millis() - time) > transmitInterval)
      {

        Serial.write(100); // лень заморачиваться, пусть мы шлём цифру 100
        time = millis();
      }
     
    Должна быть заменена на что-то вроде
    Код (Text):

    int i=0;
    unsigned char pack[4]={HEADER,0x83,0x00,0xE8};
    while (i<4) {
    //выжидаем паузу между байтами, если предыдущий байт был отправлен недавно (остаток заданного минимального интервала)
      if ((millis() - time)< transmitInterval) delay(transmitInterval- (millis() - time));
    //шлем очередной байт пакета
      Serial.write(pack[i]);
      i++;
      time = millis();
    }
     
    Предполагаю, что HEADER - это константа, определяющая первый байт каждой посылки.
     
  11. ser24alm

    ser24alm Нерд

    HEader это импульс длиной 2400
     
  12. ser24alm

    ser24alm Нерд

    И может всместо while(i<4) нужно while(i<=4)?
     
  13. ser24alm

    ser24alm Нерд

    И какова будет схема подключения? Через резистор?
     
  14. geher

    geher Гуру

    В таких условиях, возможно, надо писать байт не через Serial.write, а более простой посылкой.
    Подозреваю, что такой стартовый импульс может нарушить работу протокола последовательного порта, поскольку не уверен насчет реализации последовательного порта на предмет буферизации и прочих плюшек (например, мы выдаем стартовый импульс, а оно еще из буфера что-то старое продолжает выдавать).
    Так что либо при использовании последовательного протокола следует отказаться от стартового импульса в пользу первого заголовочного байта с некоторым значением, не использующимся в посылке (или несколько таких байт), либо отказаться от последовательного протокола в пользу своей реализации, например, что-то вроде

    Код (Text):
    void sendByte(unsigned char b)
    {
        // передаем младшим битом вперед
        for (int i=0;i<8;i++)
        {
            digitalWrite(1,(b&1)?HIGH:LOW);
            b=b>>1;
           delay(10); //время передачи бита 10 мс
           digitalWrite(1,LOW);
        }
    }
    А перед началом передачи байт пакета выдать импульс
    Код (Text):
    //сброс линии перед импульсом
    digitalWrite(1,LOW);
    delay(10);
    //импульс
    digitalWrite(1,HIGH);
    delay(2400);
    digitalWrite(1,LOW);
    // начало минимального интервала между посылками
    time = millis();
     
     
  15. Megakoteyka

    Megakoteyka Оракул

    Тогда цикл отработает 5 раз.
    Цикл while(i<4) работает так:
    0 < 4 ? ДА
    1 < 4 ? ДА
    2 < 4 ? ДА
    3 < 4 ? ДА
    4 < 4 ? НЕТ, цикл завершился.
     
  16. geher

    geher Гуру

    Вот со схемой подключения не знаю. Это к acos.
    Я пока такими вещами не баловался, только теоретизирую.
     
  17. geher

    geher Гуру

    PS.
    Не обратил сразу внимание на информацию о том, что есть какой-то готовый протокол.
    Поскольку по ссылке имеем
    Page Not Found
    то остается только теоретизировать на предмет особенностей протокола.

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

    Например, у последовательного порта каждый байт = отдельная посылка.
    Посылка начинается со стартового бита (HIGH), дальше биты данных, может быть бит четности и стоповые биты (LOW). Передача младшим битом вперед, разрывов между битами нет.

    Как в вашем случае, надо смотреть реализацию протокола и под нее уже писать реализацию sendByte и задавать реальную длительность пауз между байтами (значение transmitInterval)
     
  18. acos

    acos Официальный гик Команда форума

    @geher http://www.lasertagparts.com/mtformat-2.htm - вот правильная ссылка)
    Я просто сделал пример для Serial (он был готовый - поэтому хотелось быстро объяснить суть), тут нужна немного другая петрушка. В данном случае Serial не при чём. Я бы взял тут второй таймер и на нём шлёпал бы выдержки времени этого протокола, а в коде можно было бы просто сделать send() и не заморачиваться. Хотя можно и без таймера, если больше ничего делать не нужно.

    Инфракрасный светодиод с резистором можно просто поставить между двух ножек микроконтроллера - TX и 5. Главное, чтобы он с резистором ел меньше 40 мА
    я брал вотэтот светодиод http://amperka.ru/product/ir-led и резистор на 220 Ом
    у него мин. падение 1,2 В,
    (5-1,2)/220=1.7 мА, так что тут все ок - можно напрямую между ногами ставить.
    Т.к. Serial работает выставляя на ноге ноль, нужно ориентировать светодиод катодом к TX. Для нужд топикстартера ориентация может быть любой - главное чтоб светодиод горел при передаче, а нулем это делать или единицей - вопрос реализации.

    PS
    Действительно проще, но тут нужно быть в теме битовых операций) Ай, вру - я просто тупо не был уверен раньше в том, что из PORT можно ещё и читать:) Да и в голову это не приходило. Спасибо за устранение пробела в знаниях)
     
    Последнее редактирование: 7 авг 2014
  19. ser24alm

    ser24alm Нерд

    Мне вообще просто нужно, чтобы по нажатии на кнопку выдавлася нужный мне импульс. Но в arduino я новичок( Можно протсо готовый код с коментрариями?))
     
  20. geher

    geher Гуру

    Ознакомился с протоколом.
    Несколько непонятно, в каких единицах измеряется задержка. Если в миллисекундах ("Header = (2.4 mS burst)"), то какой-то тормозной протокол получается, больше трех секунд на посылку - по моему перебор.
    Предположим, что это все-таки микросекунды.
    Тогда можно сделать примерно следующее (решение в лоб, без использования второго таймера, первый инициализируется как было предложено раньше):
    Код (Text):

    // описываем пакет, задавая байты данных (другие примерно так же)
    unsigned char pack[3]={0x83,0x00,0xE8};
    int packlen=3;
    ...
    SendPack(pack,packlen); //Где-то в коде посылаем наш пакет
    ...
    SendPack(unsigned char* pack, int pasklen) // функция посылки пакета
    {
       //сброс линии перед импульсом
       digitalWrite(1,LOW);
       delayMicroseconds(600);
       //импульс
       digitalWrite(1,HIGH);
       delayMicroseconds(2400);
       digitalWrite(1,LOW);
       delayMicroseconds(600)
       for (i=0;i<packlen;i++)
       {    
           unsigned char b=pack[i];
           for (int j=0;j<8;j++)
           {
              digitalWrite(1,HIGH);
              delayMicroseconds(b&1)?1200:600); //время передачи бита 1 -1200 мкс, 0 600 мкс
              b=b>>1;
              // Это сделано в предположении, что байт передается младшим битом вперед.
              // Поскольку из описания протокола не совсем ясно, как оно должно быть,
              // то в случае передачи старшим битом вперед две строки выше данного блока комментариев
              // надо заменить на две строки ниже, не забыв раскомментировать их
              // delayMicroseconds(b&0x80)?1200:600); //время передачи бита 1 -1200 мкс, 0 600 мкс
              // b=b<<1; // ставим старшим битом следующий          
              digitalWrite(1,LOW);
              delayMicroseconds(600); // пауза между битами
           }
       }
    }

     
     
    Последнее редактирование: 7 авг 2014