udineze 0 24 мая, 2012 Опубликовано 24 мая, 2012 · Жалоба Здравствуйте! у меня такой вопрос: есть регулятор (модель для матлаба во вложении), есть разностные уравнения (тоже во вложении), нужно реализовать все это на контроллере. Для реализации такта квантования 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; //Завершение обработки прерывания } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 24 мая, 2012 Опубликовано 24 мая, 2012 · Жалоба По самим вычислениям ничего не скажу - разностные уравнения наглухо забыл (да и знал-то плохо...). Но вот сам алгоритм: 1) совершенно неясно, что делает while(delay) и откуда вообще там эта константа. 2) само по себе построение программы верное - ввести периодическое прерывание от таймера, и в нём с определённой частотой опрашивать АЦП и считать нужные значения. Однако это не очень гибко - если потребуется расшириение функционала и введение новых прерываний, это длительное прерывание может помешать. Можно сделать следующее: в прерывании таймера взводить флажок "нужно просчитать цикл", а в while(1), который в main(), опрашивать флажок и выполнять вычисления (ну и сбрасывать флаг, конечно). Это более простой способ, чем реализация вложенных прерываний на ARM7. Ну и ещё: вместо T0IR|=0x00000001; //Обнуление регистра прерывания таймера надо бы T0IR = 0x00000001; Также странно выглядит float yout; DACR=yout<<6; Я бы в принудительном порядке привёл к нужному типу, не надеясь на компилятор. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
udineze 0 24 мая, 2012 Опубликовано 24 мая, 2012 · Жалоба По самим вычислениям ничего не скажу - разностные уравнения наглухо забыл (да и знал-то плохо...). Но вот сам алгоритм: 1) совершенно неясно, что делает while(delay) и откуда вообще там эта константа. он делает задержку в 20 секунд, примитивно конечно, нерационально может быть, но преподаватель одобрил... 2) само по себе построение программы верное - ввести периодическое прерывание от таймера, и в нём с определённой частотой опрашивать АЦП и считать нужные значения. Однако это не очень гибко - если потребуется расшириение функционала и введение новых прерываний, это длительное прерывание может помешать. расшириение функционала и введение новых прерываний заданием не предусмотрено. меня беспокоит момент такой: когда прерывание пришло, началась обработка подпрограммы, а таймер продолжает считать или нет? иными словами возможна ли такая ситуация что во время обработки подпрограммы прерывания придет новое прерывание и вызовет опять подпрограмму и т.д. ? По самим вычислениям ничего не скажу - разностные уравнения наглухо забыл (да и знал-то плохо...). обычное уравнение, просто переменные в нем: у[k-1] - предыдущее значение y, y[k-2] - значение 2 такта назад и т.д. в данном случае нужно держать в памяти 3 значения y[k-1], y[k-2], y[k-3] Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 1 24 мая, 2012 Опубликовано 24 мая, 2012 · Жалоба 1. В прерываниях длительные вещи - сразу убиваем. Пользуемся флагами (см.выше пост) 2. Для 20 сек - то же самое, накапливаем счетчик и флаг выставляем. Первым делом обрабатываем в while(1) самый быстрый флаг 3. И что мешает ввести три разных счетчика в один и тот же таймер? Нужна задержка? сбрасываем счетчик и флаг, ждем флага. Счетчик инкрементируется в прерывании Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
udineze 0 24 мая, 2012 Опубликовано 24 мая, 2012 · Жалоба 1. В прерываниях длительные вещи - сразу убиваем. Пользуемся флагами (см.выше пост) 2. Для 20 сек - то же самое, накапливаем счетчик и флаг выставляем. Первым делом обрабатываем в while(1) самый быстрый флаг 3. И что мешает ввести три разных счетчика в один и тот же таймер? Нужна задержка? сбрасываем счетчик и флаг, ждем флага. Счетчик инкрементируется в прерывании это критично или просто нерационально? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 1 25 мая, 2012 Опубликовано 25 мая, 2012 · Жалоба это критично или просто нерационально? по-разному если реакция на прерывание короткая, то можно там и оставить, если нужны какие-то действия, требующие затрат (временнЫх), то только флаг проц должен делом заниматься, а не висеть в обработчике прерывания длительное время Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 25 мая, 2012 Опубликовано 25 мая, 2012 · Жалоба проц должен делом заниматься, а не висеть в обработчике прерывания длительное время И каким же делом в данной конкретной задаче занят процессор? Дурацкий какой-то предрассудок. он делает задержку в 20 секунд, примитивно конечно, нерационально может быть, но преподаватель одобрил... Куча вопросов: - зачем нужна задержка 20 секунд - что это за задержка - между чем и чем? - каким образом была посчитана цифра и какие гарантии, что оно завтра будет работать так же когда прерывание пришло, началась обработка подпрограммы, а таймер продолжает считать или нет? иными словами возможна ли такая ситуация что во время обработки подпрограммы прерывания придет новое прерывание и вызовет опять подпрограмму и т.д. ? Таймер, разумеется, считает (его дополнительно никто не сбросил и не остановил). И это правильно, иначе такт квантования будет неизвестно каким, и весь алгоритм "поплывёт". В данной реализации новое прерывание не "вызовет опять подпрограмму". Алгоритм реализован в самом прерывании, а по умолчанию в ARM второе прерывание "перебить" первое не сможет (исключение: первое IRQ, второе - FIQ). Впрочем, ситуация такая возможна. Надо проверить, что время исполнения алгоритма будет гарантированно меньше, чем 10 мс. Я для подобной оценки пользуюсь осциллографом - в начале функции выставляем какую-нибудь свободную ножку в "1", в конце - в "0", и смотрим... Собственно, тут-то мы и возвращемся к вопросу об "одобренной задержке". Что делает задержка на 20 секунд в функции, которая вызывается каждые 10 миллисекунд? PS и с частотой что-то странное. Если Вы отдельно не настраивали частоту периферийной шины, то на таймере не может быть 24 МГц. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
udineze 0 25 мая, 2012 Опубликовано 25 мая, 2012 · Жалоба Куча вопросов: - зачем нужна задержка 20 секунд - что это за задержка - между чем и чем? - каким образом была посчитана цифра и какие гарантии, что оно завтра будет работать так же объект управления (см аттач в первом посте) содержит в себе задержку в 20 секунд а цифровой регулятор содержит эталонную модель, которая повторяет объект и тоже содержит задержку 20 секунд в прикрепленном рисунке есть схема в матлабе, там показано расположение задержки цифра посчитана исходя из того что одна команда в цикле выполняется за такт 1/24 МГц , ну и чтобы получить число делим 20 секунд на 1/24 МГц Таймер, разумеется, считает (его дополнительно никто не сбросил и не остановил). И это правильно, иначе такт квантования будет неизвестно каким, и весь алгоритм "поплывёт". В данной реализации новое прерывание не "вызовет опять подпрограмму". Алгоритм реализован в самом прерывании, а по умолчанию в ARM второе прерывание "перебить" первое не сможет (исключение: первое IRQ, второе - FIQ). Впрочем, ситуация такая возможна. Надо проверить, что время исполнения алгоритма будет гарантированно меньше, чем 10 мс. Я для подобной оценки пользуюсь осциллографом - в начале функции выставляем какую-нибудь свободную ножку в "1", в конце - в "0", и смотрим... Собственно, тут-то мы и возвращемся к вопросу об "одобренной задержке". Что делает задержка на 20 секунд в функции, которая вызывается каждые 10 миллисекунд? PS и с частотой что-то странное. Если Вы отдельно не настраивали частоту периферийной шины, то на таймере не может быть 24 МГц. хм, а сколько на таймере ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 25 мая, 2012 Опубликовано 25 мая, 2012 · Жалоба содержит задержку 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). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
udineze 0 25 мая, 2012 Опубликовано 25 мая, 2012 · Жалоба Я действительно ничего не помню (практики у нас не было, а голая теория... просто бестолковые лекции). Но на мой взгляд, "задержка 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 с нужна - это неопровержимая истина)) вопрос в том как это реализовать, желательно без таймера ? можно кусочек кода ? а то я на си никогда не писал, поэтому и вставляю ассемблерные задержки... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 25 мая, 2012 Опубликовано 25 мая, 2012 · Жалоба Задержка в 20 секунд в имеющейся реализации - это неопровержимый бред. Как, по-Вашему, должен работать этот алгоритм? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
udineze 0 25 мая, 2012 Опубликовано 25 мая, 2012 · Жалоба Задержка в 20 секунд в имеющейся реализации - это неопровержимый бред. в чем бред то ? в величине задержки или в наличии задержки как таковой? Как, по-Вашему, должен работать этот алгоритм? так как написано в первом посте (по крайней мере это понятный мне вариант), но поскольку, вероятно, там неопровержимый бред, интересно Ваше мнение в принципе можно наверно все сделать просто в цикле, без прерывания, но как быть с тактом квантования... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 28 мая, 2012 Опубликовано 28 мая, 2012 · Жалоба Идея в следующем: каждые 10 мс вызывать прерывание, чтобы оно что-то там считало с гарантированной частотой. Идея хорошая, реализация тоже ничего так, но... Как это работает: - программа стартовала, запустила счётчик - счётчик натикал свои 10 мс, сработало прерывание, посчитались нужные значения - в прерывании же начала работать задержка 20 секунд (о том, что такие задержки делать нельзя - см. выше). - ещё через 10 мс (за вычетом времени расчётов) счётчик опять пытается вызвать прерывание. Это не проходит, т.к. из текущего прерывания мы ещё не вышли. - предыдущий пункт повторился около 2000 раз, т.к. задержка длинная. - задержка наконец закончилась, программа выходит в основной цикл. - ... и тут же попадает обратно в прерывание, т.к. таймер давным-давно установил флажок прерывания. Отличия от того, что написано в первом посте, видно? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
udineze 0 28 мая, 2012 Опубликовано 28 мая, 2012 · Жалоба Идея в следующем: каждые 10 мс вызывать прерывание, чтобы оно что-то там считало с гарантированной частотой. Идея хорошая, реализация тоже ничего так, но... Как это работает: - программа стартовала, запустила счётчик - счётчик натикал свои 10 мс, сработало прерывание, посчитались нужные значения - в прерывании же начала работать задержка 20 секунд (о том, что такие задержки делать нельзя - см. выше). - ещё через 10 мс (за вычетом времени расчётов) счётчик опять пытается вызвать прерывание. Это не проходит, т.к. из текущего прерывания мы ещё не вышли. - предыдущий пункт повторился около 2000 раз, т.к. задержка длинная. - задержка наконец закончилась, программа выходит в основной цикл. - ... и тут же попадает обратно в прерывание, т.к. таймер давным-давно установил флажок прерывания. Отличия от того, что написано в первом посте, видно? можно наверно в конце прерывания сбрасывать таймер и запускать заново ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 28 мая, 2012 Опубликовано 28 мая, 2012 · Жалоба Да блин... Мы говорим о квантовании в 10 мс или в "примерно 20 секунд" ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться