Я должен делать линейную интерполяцию со временем между двумя значениями на микроконтроллере PIC на 8 битов (Конкретно 16F627 А, но это не должно иметь значения), использование ассемблера PIC. Хотя я ищу алгоритм здесь так же как фактический код.
Я должен принять начальное значение на 8 битов, 8 битов, заканчивающих значение и положение между двумя (В настоящее время представленный, поскольку номер 0-255 на 8 битов, где 0 означает вывод, должен быть начальным значением и 255 средствами, это должно быть окончательное значение, но это может измениться, если существует лучший способ представить это), и вычисляют интерполированное значение.
Теперь PIC не имеет инструкции по делению, таким образом, я мог кодировать стандартную программу деления общего назначения, и effectivly вычисляют (B-A) / (x/255) +A на каждом шаге, но я чувствую, что существует, вероятно, намного лучший способ сделать это на микроконтроллере, чем способ, которым я сделал бы это на ПК в C++
Кто-либо получил какие-либо предложения для реализации этого эффективно на этих аппаратных средствах?
Значение, которое вы ищете, - (A * (255-x) + B * x) / 255
. Для этого требуется только умножение 8x8 и окончательное деление на 255, которое можно аппроксимировать, просто взяв старший байт суммы.
При выборе x в диапазоне 0..128 аппроксимация не требуется: возьмите старший байт (A * (128-x) + B * x) << 1
.
Это можно было сделать, используя арифметику с фиксированной точкой 8.8. Тогда число из диапазона 0..255 будет интерпретировано как 0,0 ... 0,996, и вы сможете его умножить и нормализовать.
Скажите, нужны ли вам дополнительные подробности или этого достаточно для начала.
Вместо этого вы можете охарактеризовать это как:
(B-A)*(256/(x+1))+A
используя диапазон значений x = 0..255, предварительно вычислить значения 256 / (x + 1 ) как число с фиксированной точкой в таблице, а затем закодируйте умножение общего назначения, скорректировав положение двоичной точки. Это может быть не мало в пространстве; Я ожидал, что вам понадобится таблица с 256 записями из 16-битных значений и код умножения. (Если вам не нужна скорость, это говорит о том, что ваш метод деления в порядке.). Но достаточно одного умножения и добавления.
Я предполагаю, что вам не нужны все возможные значения X. Если есть только несколько значений X, вы можете вычислить их в автономном режиме, выбрать регистр для конкретного значения X, а затем реализовать умножение с точки зрения фиксированной последовательности сдвигов и добавлений для определенного значения X. Это, вероятно, будет довольно эффективно в коде и очень быстро для PIC.
Предполагая, что вы интерполируете последовательность значений, в которой предыдущая конечная точка является новой начальной точкой:
(B-A)/(x/255)+A
звучит как плохая идея. Если вы используете базу 255 как представление с фиксированной точкой, вы получите один и тот же интерполянт дважды. Вы получаете B, когда x = 255, и B как новый A, когда x = 0.
Используйте 256 как систему с фиксированной точкой. Деление превращается в сдвиг, но вам потребуется 16-битная арифметика и умножение 8x8 с 16-битным результатом. Предыдущую проблему можно исправить, просто игнорируя любые биты в старших байтах, поскольку x mod 256
становится 0. В этом предложении используется 16-битное умножение, но невозможно переполнение. и вы не интерполируете по одному и тому же x дважды.
interp = (a*(256 - x) + b*x) >> 8
256 - x
становится просто вычитанием с заимствованием, так как вы получаете 0 - x
.
В наборе команд PIC отсутствуют следующие операции:
Вы можете получить сдвиг вправо, используя вместо этого rotate-right, с последующим маскированием лишних битов слева с помощью побитового и. Простой способ умножения 8x8 с 16-битным результатом:
void mul16(
unsigned char* hi, /* in: operand1, out: the most significant byte */
unsigned char* lo /* in: operand2, out: the least significant byte */
)
{
unsigned char a,b;
/* loop over the smallest value */
a = (*hi <= *lo) ? *hi : *lo;
b = (*hi <= *lo) ? *lo : *hi;
*hi = *lo = 0;
while(a){
*lo+=b;
if(*lo < b) /* unsigned overflow. Use the carry flag instead.*/
*hi++;
--a;
}
}
Учитывая два значения X и Y , в основном это:
(X + Y) / 2
или
X / 2 + Y / 2 (для предотвращения нечетного случая, когда A + B может переполнить размер регистра)
Следовательно, попробуйте следующее:
(Псевдо -code)
Initially A=MAX, B=MIN
Loop {
Right-Shift A by 1-bit.
Right-Shift B by 1-bit.
C = ADD the two results.
Check MSB of 8-bit interpolation value
if MSB=0, then B=C
if MSB=1, then A=C
Left-Shift 8-bit interpolation value
}Repeat until 8-bit interpolation value becomes zero.
Фактический код также прост. Только регистры и инструкции не помню вовсю.
Методы, описанные Эриком Бейнвиллом и Мэдсом Эльвхеймом, будут работать нормально; каждый использует два умножения на интерполяцию.
Скотт Даттало и Тони Кубек разработали сверхоптимизированный метод интерполяции, специфичный для PIC, под названием « твист », который немного быстрее, чем два умножения на интерполяцию.
Стоит ли использовать эту трудную для понимания технику немного быстрее?