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

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

что это было? и, главное, зачем?

 

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

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


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

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

1. по истечении 20 секунд задержка выключается

2. первые 20 секунд нужно запоминать рассчитанные значения и выводить их по истечению 20 секунд.

 

то есть алгоритм такой:

1.поступает сигнал

2. пропускаем его через регулятор

3. проверяем, если задержка не кончилась, то запоминаем результат

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

 

я так понимаю при такте 0.01 и задержке 20 секунд надо запомнить 20/0.01=2000 значений, которые по истечении 20 секунд надо выводить

 

но! пока выводим эти 2000 значений накопится новые 2000 значений

еще смущает вопрос: 20 секунд задержка - значит первые 20 секунд система должна выводить на выход 0 и заниматься только запоминанием?

 

еще момент: формирование такта квантования при помощи таймера с прерыванием теряет смысл...но блин, как то его надо формировать

 

ну и вопрос на миллион, как это все реализовать то? массив как то надо делать и сдвигать его, с трудом представляю это

 

 

стоп! этот алгоритм в подпрограмму обработки прерывания и вставим - и будет мне такт 0,01

 

подскажите как массив задать

так чтоли:

dalay[2000]=[0 0 0 0 ... 0]

 

или каждый элемент прописывать

dalay[1]=0

dalay[2]=0

...

dalay[2000]=0

 

post-68678-1338494754_thumb.jpg

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

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


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

я так понимаю при такте 0.01 и задержке 20 секунд надо запомнить 20/0.01=2000 значений, которые по истечении 20 секунд надо выводить

стоп! этот алгоритм в подпрограмму обработки прерывания и вставим - и будет мне такт 0,01

Ура. Ещё чуть-чуть - и алгоритм наконец родится!

По поводу того, что я говорил о 20000 значений - это я что-то неправильное говорил...

 

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

Десятка тактов для понимания должно хватить.

 

 

подскажите как массив задать

Учебник языка Си. Классика - Керниган и Ричи (спрашивать в гугле), но это описано в ЛЮБОМ учебнике.

 

Заполнение нулями - либо вызовом memset (см. гугл) либо организацией цикла.

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


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

переписал

#include "lpc214x.h"

void TMR_IRQ (void)    __irq;
int main(void);

float xR;          // x[k] для 1/R[z]; 
float yR;          // y[k] для 1/R[z];
float yR_1;        // y[k-1] для 1/R[z]
float yR_2;       // y[k-2] для 1/R[z]
float xRC;         // x[k] для R[z]/C[z]
float xRC_1;       // x[k-1] для R[z]/C[z]     
float xRC_2;       // x[k-2] для R[z]/C[z]
float yRC;         // y[k] для R[z]/C[z]
float yRC_1;       // y[k-1] для R[z]/C[z]
float yRC_2;       // y[k-2] для R[z]/C[z]
float yRC_3;       // y[k-3] для R[z]/C[z]
float xH;          // x[k] для H[z]
float yH;                    // y[k] для H[z]
float yH_1;                // y[k-1] для H[z]
float yH_2;               // y[k-2] для H[z]
float yHD;                // y[k] после звена запаздывания
float ADC;               // сигнал от АЦП
float yHD_ADC;     // разность сигналов от АЦП и модели
float ySUM;            // сигнал обратной связи
float delay[2000];   // массив из 2000 значений сигнала для формирования задержки 
int tau;                    // количество тактов задержки

int main(void)
{
  PINSEL1=0x05080000;

xR=0; //задаём начальные значения для переменных
yR=0;
yR_1=0;
yR_2=0;
xRC=0;
xRC_1=0;     
xRC_2=0;
yRC=0;
yRC_1=0;
yRC_2=0;
yRC_3=0;
xH=0;
yH=0;
yH_1=0;
yH_2=0;
yHD=0;
ADC=0;
yHD_ADC=0;
ySUM=0;
tau=0;

delay[2000]={0 0 0 0 0 … 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;     //Обнуление регистра прерывания таймера
  tau++;
     //переопределение переменных для блока 1/R[z]

     yR_2=yR_1;        // y[k-1]→y[k-2]
     yR_1=yR;            // y[k]→y[k-1]


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

  while ((ADC0STAT&0x00000002)==0);     //Ожидание завершения преобразования 
                                        //сигнала задания 
  xR=(AD0DR1>>6)&0x3FF;     //Получение сигнала задания
  // расчет текущего значения y[k] регулятора 1/R[z]
  yR=0.0012*xR+1.9913*yR_1-0.9913*yR_2;
  // расчет входного параметра регулятора R[z]/C[z]
  xRC=7.6*(yR-0.1316*ySUM);
  //переопределение переменных для  регулятора R[z]/C[z]

  xRC_2=xRC_1;           // x[k-1]→x[k-2]
  xRС_1=xRC;        // x[k]→x[k-1]
  yRС_3=yRC_2;        //y[k-2]→y[k-3]
  yRС_2=yRC_1;        //y[k-1]→y[k-2]
  yRС_1=yRC;        //y[k]→y[k-1]

  //расчет текущего значения y[k] регулятора R[z]/С[z]
  yRC=0.0084*xRC-0.0167*xRC_1+0.0084*xRC_2+2.9341*yRC_1-2.8698*yRC_2+0.9357*yRC_3;
  DACR=yRC<<6;     //Запись управляющего сигнала в регистр ЦАП
  //переопределение переменных для H[z]

  yH_2=yH_1;         //y[k-1]→y[k-2]
  yH_1=yH;           //y[k]→y[k-1]

  //расчет текущего значения y[k] для H[z]
  yH=0.0136*yRC+1.992*yH_1-0.9921*yH_2;
  //организация звена запаздывания
  
  if(tau<=1999){
  dalay[1999-tau]=yH;
  ySUM=yH;}
  else{
  yHD=dalay[1998];
  for(i=1998;i<=1;i--){
  dalay[i]=dalay[i-1];} // организация сдвига массива
  dalay[0]=yH;
  ADC=(AD0DR2>>6)&0x3FF;     //Получение сигнала с выхода объекта
  yHD_ADC=ADC-yHD;
  ySUM=yH+yHD_ADC;}

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

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


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

Ну вот, уже теплее :-)

 

Некоторые проблемы:

- код не компилируется из-за опечаток. Ай-ай, ну надо ж хоть проверять. Благо это можно сделать совершенно бесплатно (и довольно интересно, надо заметить).

- таймер и АЦП по-прежнему не работают (описывал проблемы выше). Это тоже можно проверить.

- название переменной ADC похоже на название регистра. Это не проблема, это просто некрасиво, на мой взгляд.

- вот это неизвестный мне язык: delay[2000]={0 0 0 0 0 … 0}; Инициализацию нулями (если уж хочется) проще сделать в цикле.

- алгоритм сдвига вроде б рабочий (один только вопрос: что будет, если tau переполнится?), но гораздо лучше ничего никуда не двигать.

 

Более правильным является алгоритм кольцевого буфера: берём индекс i (можно тау :) ), считываем i-ый элемент (это будет выходом алгоритма), записываем на это же место входное значение. Увеличиваем i на единицу, проверяем, если оно вышло за пределы массива, сбрасываем его в ноль (т.е. в начало массива).

Итого при минимальных действиях получаем то же самое поведение - входной сигнал попадёт на выход только после того, как i совершит полный "круг" и второй раз окажется в той же ячейке.

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


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

Ну вот, уже теплее :-)

 

Некоторые проблемы:

- код не компилируется из-за опечаток. Ай-ай, ну надо ж хоть проверять. Благо это можно сделать совершенно бесплатно (и довольно интересно, надо заметить).

- таймер и АЦП по-прежнему не работают (описывал проблемы выше). Это тоже можно проверить.

- название переменной ADC похоже на название регистра. Это не проблема, это просто некрасиво, на мой взгляд.

- вот это неизвестный мне язык: delay[2000]={0 0 0 0 0 … 0}; Инициализацию нулями (если уж хочется) проще сделать в цикле.

- алгоритм сдвига вроде б рабочий (один только вопрос: что будет, если tau переполнится?), но гораздо лучше ничего никуда не двигать.

 

Более правильным является алгоритм кольцевого буфера: берём индекс i (можно тау :) ), считываем i-ый элемент (это будет выходом алгоритма), записываем на это же место входное значение. Увеличиваем i на единицу, проверяем, если оно вышло за пределы массива, сбрасываем его в ноль (т.е. в начало массива).

Итого при минимальных действиях получаем то же самое поведение - входной сигнал попадёт на выход только после того, как i совершит полный "круг" и второй раз окажется в той же ячейке.

так:

for(i=0; i<=1999; i++){
delay[i]=0};

 

переполнение tau:

else{
  yHD=dalay[1999];
  for(i=1999;i<=1;i--){
  dalay[i]=dalay[i-1];} // организация сдвига массива
  dalay[0]=yH;
  ADC=(AD0DR2>>6)&0x3FF;     //Получение сигнала с выхода объекта
  yHD_ADC=ADC-yHD;
  ySUM=yH+yHD_ADC;
  [b]tau--[/b];}

насчет другого способа, спасибо, но наверно поздно...пошел печатать)

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


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

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

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

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

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

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

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

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

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

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