int16 получить битовую маску значений

kristow
kristow аватар
Offline
Зарегистрирован: 08.08.2013

Всем привет!

Использую библиотеку Modbus RTU. Опрашиваю прибор МВ 110. Там 16 входов. Сосчитать их состояние можно одной командой. В ответ получаю значения int16.

Вот так я получаю почти то что мне нужно:

char A[17];
itoa(regs[0],A,2);

т.е. при замыкании контактов 2 и 6, я получаю ответ в виде A = 100010 

Вот так только 8 контакт: 10000000

Всего 16 входов. Я хочу в print посылать значения, приведенные к нормальным, в виде: 

A = 10100010
K1 = 0
K2 = 1
K3 = 0
K4 = 0
K5 = 0
K6 = 1
K7 = 0
K8 = 1
K9 = 0
K10 = 0
K11 = 0
K12 = 0
K13 = 0
K14 = 0
K15 = 0
K16 = 0

Опытным путем сделал вот так, но все равно не совсем как надо:

void loop()
{
  modbus_update();
  mySerial.print(" regs0: ");
  char A[17];
  itoa(regs[0],A,2); 
  mySerial.print(A);
  for (byte i = 0; i < 16; i++){
    mySerial.print(" K");
    int i2 = 16-i;
    mySerial.print(i2);
    mySerial.print(": ");
    mySerial.print(A[i]);
  }
  mySerial.println();
}

При работе кода что выше я получаю строку при замкнутом 7 контакте. regs0 = показывает что замкнут только 7 контакт, а как добавить недостающие нули? чтобы мой код правильно начал работать?

 regs0: 1000000 K16: 1 K15: 0 K14: 0 K13: 0 K12: 0 K11: 0 K10: 0 K9:  K8: 0 K7:  K6:  K5:  K4:  K3:  K2:  K1:
qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Ответ банальный. Не пользоваться функцией itoa. 

kristow
kristow аватар
Offline
Зарегистрирован: 08.08.2013

qwone пишет:

Ответ банальный. Не пользоваться функцией itoa. 

Подскажите как правильно написать?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Скорее всего подобно этому.

bytes[0]=(number&0x000000FF); 
bytes[1]=(number&0x0000FF00)>>8; 
bytes[2]=(number&0x00FF0000)>>16; 
bytes[3]=(number&0xFF000000)>>24;

Но скорее в цикле A[i]=(regs[0] & (1<<i))>> i где i от 0 до 16, а regs[0] ваше число которое надо преобразовывать.

ПС: надо проверять.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Вы про битовые операции знаете? Вот их и надо использовать, как-то так, навскидку:

// файл Templates.h
#ifndef _TEMPLATES_H
#define _TEMPLATES_H

#include <Arduino.h>

template<class T>
void print_bits(T val)
{
   for(byte i=0;i<sizeof(val)*CHAR_BIT;i++)
   {
    if(val & (1 << i))
      Serial.print("1");
    else
      Serial.print("0");
   }
   Serial.println();
}

#endif

Сам скетч:

#include "Templates.h"

void setup() 
{
}

void loop() 
{

  byte bVal = 123;
  print_bits<byte>(bVal);

  int iVal = 12345;
  print_bits<int>(iVal);
  

}

Тупо быстро набросал, мог где-то ошибиться, на ардуину закачивать не стал - все свободные щас заняты :(

kristow
kristow аватар
Offline
Зарегистрирован: 08.08.2013

Что-то не один из вариантов не работает :(

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

kristow пишет:

Что-то не один из вариантов не работает :(

Сорри, я там обшибся, щас поправлю. Вот поправленный:

#ifndef _TEMPLATES_H
#define _TEMPLATES_H

#include <Arduino.h>
#include <limits.h>

template<class T>
void print_bits(T val)
{
   for(byte i=0;i<sizeof(val)*CHAR_BIT;i++)
   {
    if(val & (1 << i))
      Serial.print("1");
    else
      Serial.print("0");
   }
   Serial.println();
}

#endif

Поправил и сверху, на всякий. Совсем забыл про CHAR_BIT, голова садовая.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Проверил на http://cpp.sh/, вот код, на котором проверял всё работает как надо:

// Example program
#include <iostream>
#include <string>
#include <limits.h>

template<class T>
void print_bits(T val)
{
   for(uint8_t i=0;i<sizeof(val)*CHAR_BIT;i++)
   {
    if(val & (1 << i))
      std::cout << "1";
    else
      std::cout << "0";
   }
   std::cout << std::endl;
}

int main()
{
  uint8_t bVal = 123;
  print_bits<uint8_t>(bVal);

  int16_t iVal = 12345;
  print_bits<int16_t>(iVal);
}

Только определиться с big endian и little endian надо. Если надо в обратном порядке биты выводить, то:

// Example program
#include <iostream>
#include <string>
#include <limits.h>

template<class T>
void print_bits(T val)
{
   for(int8_t i=sizeof(val)*CHAR_BIT-1;i>=0;--i)
   {
    if(val & (1 << i))
      std::cout << "1";
    else
      std::cout << "0";
   }
   std::cout << std::endl;
}

int main()
{
  uint8_t bVal = 123;
  print_bits<uint8_t>(bVal);

  int16_t iVal = 12345;
  print_bits<int16_t>(iVal);
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Если Вы будете нумеровать их не с 1, а, как все нормальные люди, с нуля (т.е. на 1, 2, ..., 16), а (0, 1, 2, ..., 15), то можете воспользоваться простым, рабоче-крестьянским макросом bitRead. Просто, как мычание нулевой бит переменной а - bitRead(a, 0), первый - bitRead(a,1) и т.п. И не надо городить никакого огорода с самогонными функциями. Макрос простой как валенок, определён в arduino.h вот так

#define bitRead(value, bit) (((value) >> (bit)) & 0x01)

 

kristow
kristow аватар
Offline
Зарегистрирован: 08.08.2013

Спасибо всем за помощь и советы :)

Очень помогли!