Motion 0 13 февраля, 2008 Опубликовано 13 февраля, 2008 (изменено) · Жалоба Пишу программу на С для AVR. Cуть - плавный пуск. Проблемный кусок: int n=0; // External Interrupt 0 service routine interrupt [EXT_INT0] void ext_int0_isr(void) { // Place your code here n=n+1; if (0<n<11) { TCNT0=0x83; TCCR0=0x03; } if (10<n<21) { TCNT0=0x91; TCCR0=0x03; } if (20<n<31) { TCNT0=0x9D; TCCR0=0x03; } } Объявил глобальную переменную. Присвоил ей нулевое значение. При каждом внешнем прерывании переменная инкрементируется. В зависимости от количества прерываний запускается таймер с разной константой. То есть первых 10 прерываний - константа будет 0x83 Следующий 10 - 0x91 и т.д. Но на асемблере получилось не так, как планировалось. Программа проверяет каждое условие и всё равно выполняет все подряд операторы. Например в начале, когда n=1, она проверяет не меньше ли оно 10. Оно меньше. Значит выполняются операторы. Потом идёт вторая проверка. Тут условие не выполняется, но всё равно операторы выполняются. Программа на асемблере: ; 44 // Place your code here ; 45 n=n+1; MOVW R30,R4 ADIW R30,1 MOVW R4,R30 ; 46 second=0; CLR R6 CLR R7 ; 47 ; 48 if (0<n<11) { MOVW R30,R4 LDI R26,LOW(0) LDI R27,HIGH(0) CALL __LTW12 CPI R30,LOW(0xB) BRSH _0x3 ; 49 TCNT0=0x83; LDI R30,LOW(131) OUT 0x32,R30 ; 50 TCCR0=0x03; LDI R30,LOW(3) OUT 0x33,R30 ; 51 } ; 52 ; 53 if (10<n<21) { _0x3: MOVW R30,R4 LDI R26,LOW(10) LDI R27,HIGH(10) CALL __LTW12 CPI R30,LOW(0x15) BRSH _0x4 ; 54 TCNT0=0x91; LDI R30,LOW(145) OUT 0x32,R30 ; 55 TCCR0=0x03; LDI R30,LOW(3) OUT 0x33,R30 ................................... __LTW12: CP R26,R30 CPC R27,R31 LDI R30,1 BRLT __LTW12T CLR R30 __LTW12T: RET То что подчеркнул красным проблемные места. Получается R30 всегда либо 1, ли бо 0. Подскажите, в чём ошибка. Изменено 13 февраля, 2008 пользователем Владимир_КПИ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 1 13 февраля, 2008 Опубликовано 13 февраля, 2008 · Жалоба Проблема в том, что это написано не на "C" :(. Начните с изучения языка. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Motion 0 13 февраля, 2008 Опубликовано 13 февраля, 2008 (изменено) · Жалоба Программа писалась в CodeVisionAVR. Языка особо не знаю. Писал по логике. Возможно проблема вот здесь - "(10<n<21)". Изменено 13 февраля, 2008 пользователем Владимир_КПИ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 1 13 февраля, 2008 Опубликовано 13 февраля, 2008 · Жалоба Учить язык, чтобы выявить ошибку? Не вижу смысла. Проще у кого-то спросить. Хорошая фраза. Можете занести эту фразу себе в подпись. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 13 февраля, 2008 Опубликовано 13 февраля, 2008 · Жалоба Жесть! Зело позабавило :) Владимир_КПИ, для начала выражение вида if (0<n<11) запишите как if ((n>0)&&(n<11)). Но вот эту книгу на полку себе поставьте http://www.lib.ru/CTOTOR/kernigan.txt Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Motion 0 13 февраля, 2008 Опубликовано 13 февраля, 2008 (изменено) · Жалоба Спасибо. Исправил. Сейчас проверю работу на практике. Всё отлично работает. Программа своё отрабатывает. Единственное, что плавный пуск делается за 10 шагов. Нужно сделать чаще, чтобы для зрения не было замерно. Чтобы был именно планым, а не рывками. Но если добавлю ещё операторов if будет не совсем хорошо - при каждом прерывании делать множество проверок. Нельзя ли как-то оптимизировать код? Видео Изменено 13 февраля, 2008 пользователем Владимир_КПИ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
singlskv 0 13 февраля, 2008 Опубликовано 13 февраля, 2008 · Жалоба Проблема в том, что это написано не на "C" :(. Да ладно Вам, вполне жизненная конструкция, и кстати очень даже на C Например так: unsigned char a; a = 0; if (1>a>0) ...... a = 1; if (1>a>0) ...... Шучу... :a14: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
=AK= 12 13 февраля, 2008 Опубликовано 13 февраля, 2008 · Жалоба Но если добавлю ещё операторов if будет не совсем хорошо - при каждом прерывании делать множество проверок. Нельзя ли как-то оптимизировать код? http://en.wikipedia.org/wiki/Switch_statement Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 1 14 февраля, 2008 Опубликовано 14 февраля, 2008 · Жалоба http://en.wikipedia.org/wiki/Switch_statement Дык, чую,что совсем незачем принципиально так строить алгоритм - там что-то системного подхода в упор не видать :(. А co switch он такого в обнимку с волшебником натворит :). Ладно пример со switch: switch( n++ / 10 ) { case 0: TCNT0=0x83; break; case 1: TCNT0=0x91; break; case 2: TCNT0=0x9D; break; case ....... ....... break; default: ; } TCCR0=0x03; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SSerge 4 14 февраля, 2008 Опубликовано 14 февраля, 2008 · Жалоба Более эффективный способ проверок, требуется только одно сравнение для каждого поддиапазона. if( n < 11 ) TCNT0=0x83; else if( n < 21 ) TCNT0=0x91; else if( n < 31 ) TCNT0=0x9D; если хочется ещё быстрее - придётся за это заплатить размером памяти кода. Например так: __flash char table[] = { 131, 132, ..... 145 /*... и так далее */ }; // а вместо кучи if одна строка TCNT0= table[n]; разумеется, нужно позаботиться о случаях когда n меньше 0 (можно объявить как unsigned) и когда n становится больше максимального индекса в массиве table. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Motion 0 14 февраля, 2008 Опубликовано 14 февраля, 2008 · Жалоба __flash char table[] = { 131, 132, ..... 145 /*... и так далее */ }; // а вместо кучи if одна строка TCNT0= table[n]; Вот это по-моему лучший вариант для моего случая. Объявлю массив со 100 значениями. При каждом прерывании будет инкрементироваться n. За 2 секунды - 100 раз по 1%. Будет и плавнее. когда n становится больше максимального индекса в массиве table Да, думал над этим. Сейчас что-нибудь придумаю. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Gogan 0 14 февраля, 2008 Опубликовано 14 февраля, 2008 · Жалоба unsigned int n=0; #define tcnt0_max 0xff #define tcnt0_min 0x83 #define nmax 100 // External Interrupt 0 service routine interrupt [EXT_INT0] void ext_int0_isr(void) { // Place your code here if(n<nmax){n=n+1;} TCNT0=tcnt0_min+((tcnt0_max-tcnt0_min)*n)/nmax; TCCR0=0x03; } если nmax>0xff тогда нужно "TCNT0=tcnt0_min+((tcnt0_max-tcnt0_min)*(unsigned long int)n)/nmax;" операция деления для int (или long int) выполняется не помню сколько, но не более 500 клоков (на 8мГц потратится не более 0,1 мс времени, или 1% полпериода сетевого питания, я бы сделал так. ) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Motion 0 14 февраля, 2008 Опубликовано 14 февраля, 2008 (изменено) · Жалоба Есть массив: int time[100]={0xFB04, 0xF8F2, .....} Как из элемента массива отделить байты? Чтобы потом сделать так: TCNT1H=0xFB; //TCNT1H=high(time[0]) TCNT1L=0x04; //TCNT1L=low(time[0]) Коментарии условные. Изменено 14 февраля, 2008 пользователем Владимир_КПИ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Liseev 0 14 февраля, 2008 Опубликовано 14 февраля, 2008 (изменено) · Жалоба Есть массив: int time[100]={0xFB04, 0xF8F2, .....} Как из элемента массива отделить байты? Чтобы потом сделать так: TCNT1H=0xFB; //TCNT1H=high(time[0]) TCNT1L=0x04; //TCNT1L=low(time[0]) Коментарии условные. TCNT1H = (time[n] & 0xFF00) >> 8; TCNT1L = time[n] & 0xFF; ... и открыть ветку "изучаем С интерактивно" :) Изменено 14 февраля, 2008 пользователем Liseev Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Motion 0 14 февраля, 2008 Опубликовано 14 февраля, 2008 · Жалоба Спасибо Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться