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

разностные уравнения на LPC2148

Здравствуйте!

у меня такой вопрос: есть регулятор (модель для матлаба во вложении), есть разностные уравнения (тоже во вложении), нужно реализовать все это на контроллере. Для реализации такта квантования 0.01с программа выполняется по прерыванию. частота с которой генерируются прерывания f=тактовая частота/N=1/0.01=100 , N - величина до которой считает таймер/счетчик, N=24 МГц/100 Гц =240000=3A980h, все бы хорошо но меня смущает наличие функции задержки в программе. Посмотрите пожалуйста правильна ли программа:

#include "lpc214x.h"

 

void TMR_IRQ (void) __irq;

int main(void);

 

float xin,yin,yout,youtl,youtll,youtlll,sum1,sum1l,sum1ll,sum1nl,sum1nll,sum2,sum2l,su

m2ll, delay;

 

int main(void)

{

PINSEL1=0x05080000;

 

xin=0;

yin=0;

yout=0;

youtl=0;

youtll=0;

youtlll=0;

sum1=0;

sum1l=0;

sum1ll=0;

sum1nl=0;

sum1nll=0;

sum2=0;

sum2l=0;

sum2ll=0;

 

AD0CR=0x00200006; //Включаем АЦП 0 и выбираем 1 и 2 каналы

 

T0TCR=0x00000002; //Сброс регистров таймера

T0CTCR=0x00000001; //Выбираем режим таймера

T0MCR=0x00000003; //Таймер будет генерировать прерывание при совпадении

//значений в регистрах TC и MR0.

T0MR0=0x0003A980; //Запись значения при котором должно генерироваться

// прерывание а регистр MR0

T0TCR=0x00000001; //Включение таймера

 

VICVectAddr0=TMR_IRQ; //Указатель на функцию обработки прерывания

VICVectCnt0=0x00000024; //Установка источника прерывания

VICIntEnable=0x00000010; //Разрешение прерывания

 

while (1);

 

return 0;

}

 

void TMR_IRQ (void) __irq

{

T0IR|=0x00000001; //Обнуление регистра прерывания таймера

 

ADGSR=0x01000000; //Запуск АЦ преобразования

 

while ((ADC0STAT&0x00000002)==0); //Ожидание завершения преобразования

//сигнала задания

xin=(AD0DR1>>6)&0x3FF; //Получение сигнала задания

xin=xin*0.0012; //Масштабирование сигнала задания

 

while ((ADC0STAT&0x00000004)==0); //Ожидание завершения преобразования сигнала

//c выхода объекта

yin=(AD0DR2>>6)&0x3FF; //Получение сигнала с выхода объекта

yin=yin*(1/7.6); //Масштабирование сигнала с выхода

 

sum1=xin+1.9913*sum1l-0.9913*sum1ll; //Вычисление значения после блока 1/R

sum1ll=sum1l;

sum1l=sum1;

 

sum1=sum1+yin+sum2; //Вычисление значения после блока Сумма

sum1nl

sum1nll

yout= 0.0084*sum1-0.0167*sum1nl+0.0084*sum1nll+2.9341*youtl- 0.8698*youtll+0.9357*youtlll;

//Вычисление значения после блока R/C

sum1nll=sum1nl;

sum1nl=sum1;

youtlll= youtll;

youtll= youtl;

youtl= yout;

sum2=0.0136*yout+1.992*sum2l-0.9921*sum2ll; //Вычисление значения после блока Нэ

sum2ll=sum2l;

sum2l=sum2;

 

DACR=yout<<6; //Запись управляющего сигнала в регистр ЦАП

 

delay=1BCD6550

while(delay>0){delay--} //организация задержки

 

VICVectAddr=0x00000000; //Завершение обработки прерывания

}

 

post-68678-1337846502_thumb.jpg

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


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

По самим вычислениям ничего не скажу - разностные уравнения наглухо забыл (да и знал-то плохо...).

 

Но вот сам алгоритм:

1) совершенно неясно, что делает while(delay) и откуда вообще там эта константа.

 

2) само по себе построение программы верное - ввести периодическое прерывание от таймера, и в нём с определённой частотой опрашивать АЦП и считать нужные значения. Однако это не очень гибко - если потребуется расшириение функционала и введение новых прерываний, это длительное прерывание может помешать. Можно сделать следующее: в прерывании таймера взводить флажок "нужно просчитать цикл", а в while(1), который в main(), опрашивать флажок и выполнять вычисления (ну и сбрасывать флаг, конечно). Это более простой способ, чем реализация вложенных прерываний на ARM7.

 

Ну и ещё: вместо T0IR|=0x00000001; //Обнуление регистра прерывания таймера

надо бы T0IR = 0x00000001;

 

Также странно выглядит

float yout;

DACR=yout<<6;

Я бы в принудительном порядке привёл к нужному типу, не надеясь на компилятор.

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


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

По самим вычислениям ничего не скажу - разностные уравнения наглухо забыл (да и знал-то плохо...).

 

Но вот сам алгоритм:

1) совершенно неясно, что делает while(delay) и откуда вообще там эта константа.

он делает задержку в 20 секунд, примитивно конечно, нерационально может быть, но преподаватель одобрил...

 

2) само по себе построение программы верное - ввести периодическое прерывание от таймера, и в нём с определённой частотой опрашивать АЦП и считать нужные значения. Однако это не очень гибко - если потребуется расшириение функционала и введение новых прерываний, это длительное прерывание может помешать.

расшириение функционала и введение новых прерываний заданием не предусмотрено. меня беспокоит момент такой: когда прерывание пришло, началась обработка подпрограммы, а таймер продолжает считать или нет? иными словами возможна ли такая ситуация что во время обработки подпрограммы прерывания придет новое прерывание и вызовет опять подпрограмму и т.д. ?

 

По самим вычислениям ничего не скажу - разностные уравнения наглухо забыл (да и знал-то плохо...).

обычное уравнение, просто переменные в нем: у[k-1] - предыдущее значение y, y[k-2] - значение 2 такта назад и т.д.

в данном случае нужно держать в памяти 3 значения y[k-1], y[k-2], y[k-3]

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


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

1. В прерываниях длительные вещи - сразу убиваем. Пользуемся флагами (см.выше пост)

2. Для 20 сек - то же самое, накапливаем счетчик и флаг выставляем. Первым делом обрабатываем в while(1) самый быстрый флаг

3. И что мешает ввести три разных счетчика в один и тот же таймер? Нужна задержка? сбрасываем счетчик и флаг, ждем флага. Счетчик инкрементируется в прерывании

 

 

 

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


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

1. В прерываниях длительные вещи - сразу убиваем. Пользуемся флагами (см.выше пост)

2. Для 20 сек - то же самое, накапливаем счетчик и флаг выставляем. Первым делом обрабатываем в while(1) самый быстрый флаг

3. И что мешает ввести три разных счетчика в один и тот же таймер? Нужна задержка? сбрасываем счетчик и флаг, ждем флага. Счетчик инкрементируется в прерывании

это критично или просто нерационально?

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


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

это критично или просто нерационально?

по-разному

если реакция на прерывание короткая, то можно там и оставить, если нужны какие-то действия, требующие затрат (временнЫх), то только флаг

проц должен делом заниматься, а не висеть в обработчике прерывания длительное время

 

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


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

проц должен делом заниматься, а не висеть в обработчике прерывания длительное время

И каким же делом в данной конкретной задаче занят процессор? Дурацкий какой-то предрассудок.

 

 

он делает задержку в 20 секунд, примитивно конечно, нерационально может быть, но преподаватель одобрил...

Куча вопросов:

- зачем нужна задержка 20 секунд

- что это за задержка - между чем и чем?

- каким образом была посчитана цифра и какие гарантии, что оно завтра будет работать так же

 

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

Таймер, разумеется, считает (его дополнительно никто не сбросил и не остановил). И это правильно, иначе такт квантования будет неизвестно каким, и весь алгоритм "поплывёт".

В данной реализации новое прерывание не "вызовет опять подпрограмму". Алгоритм реализован в самом прерывании, а по умолчанию в ARM второе прерывание "перебить" первое не сможет (исключение: первое IRQ, второе - FIQ).

 

Впрочем, ситуация такая возможна. Надо проверить, что время исполнения алгоритма будет гарантированно меньше, чем 10 мс. Я для подобной оценки пользуюсь осциллографом - в начале функции выставляем какую-нибудь свободную ножку в "1", в конце - в "0", и смотрим...

 

Собственно, тут-то мы и возвращемся к вопросу об "одобренной задержке". Что делает задержка на 20 секунд в функции, которая вызывается каждые 10 миллисекунд?

 

PS и с частотой что-то странное. Если Вы отдельно не настраивали частоту периферийной шины, то на таймере не может быть 24 МГц.

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


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

Куча вопросов:

- зачем нужна задержка 20 секунд

- что это за задержка - между чем и чем?

- каким образом была посчитана цифра и какие гарантии, что оно завтра будет работать так же

объект управления (см аттач в первом посте) содержит в себе задержку в 20 секунд а цифровой регулятор содержит эталонную модель, которая повторяет объект и тоже содержит задержку 20 секунд

в прикрепленном рисунке есть схема в матлабе, там показано расположение задержки

цифра посчитана исходя из того что одна команда в цикле выполняется за такт 1/24 МГц , ну и чтобы получить число делим 20 секунд на 1/24 МГц

 

Таймер, разумеется, считает (его дополнительно никто не сбросил и не остановил). И это правильно, иначе такт квантования будет неизвестно каким, и весь алгоритм "поплывёт".

В данной реализации новое прерывание не "вызовет опять подпрограмму". Алгоритм реализован в самом прерывании, а по умолчанию в ARM второе прерывание "перебить" первое не сможет (исключение: первое IRQ, второе - FIQ).

 

Впрочем, ситуация такая возможна. Надо проверить, что время исполнения алгоритма будет гарантированно меньше, чем 10 мс. Я для подобной оценки пользуюсь осциллографом - в начале функции выставляем какую-нибудь свободную ножку в "1", в конце - в "0", и смотрим...

 

Собственно, тут-то мы и возвращемся к вопросу об "одобренной задержке". Что делает задержка на 20 секунд в функции, которая вызывается каждые 10 миллисекунд?

 

PS и с частотой что-то странное. Если Вы отдельно не настраивали частоту периферийной шины, то на таймере не может быть 24 МГц.

хм, а сколько на таймере ?

 

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


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

содержит задержку 20 секунд

 

Я действительно ничего не помню (практики у нас не было, а голая теория... просто бестолковые лекции). Но на мой взгляд, "задержка 20 секунд" - это большой массив, в который по кругу записываются 20 (задержка) / 0,01 (период квантования) значений, и считывается значение, которое было записано туда первым.

То, что сейчас есть, работать в принципе не должно, не смотря на все одобрения.

 

цифра посчитана исходя из того что одна команда в цикле выполняется за такт 1/24 МГц , ну и чтобы получить число делим 20 секунд на 1/24 МГц

1) команда не выполняется за 1/24 МГц. Это достаточно "навороченный" контроллер, у него несколько (!) шин, и у каждой своя (!) скорость.

2) while(delay>0){delay--} - это не одна команда. В случае float delay - это даже не десять команд. Впрочем, если компилятор чуть-чуть подумает, это будет НОЛЬ (!!) команд, т.к. результат всего этого действия никто не использует.

 

хм, а сколько на таймере ?

Юзермануал в помощь.

The VPB Divider determines the relationship between the processor clock (CCLK) and the clock used by peripheral devices (PCLK).

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


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

Я действительно ничего не помню (практики у нас не было, а голая теория... просто бестолковые лекции). Но на мой взгляд, "задержка 20 секунд" - это большой массив, в который по кругу записываются 20 (задержка) / 0,01 (период квантования) значений, и считывается значение, которое было записано туда первым.

То, что сейчас есть, работать в принципе не должно, не смотря на все одобрения.

 

 

1) команда не выполняется за 1/24 МГц. Это достаточно "навороченный" контроллер, у него несколько (!) шин, и у каждой своя (!) скорость.

2) while(delay>0){delay--} - это не одна команда. В случае float delay - это даже не десять команд. Впрочем, если компилятор чуть-чуть подумает, это будет НОЛЬ (!!) команд, т.к. результат всего этого действия никто не использует.

 

 

Юзермануал в помощь.

The VPB Divider determines the relationship between the processor clock (CCLK) and the clock used by peripheral devices (PCLK).

задержка 20 с нужна - это неопровержимая истина))

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

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


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

Задержка в 20 секунд в имеющейся реализации - это неопровержимый бред.

 

Как, по-Вашему, должен работать этот алгоритм?

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


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

Задержка в 20 секунд в имеющейся реализации - это неопровержимый бред.

в чем бред то ? в величине задержки или в наличии задержки как таковой?

Как, по-Вашему, должен работать этот алгоритм?

так как написано в первом посте (по крайней мере это понятный мне вариант), но поскольку, вероятно, там неопровержимый бред, интересно Ваше мнение

в принципе можно наверно все сделать просто в цикле, без прерывания, но как быть с тактом квантования...

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


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

Идея в следующем: каждые 10 мс вызывать прерывание, чтобы оно что-то там считало с гарантированной частотой.

Идея хорошая, реализация тоже ничего так, но...

 

Как это работает:

- программа стартовала, запустила счётчик

- счётчик натикал свои 10 мс, сработало прерывание, посчитались нужные значения

- в прерывании же начала работать задержка 20 секунд (о том, что такие задержки делать нельзя - см. выше).

- ещё через 10 мс (за вычетом времени расчётов) счётчик опять пытается вызвать прерывание. Это не проходит, т.к. из текущего прерывания мы ещё не вышли.

- предыдущий пункт повторился около 2000 раз, т.к. задержка длинная.

- задержка наконец закончилась, программа выходит в основной цикл.

- ... и тут же попадает обратно в прерывание, т.к. таймер давным-давно установил флажок прерывания.

 

 

Отличия от того, что написано в первом посте, видно?

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


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

Идея в следующем: каждые 10 мс вызывать прерывание, чтобы оно что-то там считало с гарантированной частотой.

Идея хорошая, реализация тоже ничего так, но...

 

Как это работает:

- программа стартовала, запустила счётчик

- счётчик натикал свои 10 мс, сработало прерывание, посчитались нужные значения

- в прерывании же начала работать задержка 20 секунд (о том, что такие задержки делать нельзя - см. выше).

- ещё через 10 мс (за вычетом времени расчётов) счётчик опять пытается вызвать прерывание. Это не проходит, т.к. из текущего прерывания мы ещё не вышли.

- предыдущий пункт повторился около 2000 раз, т.к. задержка длинная.

- задержка наконец закончилась, программа выходит в основной цикл.

- ... и тут же попадает обратно в прерывание, т.к. таймер давным-давно установил флажок прерывания.

 

 

Отличия от того, что написано в первом посте, видно?

можно наверно в конце прерывания сбрасывать таймер и запускать заново ?

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


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

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

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

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

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

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

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

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

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

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