Страница 1 из 1
опрос кнопок MEGA8
Добавлено: Вт дек 09, 2014 23:12:00
neox
Здравствуйте! помогите плиз с кусочком кода на "С" (пишу в компиляторе CVAVR).
задача такова: восемь кнопок одной стороной сидят на массе а второй подключены к PORTD (PORTD настроен и включена подтяжка), как написать что если любые две из восьми кнопок выключены тогда PORTD.1=0 а если все восемь включены тогда PORTD.1=1 ?
Re: опрос кнопок MEGA8
Добавлено: Ср дек 10, 2014 05:15:03
Mishany
использовать оператор с условием if
заводим переменную для каждой кнопки удобнее использовать 1 байт для 8 кнопок где 1 нажата 0 отпущена, если сумма всех значений равна 2 то ....., если 8 тогда.....
Re: опрос кнопок MEGA8
Добавлено: Ср дек 10, 2014 07:13:38
COKPOWEHEU
А можно сдвигами и сложениями. Вспомнить, что сдвиг сохраняет не поместившийся разряд в бит С, а при сложении этот бит можно добавить к слагаемым за 1 команду. На ассемблере это будет реализовать проще и быстрее чем на Си. А потом также, сравнением с 2 и 8. Подсчет кнопок займет 16 тактов. С учетом нициализации, но без учета if'ов и ввода - 18.
А можно использовать битовую магию, у меня получилось 15 тактов на подсчет кнопок. Не считая if'ов и ввода. Вот это решение даже приведу
Спойлер
Хотя и не проверял
Код: Выделить всё
.def temp=r16
.def sum=r17
ANY_PROC:
push temp //на всякий случай сохраняем временные регистры
push sum
in sum,PINB //считывание состояний кнопок. Наверное, и ввод и вывод в PORTD ошибка, пусть кнопки висят на PORTB
mov temp,sum
lsr temp //сдвиг на 1 байт
andi sum,0x55 //первое волшебное число
andi temp,0x55
add sum,temp
mov temp,sum
lsr temp //сдвиг на 2 байта
lsr temp
andi sum,0x33 // второе волшебное число
andi temp,0x33
add sum,temp
mov temp,sum
swap temp //сдвиг на 4 байта, старший полубайт в данном случае неважен, он будет отрезан andi sum,0x0F
add sum,temp
andi sum,0x0F // третье волшебное число
//проверки. Поскольку предыдущая часть считает лог.1, сравнивать надо отпущенные кнопки, а не нажатые.
cpi sum,0
breq BTN_8
cpi sum,6
breq BTN_2
FUNC_END: //конец процедуры, посстанавливаем сохраненные значения
pop sum
pop temp
ret
BTN_8:
sbi PORTD,1
rjmp FUNC_END
BTN_2:
cbi PORTD,1
rjmp FUNC_END
Re: опрос кнопок MEGA8
Добавлено: Ср дек 10, 2014 07:15:06
pyzhman
Стоять-бояться! Это как? -
neox писал(а):...подключены к PORTD...тогда PORTD.1=0...тогда PORTD.1=1
Включать, выключать подтяжку?
Re: опрос кнопок MEGA8
Добавлено: Ср дек 10, 2014 07:53:39
ARV
а к чему такая спешка - такты считать?! у меня вот достаточно тупой, без всякой магии, вариант потребляет максимум 55 тактов на вычисление количества единиц во входном байте, причем это максимум, если ни одной единицы в байте нет - и тактов по-моему 3 всего
Код: Выделить всё
uint8_t sum=0;
// переменная data содержит анализируемый байт
for(;data;data>>=1) sum += !!(data & 1);
// в переменной sum количество единиц, которые были в data
зато кратко и понятно, не то, что всякая ассемблерная магия

P.S. про 55 тактов я соврал, поспешил. Прошу простить
Re: опрос кнопок MEGA8
Добавлено: Ср дек 10, 2014 08:10:19
COKPOWEHEU
Когда разница в 3.5 раза, уже стоит задуматься. Для данной задачи оптимизация не нужна, можно хоть if'ами каждый бит по отдельности считать. И, кстати, это все равно быстрее, 16 тактов независимо от размера. Что-то мне кажется, что среднее время работы у такого кода лучше, чем у Вашего, хотя минимальное, конечно, хуже.
Код: Выделить всё
char x=PINB;
char sum=0;
if(x & (1<<0))sum++;
if(x & (1<<1))sum++;
if(x & (1<<2))sum++;
if(x & (1<<3))sum++;
if(x & (1<<4))sum++;
if(x & (1<<5))sum++;
if(x & (1<<6))sum++;
if(x & (1<<7))sum++;
Но как же можно не поразвлекаться с побитовой магией и ассемблером!
Re: опрос кнопок MEGA8
Добавлено: Ср дек 10, 2014 09:15:59
BCluster
а зачем данная конструкция туть? я имею ввиду двойное отрицание.
Re: опрос кнопок MEGA8
Добавлено: Ср дек 10, 2014 09:58:30
WiseLord
Хотел было сначала ответить: чтобы любое ненулевое число превращалось в 1. Но потом понял, что в скобках вообще-то не любое число, а либо 0, либо 1. Так что да, двойное отрицание не нужно. И вполне хватит
Код: Выделить всё
for(sum = 0; data; data >>= 1) sum += (data & 1);
Re: опрос кнопок MEGA8
Добавлено: Ср дек 10, 2014 11:06:55
Mishany
в виде функции, которую можно вызывать по мере надобности и не влияющую на все остальное, как то так:
Спойлер
Код: Выделить всё
void button(void)
{
unsigned char a,i;
for(i=0;i<8;i++)
{
if((PIND&(1<<i))==0) //проверяем в цикле все порты D
{a++;} //считаем сколько кнопок вкл/выкл
}
if(a==6) // если 2 из 8 выключены
{
//что то делаем....
}
if(a==8) // если все включены
{
//что то делаем....
}
a=0;
}
Re: опрос кнопок MEGA8
Добавлено: Ср дек 10, 2014 11:45:02
ARV
COKPOWEHEU писал(а):уже стоит задуматься
да, стоит.
как раз хотел спросить: а вы этот алгоритм сами придумали или просто содрали из книжки Кнута (если не ошибаюсь)? если сами - честь вам и хвала. однако сумеете ли преобразовать свой код для 16, 32 или 64-битных чисел? согласны, что мой код сработает для любой (в разумных пределах) разрядности переменной data без какой бы то ни был модификации?
WiseLord писал(а):чтобы любое ненулевое число превращалось в 1. Но потом понял
перемудрил, признаю
среднее быстродействие моего варианта можно еще повысить, если цикл записать в соответствии с условиями задачи
Re: опрос кнопок MEGA8
Добавлено: Ср дек 10, 2014 11:52:51
Miw
COKPOWEHEU писал(а):
А можно использовать битовую магию, у меня получилось 15 тактов на подсчет кнопок. Не считая if'ов и ввода. Вот это решение даже приведу
Вау! Это какой-то известный алгоритм или сам придумал ?
Re: опрос кнопок MEGA8
Добавлено: Ср дек 10, 2014 14:21:51
BCluster
А еще можно предподсчет сделать, если не жалко 256 байт. Оч быстро будет )
Re: опрос кнопок MEGA8
Добавлено: Ср дек 10, 2014 17:23:15
COKPOWEHEU
if((PIND&(1<<i))==0)
Если процессор будет считать честно - медленно будет, лучше завести для (1<<i) отдельныю переменную.
да, стоит.
как раз хотел спросить: а вы этот алгоритм сами придумали или просто содрали из книжки Кнута (если не ошибаюсь)?
Содрал, но не с Кнута, а с говнокода, там же понял принцип работы. Продолжить ряд магических чисел? 0x5555, 0x3333, 0x0F0F, 0x00FF, вроде так для двухбайтных чисел.
Ваш код сработает для любой разрядности, но время иногда бывает критичным, а примерно для половны чисел (у которых старший бит равен 1) оно будет максимальным.
ARV писал(а):
среднее быстродействие моего варианта можно еще повысить, если цикл записать в соответствии с условиями задачи
И при sum=2 оно повиснет.
А еще можно предподсчет сделать, если не жалко 256 байт. Оч быстро будет )
Упрощенный вариант с массивом из 16 элементов.
Код: Выделить всё
unsigned char len[16]={0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
unsigned char calc(unsigned char x){
return len[x&0x0F]+len[x>>4];
}
Re: опрос кнопок MEGA8
Добавлено: Ср дек 10, 2014 17:32:00
ARV
COKPOWEHEU писал(а):И при sum=2 оно повиснет.
почему?!
Re: опрос кнопок MEGA8
Добавлено: Ср дек 10, 2014 18:05:52
COKPOWEHEU
Условие (sum<2) будет всегда возвращать false, а false && x = false независимо от х.
Re: опрос кнопок MEGA8
Добавлено: Ср дек 10, 2014 18:17:41
ARV
COKPOWEHEU писал(а):Условие (sum<2) будет всегда возвращать false, а false && x = false независимо от х.
ну дык верно, условие false и
цикл завершается. с чего ему виснуть?
за пределами цикла смотрим на sum - если оно 0 - значит нет ни одной 1, если не ноль - как минимум что-то есть...
Re: опрос кнопок MEGA8
Добавлено: Ср дек 10, 2014 21:43:27
COKPOWEHEU
Верно, прошу прощения.