Разделить число на 8 битные

74LS00
Offline
Зарегистрирован: 11.04.2016

Програмирование не моё, но лучшее обучение это практика. Появилась офигетельная идея, аналогов не нашлось, хотя фотки искал.

По статической индикации нашлась только эта статья https://forum.alaev.club/viewtopic.php?t=317

Из кода выкинул что смог.

У меня число в 13 бит 4 разряда.

Итого 6 микросхем и одна нога лишняя. Хотел зарезервировать ещё одну и поставить 7 регистров, но врятли они нужны.

Изначально массив был byte что 8 бит, я ничего лучше не нашёл как сделать из него unsigned int, ну и чтоб всё это упростить записал данные десятичными

const unsigned int digit[] = 
{  
4095, //0 
124,  //1
7135, //2  
5631, //3  
7741, //4  
7671, //5  
8183, //6  
127,  //7  
8191, //8  
7679, //9
};

Но на выводе у меня shiftOut который принимает 8 бит

pot = int(display);
      
          x4 = pot/1000;
          x3 = (pot/100)%10;
          x2 = (pot/10)%10;
          x1 = pot%10; 
     
          digitalWrite(latchPin, LOW);
     
          shiftOut(dataPin, clockPin, MSBFIRST, digit[x1]);
          shiftOut(dataPin, clockPin, MSBFIRST, digit[x2]);
          shiftOut(dataPin, clockPin, MSBFIRST, digit[x3]);
          shiftOut(dataPin, clockPin, MSBFIRST, digit[x4]);

          digitalWrite(latchPin, HIGH);

В общем получается последовательность 0+13x4бит которые надо както покрошить на 6 раз по 8 бит.

Полный код который лучше не смотреть.

int latchPin = 10;//сигнал Ready
int clockPin = 12;//сигнал Clock
int dataPin = 11;//cигнал Data

int x1;
int x2;
int x3;
int x4;

int pot;
     
float display = 1110; //величина, выводимая на индикатор = 4 цифры


//const byte digit[] =      //seven segment digits in bits
const unsigned int digit[] = 
{  
  
4095, // 00111111111111 //B00111111, //0 
124, //0000001111100 //1
7135, // 01101111011111 //2  
5631, //B01001111, //3  
7741, //B01100110, //4  
7671,//B01101101, //5  
8183,//B01111101, //6  
127, //B00000111, //7  
8191, //B01111111, //8  
7679, //B01101111  //9
};

// 010111 11011111 , 6111 01011111011111  //B01110110 6111 //H
//B00010000  //i
//B00111000  //L
//B01011100  //o

void setup(){

  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT); 
  pinMode(clockPin, OUTPUT);
}

void loop(){
  
          
          pot = int(display);
      
          x4 = pot/1000;
          x3 = (pot/100)%10;
          x2 = (pot/10)%10;
          x1 = pot%10; 
     
          digitalWrite(latchPin, LOW);
     
          shiftOut(dataPin, clockPin, MSBFIRST, digit[x1]);
          shiftOut(dataPin, clockPin, MSBFIRST, digit[x2]);
          shiftOut(dataPin, clockPin, MSBFIRST, digit[x3]);
          shiftOut(dataPin, clockPin, MSBFIRST, digit[x4]);

          digitalWrite(latchPin, HIGH);


  delay(1000);
  
}//конец цикла

 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Общая идея как это сделать - берем 1 число digit[1], применяем к нему & B11111111 - получаем 8 бит, сохраняем. Далее смещаем побитно 8 раз digit[1]>>8. берем digit[2]<<5 смещаем его на 5, складываем, опять оператор И. И т.д. 

74LS00
Offline
Зарегистрирован: 11.04.2016

Чтото сложно примудро, без примера не понять.

Вытащил кусок ардуины arduino-1.6.8\hardware\arduino\avr\cores\arduino\wiring_shift.c

void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
{
	uint8_t i;

	for (i = 0; i < 8; i++)  {
		if (bitOrder == LSBFIRST)
			digitalWrite(dataPin, !!(val & (1 << i)));
		else	
			digitalWrite(dataPin, !!(val & (1 << (7 - i))));
			
		digitalWrite(clockPin, HIGH);
		digitalWrite(clockPin, LOW);		
	}
}

Может както побитно сюда можно втолкнуть ?

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Уважаемый, да забудьте уже про пины - Вы работаете с числами! Во-первых 16 битное число лучше обозвать uint16_t digit[4]. Только у ВАс в примере их 9...

Берем первое число и вырезаем последние 8 бит - тут понятно?

Остается 5 бит (у Вас 13 же 13 бит?) на 8-13 позиции. Их надо перегнать на 0-4 позиции. Для этого есть оператор >>. Далее - у второго числа отрезаем 3 последних бита и смещаем их на 5-7 позиции оператором <<5. Складываем, вырезаем 8 бит. И вот второй байт готов.

uint16_t digit[4];
byte resultat[8];


resultat[0]=(byte) digit[0]&B11111111;
uint16_t temp=digit[0]>>8;
resultat[1]=(byte)((temp+(digit[1]&B111)<<5)&B11111111);

 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Тут подумалось - можно малость попроще.

Берем переменную uint64 chislo=0;

Далее chislo+=digit[0]; Смещаем на 13 бит chislo<<13; Добавляем следующее chislo+=digit[1]; Опять смещаем на 13 бит chislo<<13; и т.д.

В итоге получаем 64 битное число, которое потом режем по 8 бит.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Кидану кусочек программы 

uint64_t chislo=0;
uint8_t resultat[7];
for (byte i=0; i<4; i++){
chislo<<13;
chislo+=digit[i];
}
for (i=0;i<7;i++){
resultat[i]=(byte)chislo&B11111111
chislo>>8;
}

 

74LS00
Offline
Зарегистрирован: 11.04.2016

Пока что я понял это

chislo<<13; //не работает, нет сдвига

chislo = chislo<<13; //так работает

написано тут

В общем пришлось нанрисовать другой эмуль и приделать эмулятор терминала.

В какомто посту идею понял, но у вас там ошибок море, в этом направлении попробую сам

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

74LS00 пишет:

Пока что я понял это

chislo<<13; //не работает, нет сдвига

chislo = chislo<<13; //так работает

написано тут

В общем пришлось нанрисовать другой эмуль и приделать эмулятор терминала.

В какомто посту идею понял, но у вас там ошибок море, в этом направлении попробую сам

А может Вам еще водочки поднести? Мы это завсегда! А что читаете - это очень полезно.

А насчет моря ошибок - можно поподробнее? Или так - в лужу п-нули?

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

mykaida пишет:

Кидану кусочек программы 

uint64_t chislo=0;
uint8_t resultat[7];
for (byte i=0; i<4; i++){
chislo<<13;
chislo+=digit[i];
}
for (i=0;i<7;i++){
resultat[i]=(byte)chislo&B11111111
chislo>>8;
}

 

 

А насчет моря ошибок - можно поподробнее? Или так - в лужу п-нули?

Ну, на вскидку:

строка 8 забыли точку с запятой

Строки 4 и 9 синтаксически правильны, но бессмысленны, тк ничего не делают.

Дальше не смотрел. 

inspiritus
Offline
Зарегистрирован: 17.12.2012

Как нарубить флоат на байты? union

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

asam пишет:

Ну, на вскидку:

строка 8 забыли точку с запятой

Строки 4 и 9 синтаксически правильны, но бессмысленны, тк ничего не делают.

Дальше не смотрел. 

Вы чего думали - я его проверял??? 8-ю строку Вам компилятор указал. 4 и 9 - прочитали, молодец. Так и вставьте как поняли. А дальше ничего и нет- конец цикла. Вы кое-что поняли, теперь попытайтесь назад из resultat[] получить 4 13 битных числа. И поверьте,никто программы за Вас писать не будет. Максимум алгоритм подскажут.

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

mykaida пишет:

asam пишет:

Ну, на вскидку:

строка 8 забыли точку с запятой

Строки 4 и 9 синтаксически правильны, но бессмысленны, тк ничего не делают.

Дальше не смотрел. 

Вы чего думали - я его проверял??? 8-ю строку Вам компилятор указал. 4 и 9 - прочитали, молодец. Так и вставьте как поняли. А дальше ничего и нет- конец цикла. Вы кое-что поняли, теперь попытайтесь назад из resultat[] получить 4 13 битных числа. И поверьте,никто программы за Вас писать не будет. Максимум алгоритм подскажут.

 

Чукча не читалель, чукча писатель? Если читать внимательнее будет, то увидете, что лично мне ничего не надо. Вы захерачили код с ошибками, на замечание, что там ошибки сами же поросили

Цитата:
А насчет моря ошибок - можно поподробнее? Или так - в лужу п-нули?

А теперь пургу несете.  Слив засчитан.

anatoli_nik
Offline
Зарегистрирован: 17.01.2019

inspiritus пишет:

Как нарубить флоат на байты? union

Вот так (упрощенно, можно в цикле):

float chislo=1.25;		//переменная float
byte *ptr;				//указатель
byte chislo_na_byte[4];	//здесь будет float chislo разбитым на байты
void setup()
{
ptr=(byte*)&chislo;	//нацеливаем указатель на адрес chislo
					//указатель явно на 1 байт, иначе
					//компилятор заматюкает
}
void loop()
{
chislo_na_byte[0]=*ptr++;	//младший байт
chislo_na_byte[1]=*ptr++;
chislo_na_byte[2]=*ptr++;
chislo_na_byte[3]=*ptr++;	//старший байт
}

Тоже самое с любыми типами переменных (на которые можно нацелить указатель), а также на масивы из этих типов. Естесственно подумав как лучьше.

anatoli_nik
Offline
Зарегистрирован: 17.01.2019

mykaida пишет:

Кидану кусочек программы 

uint64_t chislo=0;
uint8_t resultat[7];
for (byte i=0; i<4; i++){
chislo<<13;
chislo+=digit[i];
}
for (i=0;i<7;i++){
resultat[i]=(byte)chislo&B11111111
chislo>>8;
}

 

Модифицирую немного (можно?):


uint64_t chislo=0;
byte *ptr;
uint8_t resultat[7];
ptr=(byte*)chislo;
for (byte i=0; i<7; i++){
resultat[i]=*ptr++;
}

Не забываем что байти будут складываться в массив от младшего к старшему.

sadman41
Offline
Зарегистрирован: 19.10.2016

Наложите на свой uint64 union с bytes[8] безо всяких циклов.

74LS00
Offline
Зарегистрирован: 11.04.2016

Еслиб я видел что на выводе, но Serial.println не может выводить uint64_t, какойто костыль есть, но там тоже только последние 32 бита.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

sadman41 пишет:

Наложите на свой uint64 union с bytes[8] безо всяких циклов.

;)))) Ложить - неправильно, правильно класть! (с) "День выборов"

anatoli_nik
Offline
Зарегистрирован: 17.01.2019

sadman41 пишет:

Наложите на свой uint64 union с bytes[8] безо всяких циклов.

Даже если и "наложить"(в штаны) используя union, один фиг его нужно передавать как-то.

Цикл нужен для друго, например передачи через UART:

uint64_t chislo=0;
byte *ptr;

ptr=(byte*)chislo;
for (byte i=0; i<7; i++){
uart.send(*ptr++);
}

Это всего лишь пример. 

sadman41
Offline
Зарегистрирован: 19.10.2016

Ну, если Вам нужно что-то "например", то я тоже могу привести:

 uint64_t chislo=0xDEADBEEFFEED;
 Serial.write((uint8_t*) &chislo, sizeof(chislo));

 

74LS00
Offline
Зарегистрирован: 11.04.2016

Пока сделал так. 

Знаки

  8190, //0     1111111111110
  1984, //1     0011111000000
  8061, //2     1111101110101
  8177, //3     1111111110001
  6087, //4     1011111000111
  7671, //5     1110111110111
  7679, //6     1110111111111
  8128, //7     1111111000000
  8191, //8     1111111111111
  8183  //9     1111111110111

После того как определяется x

uint64_t chislo=0;

        chislo+=digit[x4]; // левый знак
        chislo = chislo<<13;

        chislo+=digit[x3];
        chislo = chislo<<13;

        chislo+=digit[x2]; 
        chislo = chislo<<13; 

        chislo+=digit[x1]; // правый знак
        chislo = chislo<<4; // 4 неиспользуемых порта

Сама запись в регистры

for (int i=0; i < 7; i++){
      shiftOut(dataPin, clockPin, LSBFIRST, lowByte(chislo));
      chislo = chislo>>8;
   }

Из за того что вывод 8 битный и создавать переменную для хранения старшего бита не хотелось, поменял их местами из 4321 8765 в более приемлемый 1234 5678, а именно заменил MSBFIRST на LSBFIRST.

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

Не уверен нужен ли мне вообще цикл for, или быстрее будет работать построчно, или компилятору пофиг, не думаю. В общем написал для примера.

Как тут и говорят, альтернативный вариант это побитно выводить сразу 13 бит побитно без переменной uint.

Ну а последовательность бит не красиво только 4 младшими битами которые надо дописывать, в конце последнего регистра они бы не мешали.

mykaida идею подал, но видимо я не програмист чтоб понять что там конкретно. По сравнению с autoit, функционал ардуины очень скромный.

---

В общем с разводкой тоже получилось не красиво из за сдвига в другую сторону, но при моей раскладке наверно там в любую сторону будет неудобно, так что наверно лепить перемычки. Как оказалось дорожек получается вовсе и не мало

74LS00
Offline
Зарегистрирован: 11.04.2016

Выкинул этот uint64 и получилось чтото такое

  for ( int n = 0; n < 13; n++)  {
    digitalWrite(dataPin, !!(digit[x1] & (1 << n)));
    digitalWrite(clockPin, HIGH);
    digitalWrite(clockPin, LOW);    
  }
     
  for ( int n = 0; n < 13; n++)  {
    digitalWrite(dataPin, !!(digit[x2] & (1 << n)));
    digitalWrite(clockPin, HIGH);
    digitalWrite(clockPin, LOW);    
  }

  for ( int n = 0; n < 13; n++)  {
    digitalWrite(dataPin, !!(digit[x3] & (1 << n)));
    digitalWrite(clockPin, HIGH);
    digitalWrite(clockPin, LOW);    
  }

  for ( int n = 0; n < 13; n++)  {
    digitalWrite(dataPin, !!(digit[x4] & (1 << n)));
    digitalWrite(clockPin, HIGH);
    digitalWrite(clockPin, LOW);    
  }

Вообще не понимаю как имея переменную  i вызвать  digit[x4] где цифра будет переменной

sadman41
Offline
Зарегистрирован: 19.10.2016

x[3] = pot/1000;
x[2] = (pot/100)%10;
x[1] = (pot/10)%10;
x[0] = pot%10; 

for (uint8_t = 0; i < 4; i++) {

  Serial.println(x[i]);

}
74LS00
Offline
Зарегистрирован: 11.04.2016

В общем получилось такое

    digitalWrite(latchPin, LOW);
for (int i=0; i < 4; i++){
  for ( int n = 0; n < 13; n++)  {
    digitalWrite(dataPin, !!(digit[x[i]] & (1 << n)));
      digitalWrite(clockPin, HIGH);
      digitalWrite(clockPin, LOW);
  }
}
    digitalWrite(latchPin, HIGH);

Теперь вот думаю пустить это в другую сторону и переделать ноги портов, а то чтото неудобно выходит.

---

Как оказалось достаточно физически расположить разряды в обратном порядке, пока 2 регистра легли хорошо. К коде поменять только порядок x[0]-x[3]