Перейти к содержанию
    

Непонятна логика программы

Пишу программу на С для 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.

 

 

Подскажите, в чём ошибка.

Изменено пользователем Владимир_КПИ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проблема в том, что это написано не на "C" :(. Начните с изучения языка.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Программа писалась в CodeVisionAVR. Языка особо не знаю. Писал по логике.

 

Возможно проблема вот здесь - "(10<n<21)".

Изменено пользователем Владимир_КПИ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Учить язык, чтобы выявить ошибку? Не вижу смысла. Проще у кого-то спросить.

Хорошая фраза. Можете занести эту фразу себе в подпись.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Жесть! Зело позабавило :)

Владимир_КПИ, для начала выражение вида if (0<n<11) запишите как if ((n>0)&&(n<11)).

Но вот эту книгу на полку себе поставьте http://www.lib.ru/CTOTOR/kernigan.txt

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо. Исправил. Сейчас проверю работу на практике.

 

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

Но если добавлю ещё операторов if будет не совсем хорошо - при каждом прерывании делать множество проверок. Нельзя ли как-то оптимизировать код?

 

Видео

Изменено пользователем Владимир_КПИ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проблема в том, что это написано не на "C" :(.

Да ладно Вам, вполне жизненная конструкция, и кстати очень даже на C :biggrin:

 

Например так:

unsigned char a;

a = 0;

if (1>a>0) ......

a = 1;

if (1>a>0) ......

 

Шучу... :a14:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но если добавлю ещё операторов if будет не совсем хорошо - при каждом прерывании делать множество проверок. Нельзя ли как-то оптимизировать код?

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;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Более эффективный способ проверок, требуется только одно сравнение для каждого поддиапазона.

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.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

__flash char table[] = { 131, 132, ..... 145 /*... и так далее */ };

// а вместо кучи if одна строка

TCNT0= table[n];

 

Вот это по-моему лучший вариант для моего случая. Объявлю массив со 100 значениями. При каждом прерывании будет инкрементироваться n. За 2 секунды - 100 раз по 1%. Будет и плавнее.

 

 

когда n становится больше максимального индекса в массиве table

Да, думал над этим. Сейчас что-нибудь придумаю.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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% полпериода сетевого питания, я бы сделал так. )

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть массив:

 

int time[100]={0xFB04, 0xF8F2, .....}

 

Как из элемента массива отделить байты?

 

Чтобы потом сделать так:

 

TCNT1H=0xFB; //TCNT1H=high(time[0])

TCNT1L=0x04; //TCNT1L=low(time[0])

 

Коментарии условные.

Изменено пользователем Владимир_КПИ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть массив:

 

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;

 

... и открыть ветку "изучаем С интерактивно" :)

Изменено пользователем Liseev

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...