Страница 29 из 111
Re: WinAvr в вопросах и ответах
Добавлено: Ср июл 07, 2010 21:07:45
ARV
я тут

однако, я уже устал вещать прописные истины - вы можете вдоволь начитаться их на этом форуме при помощи поиска: все переменные для прерываний должны быть volatile, о том, как делать динамическую индикацию на 7-сегментниках я писал на своем сайте и здесь не один раз, преобразование чисел в символы индикатора - то же самое, код написан тяп-ляп... короче, ковыряться в этом нет желания, извините... чего стоит только это (а там и остального хватает):
Код: Выделить всё
ISR (ADC_vect)
{
adc[n]=ADCW;
switch(n) // преобразование согласно номера канала, переход к 0 каналу после 4-го
{
case 0x00: fbin[n]=adc[n]*1000/1024; n++; ADMUX=ADMUX+1; break;
case 0x01: fbin[n]=adc[n]*1000/1024; n++; ADMUX=ADMUX+1; break;
case 0x02: fbin[n]=adc[n]*100*5/1024;n++; ADMUX=ADMUX+1; break;
case 0x03: fbin[n]=adc[n]*10*5*6/1024;n=0;ADMUX=0b01000000; break;
default: break;
}
ADCSRA=0xFF;
}
когда это должно делаться примерно как-то так:
Код: Выделить всё
ISR (ADC_vect){
static uint8_t n = 0; // номер канала
adc[n] = ADC;
fbin[n] = adc[n] * koefficient[n]; // коэффициенты по каналам в отдельном массиве
if(++n >= 4) n = 0; // выбор следующего номера канала
ADMUX = REFS | n; // включение канала. REFS - константа выбора опорника
ADCSRA |= _BV(ADSC); // запуск очередного измерения
}
и даже в этом случае оптимальнее коэффициенты хранить во FLASH, чтобы ОЗУ не тратить напрасно; массив
fbin заполнять в основном цикле, т.к. длительность прерывания должна быть минимальной, а необходимости именно в прерывании делать вычисления - нет.
короче, разберитесь с формой, а потом поговорим о содержании. обычно протеус достаточно качественно работает с подобными простыми алгоритмами, так что скорее всего ваш код неверен - и неудивительно: алгоритм вы четко не продумали, и явно где-то плюха.
Re: WinAvr в вопросах и ответах
Добавлено: Чт июл 29, 2010 10:38:18
dns
Доброго времени суток! Подскажите,друзья, как правильно сделать ассемблерную вставку, чтобы в ней обрабатывалась переменная из основного сишного кода?
Re: WinAvr в вопросах и ответах
Добавлено: Чт июл 29, 2010 11:39:31
ARV
dns писал(а):Доброго времени суток! Подскажите,друзья, как правильно сделать ассемблерную вставку, чтобы в ней обрабатывалась переменная из основного сишного кода?
если не секрет - зачем вам это? вы действительно чувствуете в себе уверенность обойти оптимизатор компилятора? или даже пяток тактов экномии вам важен?
дело в том, что руководство (далеко не полное!) по ассемблерным вставкам - это 9 страниц А4 текста... а ограничиться просто какой-то выдержкой из него - вряд ли вы сумеете воспользоваться этим...
если очень важно быстродействие, может, лучше задуматься о реализации целых функций на ассемблере? подключение ассемблерных файлов к сишному проекту (как и сам ассемблер из GCC) намного проще и удобнее...
Re: WinAvr в вопросах и ответах
Добавлено: Чт июл 29, 2010 12:18:00
dns
Оптимизатор мне конечно не обойти, но кое-что за ним прибрать могу. Вообще оптимизатор является оптимизатором только для матерых эмбедеров, а у остальных программистов си-код становиться весьма ветвистым в асме.
Попробую поработать с подключаемыми файлами, спасибо за совет.
Re: WinAvr в вопросах и ответах
Добавлено: Чт июл 29, 2010 12:26:31
ARV
dns писал(а):Вообще оптимизатор является оптимизатором только для матерых эмбедеров, а у остальных программистов си-код становиться весьма ветвистым в асме.
ничего не понял
Re: WinAvr в вопросах и ответах
Добавлено: Чт июл 29, 2010 13:01:00
dns
я в том смысле, что неграмотно написаный код на си в асме превращается в сплошные дебри.
Конкретно сейчас я привожу к жизни чужую программу, которая не работала именно по причине неуспевания некоторых функций. Просто заменив 5 раз
PORTС|=1<<PIN_STROB; на
asm("SBI 0x15,2"); удалось ускорить программу на 20% (!)
но это, конечно, грубый подход, не хватает мне опыта, а некоторые опытные сишники в своих оптимизациях доходят вообще до непонятных вещей
uint8_t i;
uint32_t counter;
тогда операции типа
i = (uint8_t) counter;
лучше писать в виде
i = *(uint8_t *) &counter;
Утверждается, что экономится 6 тактов процессора. Так что оптимизатор, как и любой инструмент, приносит пользу только когда им правильно пользоваться.
Re: WinAvr в вопросах и ответах
Добавлено: Чт июл 29, 2010 13:37:21
ARV
я могу утверждать с полной уверенностью, что ваш пример с
PORTC компилировался БЕЗ оптимизатора, так как с включением оптимизатора (
-Os) оператор PORTB |= 1<<PB2; компилируется в одну ассемблерную команду:
Код: Выделить всё
PORTB |= 1<<PB2;
32: c2 9a sbi 0x18, 2 ; 24
под оптимизатором я имел ввиду исключительно работу компилятора, а не извращения программиста типа обмана компилятора указателеями и т.п. оптимизатор неплохо справляется и без таких изголений.
на счет второго вашего примера - это также чушь. при включенной оптимизации (
-Os) эффект наблюдается прямо противоположный заявленному:
Код: Выделить всё
uint32_t counter;
uint8_t i,n;
int main(void) {
i = counter;
n = (uint8_t *)&counter;
}
а вот результат компиляции:
Код: Выделить всё
i = counter;
32: 80 91 62 00 lds r24, 0x0062
36: 80 93 61 00 sts 0x0061, r24
n = (uint8_t *)&counter;
3a: 82 e6 ldi r24, 0x62 ; 98
3c: 90 e0 ldi r25, 0x00 ; 0
3e: 80 93 60 00 sts 0x0060, r24
как видите, первый оператор скомпилировался в
2 команды ассемблера, а второй - в
три
хотя без оптимизации (-O0) второй вариант на 2 команды короче:
Код: Выделить всё
i = counter;
3a: 80 91 62 00 lds r24, 0x0062
3e: 90 91 63 00 lds r25, 0x0063
42: a0 91 64 00 lds r26, 0x0064
46: b0 91 65 00 lds r27, 0x0065
4a: 80 93 61 00 sts 0x0061, r24
n = (uint8_t *)&counter;
4e: 82 e6 ldi r24, 0x62 ; 98
50: 90 e0 ldi r25, 0x00 ; 0
52: 80 93 60 00 sts 0x0060, r24
я настоятельно рекомендую вам не заниматься ерундой, а включить оптимизатор и просто писать программы (желательно, аккуратно и без ошибок)

Re: WinAvr в вопросах и ответах
Добавлено: Пн авг 16, 2010 15:26:04
1exa
А как в WinAvr прошивать фьюзы?
Re: WinAvr в вопросах и ответах
Добавлено: Пн авг 16, 2010 15:46:55
ARV
1exa писал(а):А как в WinAvr прошивать фьюзы?
WinAVR не занимается прошивкой МК - это
компилятор, а не программатор. в комплекте есть и утилита для прошивки
avrdude, однако работать с ней начинающему сложновато.
Re: WinAvr в вопросах и ответах
Добавлено: Вт авг 17, 2010 00:24:46
1exa
В винавр можно автоматом заливать прошивку если зделать мейк фаил но как таким образом фьюзы выставлять ? Аврдуо использовал с граф оболочкой.
Re: WinAvr в вопросах и ответах
Добавлено: Вт авг 17, 2010 15:05:21
ARV
в
makefile в цели пишите командную строку запуска
avrdude, а в его командной строке пишите параметр для зашивания фьюзов - отдельно для старшего, младшего и расширенного байтов. короче, читайте доку
avrdude 
Re: WinAvr в вопросах и ответах
Добавлено: Чт авг 19, 2010 21:02:00
32768
Начал изучать С,но не смог сделать самой простой вещи,а именно скопировать один из битов переменной в бит другой переменной или порта,не изменяя остальных битов (DATA.0->PORTC.1 например).
Как это на С делается?
Re: WinAvr в вопросах и ответах
Добавлено: Пт авг 20, 2010 11:37:44
ARV
32768 писал(а):Начал изучать С,но не смог сделать самой простой вещи,а именно скопировать один из битов переменной в бит другой переменной или порта,не изменяя остальных битов (DATA.0->PORTC.1 например).
Как это на С делается?
как установить бит(ы) переменной, не меняя остальные биты в ней?
как узнать, установлен (или сброшен) определенный бит в переменной?
а так же некоторые другие вопросы начинающих -
ответы здесь.
P.S. не привыкайте к нестандартным приемам типа PORTC
.1 или DATA
.2 - нет такой формы обращения к битам в языке Си.
Re: WinAvr в вопросах и ответах
Добавлено: Пт авг 20, 2010 12:36:40
AI_Disable
32768 писал(а):Начал изучать С,но не смог сделать самой простой вещи,а именно скопировать один из битов переменной в бит другой переменной или порта,не изменяя остальных битов (DATA.0->PORTC.1 например).
Как это на С делается?
Код: Выделить всё
var_1|=var_2&0b00000001; //Копируем 0-й бит из var_2 в var_1, остальные биты var_1 не изменяются
var_1|=var_2&0b10000000; //Копируем 7-й бит из var_2 в var_1, остальные биты var_1 не изменяются
Re: WinAvr в вопросах и ответах
Добавлено: Пт авг 20, 2010 13:01:41
ARV
сдается мне,
AI_Disable, вы не поняли нюанса: вопрошалось о том, как перенести бит, не совпадающий по порядковому номеру с исходным... в вашем ответе номера битов одинаковы. если с моей подсказки (и вашей) топикстартер не дотумкает, как надо поступить - придется послать его к истокам: K&R или хотя бы куда-то в википедию, что ли... короче, учить синтаксис Си

Re: WinAvr в вопросах и ответах
Добавлено: Пт авг 20, 2010 13:14:29
AI_Disable
ARV писал(а):сдается мне, AI_Disable, вы не поняли нюанса: вопрошалось о том, как перенести бит, не совпадающий по порядковому номеру с исходным...
Каюсь, да, не обратил должного внимания. К тому же, не учёл, что переменная, в которую копируют, не обязательна пуста. Похоже, тут не обойтись без if.
Re: WinAvr в вопросах и ответах
Добавлено: Пт авг 20, 2010 14:55:48
AlexFisher
1. Сделать через if - несколько громоздко, но удобочитаемо.
2. Сделать через промежуточную переменную. Непосредственно в порту делать нельзя, потому что нужный бит нужно сначала сбросить.
Код: Выделить всё
temp=PINC;
temp&=`(1 << NumBitToOut); // сброс нужного бита
PORTC=temp | (((DATA >> NumBitFrom) & 0b11111110) << NumBitToOut);
Иначе говоря, если биты разные, то нужный бит сначала двигаем вправо до крайней позиции, маскируем остальные биты, двигаем на нужную позицию. В результате получаем маску для наложения на выходной порт.
Это ассемблерный подход, но, по моему мнению, правильный.
Имеет смысл оформить макросом или инлайновой функцией.
Re: WinAvr в вопросах и ответах
Добавлено: Пт авг 20, 2010 15:43:49
ARV
AlexFisher писал(а):1. Сделать через if - несколько громоздко, но удобочитаемо.
для задачи, которая была озвучена, использование
if действительно лишнее и не такое уж удобочитаемое. как вам такой вариант:

раз уж вы взялись юзать WinAVR - юзайте его на полную катушку, т.е. используйте макросы, которые за вас уже придуманы командой разработчиков (это я про
_BV())
AlexFisher писал(а):2. Сделать через промежуточную переменную. Непосредственно в порту делать нельзя, потому что нужный бит нужно сначала сбросить.
не понял

откуда вы про сброс взяли? не было об этом речи...
AlexFisher писал(а):Иначе говоря, если биты разные, то нужный бит сначала двигаем вправо до крайней позиции, маскируем остальные биты, двигаем на нужную позицию. В результате получаем маску для наложения на выходной порт.
Это ассемблерный подход, но, по моему мнению, правильный.
и в ассемблере это
не правильный подход, и в Си так же. сдвиг на несколько битов - это не такая уж элементарная операция, особенно если переменные не однобайтовые, в то время как проверка состояния бита и на ассемблере 1 команда, и на Си будет скомпилирована в 1 команду. ну ладно, пусть не одна

но все равно сдвиг на 5 битов будет хуже, чем
sbrs|
sbrc и
sbr|
cbr, а сдвиг на 12 битов тем паче

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

Re: WinAvr в вопросах и ответах
Добавлено: Пт авг 20, 2010 15:49:17
32768
AlexFisher писал(а):Код: Выделить всё
temp=PINC;
temp&=`(1 << NumBitToOut); // сброс нужного бита
PORTC=temp | (((DATA >> NumBitFrom) & 0b11111110) << NumBitToOut);
И это язык высокого уровня...
На ассемблере поменьше писанины для того же действия.
Ну ладно, будем курить дальше.
За ответы спасибо!
Re: WinAvr в вопросах и ответах
Добавлено: Пт авг 20, 2010 16:56:43
AlexFisher
ARV писал(а):
AlexFisher писал(а):2. Сделать через промежуточную переменную. Непосредственно в порту делать нельзя, потому что нужный бит нужно сначала сбросить.
не понял

откуда вы про сброс взяли? не было об этом речи...
AlexFisher писал(а):Иначе говоря, если биты разные, то нужный бит сначала двигаем вправо до крайней позиции, маскируем остальные биты, двигаем на нужную позицию. В результате получаем маску для наложения на выходной порт.
Это ассемблерный подход, но, по моему мнению, правильный.
и в ассемблере это
не правильный подход, и в Си так же. сдвиг на несколько битов - это не такая уж элементарная операция, особенно если переменные не однобайтовые, в то время как проверка состояния бита и на ассемблере 1 команда, и на Си будет скомпилирована в 1 команду. ну ладно, пусть не одна

но все равно сдвиг на 5 битов будет хуже, чем
sbrs|
sbrc и
sbr|
cbr, а сдвиг на 12 битов тем паче

поэтому оптимальнее сделать именно через проверку и установку бита "в случае если..."
Про "сбросить бит" я имел в виду то, чтобы применить к биту операцию ИЛИ, там должен быть 0, иначе мы не сможем этой операцией записать в бит 0.
Речь шла о ситуации, когда один из операндов является портом, следовательно, про 16 бит говорить, я думаю, не стоит, хотя переменная может быть любой разрядности. Если номера битов являются константами, то, конечно, не имеет смысла двигать бит туда-сюда. Нужно сразу сдвинуть в нужную сторону на разность номеров битов.
Вообще, у каждой задачи может быть множество решений. Автор выберет то, что ему будет понятней.