Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить

Re: Хитрые, необычные алгоритмы и код

Вс авг 09, 2015 15:21:57

честно говоря, вы тут слишком много понаписали и все запутали.

1 измерение АЦП это максимум 1023. 100 измерений в секунду за час дадут сумму максимум 1023*60*60*100=368280000 это unsigned long. эта переменная сможет накапливать ваши измерения в течение 11 часов максимум, потом переполнится.

нет никакой проблемы суммировать и сравнивать unsigned long для 8-битного МК.

Re: Хитрые, необычные алгоритмы и код

Пн авг 10, 2015 05:03:36

ARV писал(а):честно говоря, вы тут слишком много понаписали и все запутали.

возможно я виноват - признаюсь
попытаюсь еще раз объяснить
цифра которая видна на экране состоит из 2 переменных.
значение до запятой это 1-я переменная типа int - будет цифра на пределе инта = 65535
значение после запятой это 2-ая переменная типа char - будет цифра от 0 до 99
также в бэкграунде будет 3-ая переменная в которую будут суммироваться значения АЦП, значение этой переменной после каждого сложения с значением АЦП будет сравниваться с константой 360 000. Если значение 3-ей переменой перевалит за 360 000 тогда из нее вычитается 360 000, а 2-ая переменная инкрементируется.
Когда вторая переменная достигнет 100 она обнуляется, а первая переменная инкрементируется.

Вопрос был как лучше оптимизировать все потому что из-за большой константы 360 000 вынужден третью переменную сделать типа long. А это 100 раз в секунду работать с такой огромной переменной это нагрузка на MK который имеет еще кучу задач.

И понимаю чтоб уменьшить константу надо увеличить вторую переменную до уровня int и сделать ее в 10 раз больше то есть будут миллиамперы час. Таким образом константа сравнения будет в 10 раз меньше и смогу уместить 3-ю переменную в размер int.

А вторую переменную перед показом на экран буду делить на 10.

Re: Хитрые, необычные алгоритмы и код

Пн авг 10, 2015 07:00:31

amd9800 писал(а):с такой огромной переменной это нагрузка на MK
Госпадяяяя... какая же это нагрузка - сравнение, вычитание, сложение, ... ? Тем более с константами :facepalm:
Делайте long и не парьтесь...

PS: Вы делаете проблему буквально из ничего. Что в этой теме, что в других. Вы, для начала, сделайте, а потом когда проблема появится - будете уже её решать.

Re: Хитрые, необычные алгоритмы и код

Пн авг 10, 2015 08:57:41

Немного отвлеку вас от текущего обсуждения...

В теме http://radiokot.ru/forum/viewtopic.php?f=61&t=119254 был поднят вопрос об инверсии порядка следования битов в слове на обратное (реверсия слова). Мне посоветовали продублировать ответ в этой теме, что я и делаю.

Первое, что приходит на ум, это реализовать такую функции с помощью цикла с побитовым просмотром исходного слова, однако в
книге Генри Уоррена "Алгоритмические трюки для программистов" можно найти вариант этой операции без использования цикла.
Для реверсии байта функция будет выглядеть следующим образом:

uint8_t ReverseByte(uint8_t b)
{
uint8_t ret;

ret = ((b & 0x55)<<1) | ((b & 0xAA)>>1);
ret = ((ret & 0x33)<<2) | ((ret & 0xCC)>>2);
ret = ((ret & 0x0F)<<4) | ((ret & 0xF0)>>4);

return ret;
}

Re: Хитрые, необычные алгоритмы и код

Пн авг 10, 2015 11:32:58

amd9800 писал(а):цифра которая видна на экране состоит из 2 переменных.
значение до запятой это 1-я переменная типа int - будет цифра на пределе инта = 65535
значение после запятой это 2-ая переменная типа char - будет цифра от 0 до 99
также в бэкграунде будет 3-ая переменная в которую будут суммироваться значения АЦП...
По мне, гораздо проще объявить 1 переменную ΣCODE как 32 разрядную и результат получать по выражению 100*RES=ΣCODE/K, где
100 - число измерений в единицу времени
K - коэффициент преобразования.
Децимальную точку принудительно ставить после единиц. Например K=130, т.е. 1A соответствует значение 130 единиц АЦП и входном токе 7.86А в сумматоре ΣCODE должно накопиться
7.86*130*100=102180 и 100*RES=ΣCODE/K=102180/130=786
Можно избавиться от операции деления на константу, заменив её умножением. В данном случае разрядность ΣCODE не изменится.

Re: Хитрые, необычные алгоритмы и код

Пн авг 10, 2015 21:20:30

akl писал(а):...

я признателен за попытку помочь, но мне кажется что вы запутались и не заметили что перепутали ампер*часы с амперами.
Поэтому ваши расчеты получились не правильными.
Также у вас в расчетах появилось деление, наверное на фоне деления - long уже точно не проблема.
Я хочу разгрузить МК более оптимизированным кодом, а не загрузить дополнительно.

Все таки оптимизировал экономия скомпилированной программы примерно 40 байт.
Вместо 3 переменной unsigned long.
Будет 3 переменная unsigned int
и 4 переменная unsigned char.

Код:
Ah       - первая    (unsigned int)
cAh      - вторая    (unsigned char)
tempAh   - третья    (unsigned int)
tempAhz  - четвертая (unsigned char)

Код:
 tempAh=tempAh+Amp;
      if (tempAh>35999)
         {
         tempAh=tempAh-36000;
         tempAhz++;
         if (tempAhz>9)
          {
          tempAhz=0;
          cAh++;
          if (cAh>99)
             {
             cAh=0;
             Ah++;
             }
          }   
         }

Re: Хитрые, необычные алгоритмы и код

Сб авг 15, 2015 05:08:08

Const14 писал(а):Немного отвлеку вас от текущего обсуждения...

В теме http://radiokot.ru/forum/viewtopic.php?f=61&t=119254 был поднят вопрос об инверсии порядка следования битов в слове на обратное (реверсия слова). Мне посоветовали продублировать ответ в этой теме, что я и делаю.

Первое, что приходит на ум, это реализовать такую функции с помощью цикла с побитовым просмотром исходного слова, однако в
книге Генри Уоррена "Алгоритмические трюки для программистов" можно найти вариант этой операции без использования цикла.
Да, на Си оно выглядит довольно красиво. Однако, как мне кажется, реализация этого дела займет гораздо больше 16 машинных команд того же АВР. Тогда, как банальное повторение 8 раз пары команд rol r0 ror r1 легко и непринужденно вывернет наизнанку содержимое R0 и поместит его в R1. Про 8051 не скажу, не знаю я его, но, даже если у него есть сдвиги на заданное число разрядов, а не на один, все равно все это довольно сложно, в отличие от

Re: Хитрые, необычные алгоритмы и код

Сб сен 05, 2015 20:22:04

Вот так можно менять значения установки часов для серии DS1307 - DS3232M, не прибегая к таблицам, и BCD->HEX->BCD
В rab первое значение, все остальное в rab1 , кроме 0

Код:
;**************************************************
;*               ;;/PLUS DATA;;*                *
;**************************************************
Clock_Plus:
      push   temp
      ld      temp,X            ;| Получаем значение
      add      temp,rab         ;| Прибавляем константу для счёта в BCD
      subi   temp,-1            ;| Прибавляем единицу
      brhc   Plus_Chng         ;| Проверяем переход с F->0 (перенос)
SAVE_PLUS:
      sub      temp,rab         ;| Вычитаем константу и получаем упакованный BCD
      cpse   temp,rab1         ;| Сравниаем с максимально допустимым
      rjmp   END_PLUS         ;|для этого значения часов
      sbrc   Flags1,fl_Chng_Way   ;+ проверяем флаг направления
      ldi      temp,1            ;|Если флаг установлен загружаем (1-день,число,месяц)
      sbrs   Flags1,fl_Chng_Way   ;+ проверяем флаг направления
      clr      temp            ;|Если флаг сброшен загружаем (0-час,минута,год)
END_PLUS:
      st      X,temp            ;| и возвращаем на место
      rcall   OUT_Clock_LCD      ;/ Выводим на LCD новое значение
      pop      temp
      ret
Plus_Chng:
      subi   temp,-6            ;|Если в младшей тетраде 0 прибавляем 6)
      rjmp   SAVE_PLUS
;**************************************************
;*               ;;/MINUS DATA;;*                *
;**************************************************
Clock_Minus:
      push   temp
      ld      temp,X            ;| Получаем значение
      cpse   temp,zero         ;| Проеряем на 0-час,минута,год
      rjmp   PC+2
MOVE_MINUS:
      mov      temp,rab1         ;| Равны , копируем в temp максимально допустимый предел
      add      temp,rab         ;| Прибавляем константу для счёта в BCD
      subi   temp,1            ;| Вычитаем единицу
      sub      temp,rab         ;| Вычитаем константу и получаем упакованный BCD
      brhs   Minus_Chng         ;| Проверяем переход с 0->F (заём)
      cpse   temp,zero         ;| Проверяем на 0-день,число,месяц
      rjmp   END_MINUS
      sbrc   Flags1,fl_Chng_Way   ;+ проверяем флаг направления
;| Если при устан. флаге temp=0, меняем значение на максимально возможное и снова на математику
      rjmp   MOVE_MINUS
END_MINUS:
      st      X,temp
      rcall   OUT_Clock_LCD      ;/ Выводим на LCD новое значение
      pop      temp
      ret
Minus_Chng:
      subi   temp,6            ;| Куда же без числа 6
      rjmp   END_MINUS

Setting_Clock: .db 0x66,0x24,0x60,8,0x32,0x13,0xA0,00

Re: Хитрые, необычные алгоритмы и код

Сб сен 05, 2015 23:41:46

Раз уж зашла речь о часах, во многих процессорах предусмотрены операции для BCD арифметики, что позволяет упростить код. Например, вот так можно увеличивать значения часов H (переменная определённая в RAM) на 1 по модулю 24 в архитектуре 8051 (уменьшение пишется аналогично). Собственно, хитрости в кодах ниже нет - скорее стандартная практика.
Код:
      mov   A, H             ; load H into ACC
      add   A, #1            ; increment the value
      da    A                ; decimal adjust to BCD
      cjne  A, #0x24, cont   ; is maximum reached?
      clr   A                ; YES - reset A to 0
cont: mov   H, A             ; save updated value

Oчень похоже это выглядит в HCS08 и подобных:
Код:
      lda   H           ; load H into ACC
      add   #1          ; increment the value
      daa   A           ; decimal adjust to BCD
      cbeqa #0x24, rest ; is maximum reached?
      bra   cont        ; NO  - continue
rest: clra              ;   YES - reset A to 0
cont: sta   H           ; save updated value

У MSP430 можно все сделать прямо в памяти, и, конечно, в регистрах:
Код:
      clrc             ; reset C flag
      dadd.b #1, &H    ; increment H in BCD
      cmp.b  #0x24, &H ; is maximum reached?
      jne    cont      ;   NO  - continue
      clr.b  &H        ;   YES - reset H to 0
cont:   

Ну и для Кортексов M3/M4. У них нет команд для работы с BCD, но многие операции могут выполняться условно.
Код:
      ldr    R1, =H        ; R1 = address of H
      ldrb   R0, [R1]      ; R0 = hours
      add    R0, #1        ; increment the value in R0 mod 24
      tst    R0, #0x0A     ; need decimal adjust?
      addne  R0, #6        ;   YES - do it
      cmp    R0, #0x24     ; is maximum reached?
      moveq  R0, #0        ;   YES - reset R0 to 0
      strb   R0, [R1]      ; save result in RAM

Re: Хитрые, необычные алгоритмы и код

Вс сен 06, 2015 06:36:16

Ser60
Возможно есть смысл (как ранее предлагалось и в этой теме) открыть отдельный раздел, где выкладывать типовые алгоритмы без привязки к конкретной системе команд конкретного МК - в виде пошаговых текстовых описаний (подобия ранних схем алгоритмов начала эры МК/ПК).
А доводку такого шаблона пользователь сможет выполнить самостоятельно уже в привязке к собственному проекту (модель памяти и ресурсов в конкретной задаче с конкретным МК)..?
:roll:
Весьма неплохая "копилка шаблон-алгоритмов" получиться может, особо если отредактировать в "дружественно-конструктивном" режиме базовые правила описания алгоритмов.
:beer:

Re: Хитрые, необычные алгоритмы и код

Вс сен 06, 2015 07:08:48

Неплохая идея. Думаю, будет полезно начинающим и не только. Но мне заниматься ведением этой темы некогда. Если возьмётесь, будет замечательно. Помимо описания алгоритмов может стоит будет привести наброски примеров их реализации под популярные архитектуры. В этом случае мой предыдущий пост будет уместно перенести туда.

Re: Хитрые, необычные алгоритмы и код

Пн сен 07, 2015 09:28:00

Не знаю, в чём затык с часами. Я сделал поразрядную установку с проверкой (отдельно время, отдельно дата):
десятки дней (0...3), единицы дней (0...9), десятки месяцев (0 или 1), ед. мес (0...9), года (0...99 поразрядно);
Десятки часов (0...2), ед.ч. (0...9), дес. мин. (0...5), ед. мин. (0...9).

Re: Хитрые, необычные алгоритмы и код

Вс окт 11, 2015 21:09:01

Const14 писал(а):Немного отвлеку вас от текущего обсуждения...

В теме http://radiokot.ru/forum/viewtopic.php?f=61&t=119254 был поднят вопрос об инверсии порядка следования битов в слове на обратное (реверсия слова). Мне посоветовали продублировать ответ в этой теме, что я и делаю.

Первое, что приходит на ум, это реализовать такую функции с помощью цикла с побитовым просмотром исходного слова, однако в
книге Генри Уоррена "Алгоритмические трюки для программистов" можно найти вариант этой операции без использования цикла.
Для реверсии байта функция будет выглядеть следующим образом:
Код:
uint8_t ReverseByte(uint8_t b)
{
uint8_t ret;

ret = ((b & 0x55)<<1) | ((b & 0xAA)>>1);
ret = ((ret & 0x33)<<2) | ((ret & 0xCC)>>2);
ret = ((ret & 0x0F)<<4) | ((ret & 0xF0)>>4);

return ret;



А где сдвиг третьего бита?! А ну понятно, он как-то сам хитро сдвигается. Код скорее головоломка забавная. Нагляднее в цикле написать или по простому

Код:
ret = (b<<8)
ret = ret | ((b & 10b)<<6)
ret = ret | ((b & 100b)<<4)
...


Хоть в отладчике можно посмотреть что делается, а не каша из бит, но быстрее работает понятно, может на 20% :)

Re: Хитрые, необычные алгоритмы и код

Пт дек 25, 2015 17:09:47

А вот как это всё выглядит на Cortex M3 и выше...

ret = __REV(__RBIT(b));

Две команды МК... и только...

Re: Хитрые, необычные алгоритмы и код

Пн дек 28, 2015 22:32:45

А вот есть такой код , не упрощал , ну и если очень приспичит , как мне, то можно пользовать
Код:
   add      R18,temp
   adc      R18,R21
   brhc   yy
   subi   R18,0x10
   sec
xx:
   adc      R19,temp1
   adc      R19,r21
   brhc   YYY
   subi   R19,0x10
   sec
xxx:
   adc      R20,XL
   rjmp   xxxx

yy:
   subi   r18,6
   rjmp   XX
YYY:
   subi   r19,6
   rjmp   XXX

Re: Хитрые, необычные алгоритмы и код

Чт сен 15, 2016 23:38:20

Вариант программной "безджиттерной" генерации интервалов на основе векторно - условных переходов.
Как частный случай - генерация пакета для ленты WS2812 c фазовой манипуляцией:
viewtopic.php?p=2858887#p2858887
В принципе позволяет стабилизировать период с точностью до одного командного цикла.
Альтернатива накапливаемой ошибке при применении стандартных команд перехода по условию, для которых существует правило разного времени исполнения в случаях истина или ложь.
Конструкция конечно более громоздкая по количеству команд, зато время выполнения весьма равномерно распределено.
:roll:

Re: Хитрые, необычные алгоритмы и код

Ср окт 12, 2016 09:12:39

Уж не знаю, насколько это хитро, но давно использую для математических вычислений на МК следующее свойство:
1. Если сдвинуть двоичное число на один разряд влево, то это равносильно умножению на два. Это общеизвестно.
2. Если сдвинуть двоичное число на один разряд вправо, то это равносильно делению на два. Это тоже общеизвестно.
3. Если сдвигать двоичное число на один разряд вправо столько раз, сколько нужно, чтобы результат стал равен единице, то это количество раз будет логарифмом по основанию 2 от нашего числа. А про это забывают.

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

Re: Хитрые, необычные алгоритмы и код

Сб фев 16, 2019 15:32:24

Может уже было? Исключительно для собственных протоколов передачи данных.
Многим известно что для защиты целостности передачи данных используется контрольная сумма. В общем случае используют известные методы CRC8,CRC16,CRC32 с разными полиномами. В некоторых контроллерах есть уже встроенные блоки подсчета CRC, но часто нужно самому софтово ее считать. И мне тоже понадобилось.
Физический смысл CRC - циклическая сумма остатков от деления байта (слова) на известный полином (8,16,32 бит). Википедия все красиво описывает. Когда-то я при передаче пакетов USART по воздуху так и писал
crc = (crc+data)%POLINOM;
и в конце пакета добавлял в передачу CRC.
Сам расчет контрольной суммы занимает определенное время, особенно деление. Для ускорения процесса используют таблицы с частным для нужного полинома. Я сейчас использую STM32. Там тоже тратится время на деление, но вот умножение делается за один такт!
Пришла идея заменить деление умножением с отбрасыванием "целой" части и приведением результата к нужному типу данных.
Получилась такая строка для CRC8:
crc = (uint8_t)(0xff & (((uint8_t)(0xff & (crc+data)))*POL));
где POL полином контрольной суммы,задается в дефайнах, у меня 0х31.
Все это компилируется в 5 ассемблерных команд и выполняется примерно за 8 тактов.
Передача проходит четко.
Вот так выглядит обработчик прерывания USART для захвата пакета в 80 байт с преамбулой
void USART1_IRQHandler (void)
{
if (USART1->ISR & USART_ISR_RXNE) data = USART1->RDR;
if (rf_stat == 2)
{
rx_buf[r_ptr] = data;r_ptr++;
if(r_ptr > 80)
{
if (crc == rx_buf[80]) rx_buf_rdy = 1; else rx_buf_rdy = 0;
crc = 0,r_ptr = 0,rf_stat = 0;
} else crc = (uint8_t)(0xff & (((uint8_t)(0xff & (crc+data)))*POL));
} else
if ((rf_stat == 1) && (data == 0xD4)) rf_stat++; else
if ((rf_stat == 0) && (data == 0x2D)) rf_stat++;
};

0x2D и 0xD4 старт пакета,rx_buf_rdy-флаг готовности,rf_stat - статус разбора пакета.
Естественно от устройства с формированием CRC таким-же способом.

Re: Хитрые, необычные алгоритмы и код

Вт фев 26, 2019 07:02:59

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

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

Re: Хитрые, необычные алгоритмы и код

Вт фев 26, 2019 11:43:48

Может уже было? Исключительно для собственных протоколов передачи данных.
Многим известно что для защиты целостности передачи данных используется контрольная сумма. В общем случае используют известные методы CRC8,CRC16,CRC32 с разными полиномами. В некоторых контроллерах есть уже встроенные блоки подсчета CRC, но часто нужно самому софтово ее считать. И мне тоже понадобилось.


Еще проще просто сумма, качество обнаружения ошибки падает, но не критично, я проверял, зато какая простота
https://habr.com/ru/post/278171/

CRC полноценная кстати не намного дольше считается. Там деление вырождается в 8 операций смещения бита вправо и 8 опраций XOR.
Как я понимаю смотрим младший бит, если он 1 то делаем XOR с полиномом. Потом смотрим предпоследний бит, и если он 1 то делаем XOR с полиномом.
https://ru.wikipedia.org/wiki/%D0%A6%D0 ... 0%BE%D0%B4

Изображение

Вот если бы считали 16 или 32 бит контрольную сумму, тут выигрыш был бы значительным.

И проверки алгоритма у вас нет, нужно собрать статистику, имитируая передачу миллиона сбойных пакетов, с 1,2,3..10 сбойными битами. Может полином быть выбран неудачно.
Ответить