реклама на сайте
подробности

 
 
> Скорость выполнения кода на atmega640
Leonmezon
сообщение Jul 24 2009, 11:12
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Просьба помочь с функцией отправки байт по RS232 от atmega640 (сама функция полностью работает, но необходимо ускорить ее выполнения (на ассемблер перейти не могу - его не знаю).
// Функция передачи данных на ЭВМ по RS232 (масивы B1, B2 - создаю в ОЗУ, передаю по переменно взависимости от флагов. перед массив идут 5 0хF0 - заголовок.
Код
void RS232(void)
{
unsigned int i, j;
unsigned char data[4];
signed long *p;
p=(signed long*)data;
flag_BUF=0;
if (flag_B2==1)
{
  UDR0 = 0xF0;
  while ( !( UCSR0A & (1<<UDRE0)) ) { };
  UDR0 = 0xF0;
  while ( !( UCSR0A & (1<<UDRE0)) ) { };
  UDR0 = 0xF0;
  while ( !( UCSR0A & (1<<UDRE0)) ) { };
  UDR0 = 0xF0;
  while ( !( UCSR0A & (1<<UDRE0)) ) { };
  UDR0 = 0xF0;
  while ( !( UCSR0A & (1<<UDRE0)) ) { };
  // Преобразуем signed long B1 и в ЭВМ
     for(i=0; i<600; i++)
     {
        *p=B1[i];
         for (j=0; j<4; j++)
           {
              UDR0 = data[j];
              while ( !( UCSR0A & (1<<UDRE0)) ) { };
           }
     }
}
else
{
  UDR0 = 0xF0;
  while ( !( UCSR0A & (1<<UDRE0)) ) { };
  UDR0 = 0xF0;
  while ( !( UCSR0A & (1<<UDRE0)) ) { };
  UDR0 = 0xF0;
  while ( !( UCSR0A & (1<<UDRE0)) ) { };
  UDR0 = 0xF0;
  while ( !( UCSR0A & (1<<UDRE0)) ) { };
  UDR0 = 0xF0;
  while ( !( UCSR0A & (1<<UDRE0)) ) { };
// Преобразуем signed long B2 и в ЭВМ
    for(i=0; i<600; i++)
     {
        *p=B2[i];
         for (j=0; j<4; j++)
           {
              UDR0 = data[j];
              while ( !( UCSR0A & (1<<UDRE0)) ) { };
           }
     }      
}
}
Причина редактирования: Оформление цитаты исходника.
Go to the top of the page
 
+Quote Post
5 страниц V   1 2 3 > »   
Start new topic
Ответов (1 - 68)
Непомнящий Евген...
сообщение Jul 24 2009, 11:24
Сообщение #2


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



А зачем вам ускорять скорость ее выполнения? Какая скорость rs232? По-идее, вы вполне будете ее выдерживать... Никаких тяжелых вычислений нет.

ps есть полезный тег code
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jul 24 2009, 11:38
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Переведите работу на прерывания - все равно, на чем написана программа, если она тупо ждет установки флага UART'а.
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 24 2009, 14:17
Сообщение #4


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(Непомнящий Евгений @ Jul 24 2009, 15:24) *
А зачем вам ускорять скорость ее выполнения? Какая скорость rs232? По-идее, вы вполне будете ее выдерживать... Никаких тяжелых вычислений нет.

ps есть полезный тег code

1. Скорость RS232 - 115200 бит/с.
2. Прерывания - нельзя - эта функция работает постоянно, как готовы новые данные (т.е. заполнен буфер B1 или В2), а по прирыванию - идет заполнение буферов по переменно.
Вот примерно как идет работа: (лишнее убрал)
Код
void main(void)
{
DDRF=0x0F;
DDRC=0x0F;
SpiInit();
uart0_init();
init_devices();
//Инициализация АЦП
// Задание параметров работы АЦП
// Бесконечный цикл с приемом данных и передачей по RS232
while(1)
{
   if(flag_BUF==1)
    {
      RS232();
    }
   NOP();
}
}
Причина редактирования: Оформление цитаты исходника.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jul 24 2009, 14:27
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(Leonmezon @ Jul 24 2009, 17:17) *
2. Прерывания - нельзя - эта функция работает постоянно...

Вот именно по этой причине и нужны ПРЕРЫВАНИЯ или,как минимум буферизация, иначе эта фигня не "работает постоянно" а тупо жрет время в ожидании передачи байта. Проблема в том, что система постороена неправльно и никакими ASM тут ничем не поможешь.
Цитата
на ассемблер перейти не могу - его не знаю

И Си тоже sad.gif


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Jul 24 2009, 14:30
Сообщение #6


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



я что-то не пойму. Вы не успеваете отправлять со скоростью 115200?

В функции особо ускорять нечего. Она просто сует байты УАРТу и ждет, пока они отошлются. Если она не успевает их слать - возможно у вас какие-то "долгоиграющие" прерывания работают...

Цитата(zltigo @ Jul 24 2009, 18:27) *
Вот именно по этой причине и нужны ПРЕРЫВАНИЯ или,как минимум буферизация, иначе эта фигня не "работает постоянно" а тупо жрет время в ожидании передачи байта. Проблема в том, что система постороена неправльно и никакими ASM тут ничем не поможешь.


Дык у топикстартера в главном цикле только эта функция и работает... А остальное, как я понял, в прерываниях. Если и эту функциональность перетащить в прерывания - разве получится какой-то выигрыш?
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jul 24 2009, 14:37
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(Непомнящий Евгений @ Jul 24 2009, 17:30) *
Дык у топикстартера в главном цикле только эта функция и работает... А остальное, как я понял, в прерываниях.

Очень сильно сомневаюсь:
Цитата
// Бесконечный цикл с приемом данных и передачей по RS232

нет там прерываний. Совсем.
Moderator:
Тему перенес.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Палыч
сообщение Jul 24 2009, 15:05
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Цитата(Leonmezon @ Jul 24 2009, 14:12) *
... но необходимо ускорить ее выполнения ...
Если в посылках данных есть перебои, которые возникают не от того что буфер с данными не готов, то проблема, скорее всего, не в приведённом Вами коде, а в большом времени работы процедур обработки прерываний в которых эти данные готовятся. Если время работы процедуры прерывания превышает время передачи одного байта, то буферный регистр и регистр сдвига USART могут быть опустошены, и передача прекратится до выхода из прерывания...
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 24 2009, 15:52
Сообщение #9


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Перерыва в передачи байтов нет (данные принимаются на микроЭВМ, но хочу создать запас между посылками: сейчас примерно прием 400 мс, ожидае 600 мс - хочу увеличить время ожидания 800 мс и соотвественно за 200 мс все передовать) - простоя думаю как укорить этот процесс, чтобы был больший запас времени (физически скорость увеличить нельзя - 115200 бит/с - это максимум что может atmega), возможно можно увеличить скорость программно (т.е. уменьшить время между посылками). Весь алгоритм не привожу - так как неделю потрачу на его объяснение (сам струдом понимаю как его умудрился написать и при этом все работает).


Само прерывание (причем таких три - от трех АЦП обрабатываются последовательно - сигнал RDY - обединен и заводиться на INT6):
CODE
/ Функция получения данных от 1-го АЦП
// Запускается только в том случае если прием разрешен,
// и от АЦП пришел сигнал аппаратный о готовности данных - линия RDY
signed long uzmerenie1(void)
{
unsigned int reg;
unsigned long A, B, C;
signed long rez;
signed long K;
double U;
//Чтение регистра ADC Status
PORTF&=~BIT(0); // CS1 установить в 0 - выбор 1 АЦП
delay();
SpiWriteByte(0x04+0x40);
reg=SpiReadByte();
// Выбор канала готовых данных (аппаратно RDY дает сигнал только о готовности данных,без указания канала
switch (reg)
{
case 0x01:
{
// Установка чтение 0 канала данных
//Устанавливаем регистр для чтения - выходные данные 24 бит - 3 байта
SpiWriteByte(0x08+0x40);
K=K11;
}
break;
case 0x04:
{
// Установка чтение 1 канала данных
//Устанавливаем регистр для чтения - выходные данные 24 бит - 3 байта
SpiWriteByte(0x0A+0x40);
K=K12;
}
break;
default: { return (0x00);}
}
//Чтение данных из регистра АЦП
// Читаем и заносим в буфер
SPDR = 0x00;
while (!(SPSR&0x80)); // ожидание готовности порта, прежде чем считывать
A=SPDR; //считать SPDR - 1 байт
SPDR = 0x00;
while (!(SPSR&0x80)); // ожидание готовности порта, прежде чем считывать
B=SPDR; //считать SPDR - 2 байт
SPDR = 0x00;
while (!(SPSR&0x80)); // ожидание готовности порта, прежде чем считывать
C=SPDR; //считать SPDR - 3 байт
// Закрываем АЦП
PORTF|=BIT(0); // CS1 установить в 1
// Получаем длиное целое из полученных байт
// с учетом что первым идет старший байт
rez=(C+(B<<8)+(A<<16));
// Далее преобразуем с типу double и Преобразуем к напряжению
U=(((double)(rez))*20)/Kd; // Получаем напряжение от 0 до 20 В
// Отнимаем 10 В - для сдига в биполярный сигнал - получаем изменение напряжения от -10 до 10В
U=U-10;
U=U*KU;
// Преобразуем в микровольты и возращаем результат
rez=(signed long)(U*1000000);
rez=rez-K;
return (rez);
}
Причина редактирования: Оформление цитаты исходника.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jul 24 2009, 15:59
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Оптимизацию советую начать отсюда:
Код
U=(((double)(rez))*20)/Kd; // Получаем напряжение от 0 до 20 В

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

Ускорить void RS232(void) не получится - если он не отрабатывает за 200 с небольшим миллисекунд при скорости UART 115200, значит ему мешают тормозные прерывания.

P.S. Пожалуйста, пользуйтесь тегами [сode][/сode], иначе вашу программу просто никто не станет читать.
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jul 24 2009, 16:03
Сообщение #11


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(Leonmezon @ Jul 24 2009, 19:52) *
физически скорость увеличить нельзя - 115200 бит/с - это максимум что может atmega

Ну и кто вам сказал такую ерунду?

Как делитель установите, так и будет передавать.


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 24 2009, 16:12
Сообщение #12


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(aaarrr @ Jul 24 2009, 19:59) *
Оптимизацию советую начать отсюда:
Код
U=(((double)(rez))*20)/Kd; // Получаем напряжение от 0 до 20 В

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

Ускорить void RS232(void) не получится - если он не отрабатывает за 200 с небольшим миллисекунд при скорости UART 115200, значит ему мешают тормозные прерывания.

P.S. Пожалуйста, пользуйтесь тегами [сode][/сode], иначе вашу программу просто никто не станет читать.

А как? Не совсем понятно чем можно заменить (данные на ЭВМ должны идти уже в напряжении).
Значения коээфициентов: (боле понятно будет)
const signed int K11=-831; // программный учет смещения в 1 канале 1 АЦП вычисляеться на ЭВМ за 1 час
const signed int K12=-999; // программный учет смещения в 2 канале 1 АЦП вычисляеться на ЭВМ за 1 час
const double KU=1; // коэффициент передачи сигнала в аналоговой части 1.077
const double Kd=16777215; // длина всего диапазона для +-10В - 0xFFFFFF
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jul 24 2009, 16:16
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Leonmezon @ Jul 24 2009, 20:12) *
А как? Не совсем понятно чем можно заменить (данные на ЭВМ должны идти уже в напряжении).

Заменить целочисленными операциями. Как - подумайте, арифметика у вас элементарная и уж точно не требует 64-х битной плавающей запятой.
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jul 24 2009, 16:24
Сообщение #14


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(Leonmezon @ Jul 24 2009, 20:12) *
А как?

U=(((double)(rez))*20)/Kd; // Получаем напряжение от 0 до 20 В
rez=(signed long)(U*1000000);

Ну, как минимум, заменить 3 операции умножения / деления одной
Либо двумя, но без плавучки

U=(((long long)rez)*20000000)/Kd;

А вообще, уже писали.
Подход неверный вкорне.

Работа с UARTом должна происходить по прерываниям в фоне, а в это время обсчитывается следующий пакет.


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 24 2009, 17:02
Сообщение #15


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(MrYuran @ Jul 24 2009, 20:24) *
U=(((double)(rez))*20)/Kd; // Получаем напряжение от 0 до 20 В
rez=(signed long)(U*1000000);

Ну, как минимум, заменить 3 операции умножения / деления одной
Либо двумя, но без плавучки

U=(((long long)rez)*20000000)/Kd;

А вообще, уже писали.
Подход неверный вкорне.

Работа с UARTом должна происходить по прерываниям в фоне, а в это время обсчитывается следующий пакет.

Просчитал - не получить, я ограничен возможностями компилятора ( максим на тип signed long - 4 байта), а для работы в чисто целочисленном (без использования плавующей точки - (плавующая то же 4 байтная)) - надо 8 байт. Компилятор - менять не буду!
Может конструкция switch {} заменить на if? (здесь можно что то выиграть)
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jul 24 2009, 17:22
Сообщение #16


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Leonmezon @ Jul 24 2009, 21:02) *
Просчитал - не получить, я ограничен возможностями компилятора ( максим на тип signed long - 4 байта), а для работы в чисто целочисленном (без использования плавующей точки - (плавующая то же 4 байтная)) - надо 8 байт. Компилятор - менять не буду!

Вы ограничены не компилятором, а собственным воображением. У компилятора, наверное, есть тип long long.
Но это все равно не поможет, если сначала делить на 16777215, а затем умножать на 1000000. С таким подходом никакой разрядности не хватит,
надо менять образ мышления.

Цитата(Leonmezon @ Jul 24 2009, 21:02) *
Может конструкция switch {} заменить на if? (здесь можно что то выиграть)

По сравнению с остальным это такая мелочь, что не выйграете ровным счетом ничего.
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 24 2009, 17:44
Сообщение #17


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(aaarrr @ Jul 24 2009, 21:22) *
Вы ограничены не компилятором, а собственным воображением. У компилятора, наверное, есть тип long long.
Но это все равно не поможет, если сначала делить на 16777215, а затем умножать на 1000000. С таким подходом никакой разрядности не хватит,
надо менять образ мышления.


По сравнению с остальным это такая мелочь, что не выйграете ровным счетом ничего.

Причем здесь мышление не совсем понятно, код в целочисленном виде я могу записать вот так (чтобы не было точно double!!!).
Код
rez=((rez*215540000)/16777215)-107700000;
// где при максимальном rez=0xFFFFFF - получим в первой скобке число 3616160921100000=0xCD8E113271EE0 - 8байт
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jul 24 2009, 18:05
Сообщение #18


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Да не нужно заниматься ерундой и делить на 16777215! В самом начале Вы получаете 24-х битное число, так и работайте дальше с ним.
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 24 2009, 18:14
Сообщение #19


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(aaarrr @ Jul 24 2009, 22:05) *
Да не нужно заниматься ерундой и делить на 16777215! В самом начале Вы получаете 24-х битное число, так и работайте дальше с ним.

Как я могу обойтись без деления, если мне необходимо перевести из коды АЦП в напряжение??? Весь диапазон: 20 В - или 0xFFFFFF в кодах, используя простое правило пропрции - получаем искомое, как можно еще иначе? (причем если значения коэффициентов: масштабного и учет смещения в Вольтах).
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jul 24 2009, 18:40
Сообщение #20


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Деление на 16777215 и умножение на 20000000 эквивалентно умножению 1.1921. В целых числах делается умножением и сдвигом.
Коэффициенты пересчитайте отдельно.
Go to the top of the page
 
+Quote Post
rezident
сообщение Jul 24 2009, 18:41
Сообщение #21


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Leonmezon @ Jul 25 2009, 00:14) *
Как я могу обойтись без деления, если мне необходимо перевести из коды АЦП в напряжение???
Вы огласите сначала, с какой точностью вам нужно проводить измерения?
А то мучаетесь тут с каким-то микровольтами и 24-разрядным результатом измерения АЦП, а требуется, допустим, 0,1% относительная приведенная погрешность. Для этого при диапазоне входных напряжений -10В...+10В достаточно измерять с разрешением (10В-(-10В))/(0,1%*100)<=20мВ скажем 1мВ. Для представления напряжения с точностью 1мВ в указанном диапазоне вполне достаточно 16-и разрядного знакового числа. И соответственно типа long вполне хватит для всех вычислений.
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 24 2009, 18:58
Сообщение #22


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(aaarrr @ Jul 24 2009, 22:40) *
Деление на 16777215 и умножение на 20000000 эквивалентно умножению 1.1921. В целых числах делается умножением и сдвигом.
Коэффициенты пересчитайте отдельно.

1. Для меня это сложно! Умножать на 1,1921 со сдвигом. (точнее правильно с масштабом 1,077 умножить надо на К=1,283884124987371265135482855766 чтобы использовать уменьшению формулу:
rez=(rez*К)-107700000;

2. Точность необходима полная - все 24 разряда.
Go to the top of the page
 
+Quote Post
rezident
сообщение Jul 24 2009, 19:02
Сообщение #23


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Leonmezon @ Jul 25 2009, 00:58) *
2. Точность необходима полная - все 24 разряда.
Ерунду написали. АЦП измеряет напряжение. Напряжение принято выражать в Вольтах. С какой относительной погрешностью (в процентах) и в каком диапазоне напряжений (в Вольтах) вам нужно проводить измерения?
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 24 2009, 19:10
Сообщение #24


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(rezident @ Jul 24 2009, 23:02) *
Ерунду написали. АЦП измеряет напряжение. Напряжение принято выражать в Вольтах. С какой относительной погрешностью (в процентах) и в каком диапазоне напряжений (в Вольтах) вам нужно проводить измерения?

Повторюсь - 24 разряда АЦП или +- 10 В с максимальной точностью что дает АЦП (по заявленным характеристикам без ухищрений +- 150 мкВ).
Go to the top of the page
 
+Quote Post
rezident
сообщение Jul 24 2009, 19:25
Сообщение #25


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Leonmezon @ Jul 25 2009, 01:10) *
Повторюсь - 24 разряда АЦП или +- 10 В с максимальной точностью что дает АЦП (по заявленным характеристикам без ухищрений +- 150 мкВ).
150мкВ при опоре 2,5В (или 1,25В?) это уже никак не "все 24 разряда". Плюс потеря точности на делителе/преобразователе, который приводит диапазон -10В...+10В ко входному 2,5В(1,25В). В результате относительная точность измерения входного напряжения скорее всего не лучше 0,01%. Но вы конечно же можете продолжать использовать "все 24-разряда" для вычислений. laughing.gif
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 24 2009, 19:52
Сообщение #26


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(rezident @ Jul 24 2009, 23:25) *
150мкВ при опоре 2,5В (или 1,25В?) это уже никак не "все 24 разряда". Плюс потеря точности на делителе/преобразователе, который приводит диапазон -10В...+10В ко входному 2,5В(1,25В). В результате относительная точность измерения входного напряжения скорее всего не лучше 0,01%. Но вы конечно же можете продолжать использовать "все 24-разряда" для вычислений. laughing.gif

Вы не правы! Для начала посмотрите даташит на АЦП (AD7732) где при ИОН 2,5 В за счет внутренних резисторов !!!!!!! (выполненых с точность не менее 0.006 %) и получаеться заявленная мною неустойчивость, так что реально необходимы все разряды АЦП без округления.
Между прочим - я просил код помочь оптимизировать на быстродействие - а не рассказыват о точности АЦП - в любом случае Ваши знания не точнее информации из даташита!
Go to the top of the page
 
+Quote Post
Kuzmi4
сообщение Jul 24 2009, 21:11
Сообщение #27


Гуру
******

Группа: Свой
Сообщений: 3 304
Регистрация: 13-02-07
Из: 55°55′5″ 37°52′16″
Пользователь №: 25 329



2 Leonmezon - откройте секрет laughing.gif - что вы там такое меряете и самое главное НА КАКОМ ЖЕЛЕЗЕ ? А то чтоб 2.5 вольта и чтоб все 24 разряда были точно значащие...

пЫсЫ..
Цитата
компилятор менять не буду!
+ 100 biggrin.gif
Go to the top of the page
 
+Quote Post
mdmitry
сообщение Jul 24 2009, 21:44
Сообщение #28


Начинающий профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 25-10-06
Из: СПб
Пользователь №: 21 648



На семинаре AD по АЦП специалисты компании утверждали, что получить точность 12 разрядов можно без особых ухищрений, 16 требуются смемотехнические решения, а 24 разряда ОЧЕНЬ сложная задача. А у Вас наводка на плату без экрана не будет больше цены младшего разаряда АЦП? wink.gif


--------------------
Наука изощряет ум; ученье вострит память. Козьма Прутков
Go to the top of the page
 
+Quote Post
x736C
сообщение Jul 25 2009, 03:25
Сообщение #29


Профессионал
*****

Группа: Участник
Сообщений: 1 273
Регистрация: 3-03-06
Пользователь №: 14 942



Цена деления 1,2 мкВ при точности ±150 мкВ.. unsure.gif

Кстати, вы, вероятно, ошиблись. В описании на AD7732 явно указано «% of FSR», а не процент от опорного. Получается около ±6 мВ.

По поводу оптимизации.
Посмотрите в таком направлении, может что и получится:
Думаю, не обязательно перемножать каждый раз то, что можно перемножить заранее.
«Используя простое правило пропорции», никто вас не обязывает брать крайние значения.

Например можно взять половину от hFFFFFF.

rez = (Kd - h7FFFFF) * (10^7*KU) / h7FFFFF
1. Вычитание со знаком;
2. Умножение (6 байт включая знак!).
3. Деление (фактически сдвиг на 7 бит с отбросом двух байт с сохранением знака).
Осталось одно умножение, которое, видимо, можно сделать заблаговременно (10^7 * Ka).
Погрешность у меня получилась ~1,2 мкВ при цене деления 1,2 мкВ.
Вам правильно указали, что надо определиться с точностью.
И тогда, может быть, выбрать еще более приятную всё ту же пропорцию.
Удачи.

Сообщение отредактировал x736C - Jul 25 2009, 03:34
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 25 2009, 16:24
Сообщение #30


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Если вот так записать код, насколько будет быстрее первоначального? (и что еще можно упростить, без применения ухишрений (типа сдвига...). И можно что то сделать с отниманием 1 (или она мало занимает кода).
Код
const signed int K11=-831; // программный учет смещения в 1 канале 1 АЦП
const signed int K12=-999; // программный учет смещения в 2 канале 1 АЦП
const double KU=10770000; // коэффициент передачи сигнала в аналоговой части 1.077 умноженный на 1000000х10
const double Kd=8388608; // половина всего диапазона для +-10В - 0xFFFFFF/2
.
.
// Функция получения данных от 1-го АЦП
signed long uzmerenie1(void)
{
.
.
.
   rez=(C+(B<<8)+(A<<16));
   /* Далее преобразуем с типу double и преобразуем к напряжению с упрощением операций,
   конечный результат: напряжение от -10 В до 10 В в микровольтах*/
   U=((double)(rez))/Kd;
   U=U-1;    // Отнимаем 1  - для сдига в биполярный сигнал
   rez=(signed long)(U*KU);  // Изменяем масштаб и преобразуем в микровольты и возращаем результат
   rez=rez-K; //Учитываем смещение в каждом из каналов АЦП: 1К -  К11; 2К- К12
   return (rez);
}


Сообщение отредактировал Leonmezon - Jul 25 2009, 16:26
Go to the top of the page
 
+Quote Post
x736C
сообщение Jul 25 2009, 16:54
Сообщение #31


Профессионал
*****

Группа: Участник
Сообщений: 1 273
Регистрация: 3-03-06
Пользователь №: 14 942



Я написал просто деление. Дальше в скобках уточнил, что процедура деления в вашем случае достаточно быстрая.
Не надо рассматривать это, как ухищрение.
Не приводите перед делением rez к типу double. У вас абсолютно целочисленное деление на (2^23 - 1).
Все в signed long.

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

Цитата(Leonmezon @ Jul 25 2009, 20:24) *
И можно что то сделать с отниманием 1 (или она мало занимает кода).

Думаю, что это не тот случай, чтоб оптимизировать вычитание единицы. Оставьте так smile.gif

Сообщение отредактировал x736C - Jul 25 2009, 16:57
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 25 2009, 17:01
Сообщение #32


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(x736C @ Jul 25 2009, 20:48) *
Я написал просто деление. Дальше в скобках уточнил, что процедура деления в вашем случае достаточно быстрая.
Не надо рассматривать это, как ухищрение.
Не переводите перед делением rez к типу double. У вас абсолютно целочисленное деление на (2^23 - 1).
Все в signed long.

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

1. По времени - попробую на работ- напишу. (Хотя тяжело точно отследить - примерно будет только).
2. В целочисленных нельзя (правда я не уверен - как на самом деле будет происходить преобразования типов: сначала результат, потом преобразование или нет): U=rez/Kd - если rez и Kd целочисленные - то результат будет 0 при rez<Kd?
3. Частота 14,... МГц - хотя сейчас думаю перевести на Xmega - с частотой 14,...х2 = 28,.. МГц (в теме Xmega писал уже)
4. В принципе и сейчас все работает (и очень хорошо),но появился датчик (с собственным шумом 300 нВ) и для работы с ним планирую сделать запас времени, чтобы сняв 200 выборок за 1 сек прогнать через простой режекторный цифровой фильтр в микроконтроллере (повысить точность измерений) - для этого и еще как бы выиграть еще время, т.е. перед отправкой буфера (2400 байт) по RS232 успеть 200-300 мс прогнать через фильтр. (Фильтр пишу не я - человек на них собаку съел - но просит запас по времени на работу фильтра)
Go to the top of the page
 
+Quote Post
x736C
сообщение Jul 25 2009, 17:28
Сообщение #33


Профессионал
*****

Группа: Участник
Сообщений: 1 273
Регистрация: 3-03-06
Пользователь №: 14 942



1. Как оцениваете время выполнения функции? Симулятор не может посчитать?
2. Результат будет правильным. Типы менять туда-сюда не надо в вашем случае.
3. 28 — огромная частота smile.gif
4.1. Если вы поверите в прерывания, то сможете многое выполнять параллельно. Например, работать с данными и отсылать их одновременно, выполняя что-то третье.
4.2. 200-300 мс — огромное время smile.gif
4.3. 1 сек — cranky.gif

«..200 выборок за 1 сек прогнать через...»
«...успеть 200-300 мс прогнать через...»
Сколько в итоге?

Если не секрет, какого рода данные с датчика? Что-то периодичное? Почему такие точности?


P. S. Неужели ассемблер окончательно отмирает unsure.gif

Сообщение отредактировал x736C - Jul 25 2009, 17:29
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 25 2009, 18:19
Сообщение #34


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(x736C @ Jul 25 2009, 21:28) *
1. Как оцениваете время выполнения функции? Симулятор не может посчитать?
2. Результат будет правильным. Типы менять туда-сюда не надо в вашем случае.
3. 28 — огромная частота smile.gif
4.1. Если вы поверите в прерывания, то сможете многое выполнять параллельно. Например, работать с данными и отсылать их одновременно, выполняя что-то третье.
4.2. 200-300 мс — огромное время smile.gif
4.3. 1 сек — cranky.gif

«..200 выборок за 1 сек прогнать через...»
«...успеть 200-300 мс прогнать через...»
Сколько в итоге?

Если не секрет, какого рода данные с датчика? Что-то периодичное? Почему такие точности?


P. S. Неужели ассемблер окончательно отмирает unsure.gif

1. Я и на симулятор не могу дома (компилятор не компилирует код - только до 4 кБ - а у меня больше - на работе - лицензия - тогда и проверю).
2. Насчет типов - проверю.
3. 28 - это не много.
4.1. На прерывания - нельзя, ввиду того что на прерываниях сидят 3 АЦП, плюс прерывание синхронизации от GPS.
4.2. Не очень верно написал: по внешнему такту, а запускаю 3 АЦП на оцифровку данных - с частотой 200 Гц - получаю за 1 сек - 600 значений (три канала) и останавливаюсь на 10 мкс, приходит новый такт и процесс повторяться по АЦП, при этом данные принятые за предыдущею секунду передаются по RS232 (надо успеть до нового такта). Т.е. получаем трехканальную систему синхронной оцифровки которая работает с задержкой во времени на 1 сек. (Заказчика устраивает).
4.3. Датчик - сейсмодатчик, последний с динамическим диапазоном 145 дБ (но самый верх можно не мерять - но выше 9 балов по шкале Рихтера можно не мерять...)
5. На ассемблере - это тяжка написать, если только не критические функции...
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jul 25 2009, 18:23
Сообщение #35


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(x736C @ Jul 25 2009, 21:28) *
2. Результат будет правильным. Типы менять туда-сюда не надо в вашем случае.

Не будет.

Цитата(x736C @ Jul 25 2009, 21:28) *
P. S. Неужели ассемблер окончательно отмирает unsure.gif

Ну и причем тут ассемблер?

2 Leonmezon:

Во-первых, 24-х значащих бит у Вас не будет никогда, просто примите это как данность. Во-вторых сдвиг является не "ухищрением",
а нормальным методом деления и умножения на степень двойки. И освойте тип long long.

Получите что-то типа:
Код
const signed int K11=-831; // программный учет смещения в 1 канале 1 АЦП
const signed int K12=-999; // программный учет смещения в 2 канале 1 АЦП
const long KU=10770000; // коэффициент передачи сигнала в аналоговой части 1.077 умноженный на 1000000х10
const double Kd=8388608; // половина всего диапазона для +-10В - 0xFFFFFF/2
.
.
// Функция получения данных от 1-го АЦП
signed long uzmerenie1(void)
{
   long long U;
.
.
.
   U=(C+(B<<8)+(A<<16));
   U -= Kd; // Отнимаем 1  - для сдига в биполярный сигнал
   rez = (U * KU) >> 23; // Изменяем масштаб и преобразуем в микровольты и возращаем результат
   rez=rez-K; //Учитываем смещение в каждом из каналов АЦП: 1К -  К11; 2К- К12
   return (rez);

Хотя и это дикий маразм, т.к. я уверен, что и 1.077 и (10000000 / 8388608) можно упихать в один восьмибитный коэффициент,
оставшись при этом в пределах 32-х битной арифметики, безо всякого ущерба для конечного результата.
Go to the top of the page
 
+Quote Post
x736C
сообщение Jul 25 2009, 18:43
Сообщение #36


Профессионал
*****

Группа: Участник
Сообщений: 1 273
Регистрация: 3-03-06
Пользователь №: 14 942



Цитата(aaarrr @ Jul 25 2009, 22:23) *
Не будет.

Ну и причем тут ассемблер?


То есть поделить signed long на signed long нельзя? Каким будет результат при отрицательном значении делимого?
Не знал этого, спасибо за замечание.

По поводу ассемблера имел в виду не то, что надо все и вся на нем писать,
а то что иногда надо понимать то, что выполняет Си-комплилятор, понимая процесс чуть глубже.
Опыт использования ассемблера в этом смысле только плюс.
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 25 2009, 18:43
Сообщение #37


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



long long - длиное целое 8 байтовое?
( Если да, то у меня только до 4 байт).
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jul 25 2009, 18:48
Сообщение #38


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(x736C @ Jul 25 2009, 22:43) *
То есть поделить signed long на signed long нельзя? Каким будет результат при отрицательном значении делимого?
Не знал этого, спасибо за замечание.

Можно, конечно. Просто нет смысла делить, условно говоря, 12345 на 123456.

Цитата(Leonmezon @ Jul 25 2009, 22:43) *
long long - длиное целое 8 байтовое?
( Если да, то у меня только до 4 байт).

Уверены? И double тоже 32-х битный?
Go to the top of the page
 
+Quote Post
x736C
сообщение Jul 25 2009, 19:02
Сообщение #39


Профессионал
*****

Группа: Участник
Сообщений: 1 273
Регистрация: 3-03-06
Пользователь №: 14 942



Вы сначала написали, что результат не будет корректным.
«Нет смысла делить» и «результат не будет правильным» — это разное.

Смысле ваших слов («12345 на 123456») не понял. Лучше бы вы сказали не условно, а по существу.
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 25 2009, 19:11
Сообщение #40


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(aaarrr @ Jul 25 2009, 22:48) *
Можно, конечно. Просто нет смысла делить, условно говоря, 12345 на 123456.


Уверены? И double тоже 32-х битный?

Да; long, float, double - 4 байтовые. Компилятор ICC AVR 7.22 STD. Я често не знаю, но только вроде в IAR есть long long 8 байт.

По делению как раз понятно (я еще вчера об этом говорил) 12345/123456= 0 в целочисленном вычеслении.

Сообщение отредактировал Leonmezon - Jul 25 2009, 19:13
Go to the top of the page
 
+Quote Post
x736C
сообщение Jul 25 2009, 19:24
Сообщение #41


Профессионал
*****

Группа: Участник
Сообщений: 1 273
Регистрация: 3-03-06
Пользователь №: 14 942



Цитата(Leonmezon @ Jul 25 2009, 23:11) *
По делению как раз понятно (я еще вчера об этом говорил) 12345/123456= 0 в целочисленном вычеслении.

Понял, что имел в виду aaarrr.

В целочисленном исчислении нет знака?
-1234567/123456= 0 ?
Все зависит от компилятора, конечно.

Такая («12345/123456») ситуация, как привел aaarrr, когда делимое меньше делителя,
в приведенной мной последовательности вычислений не возникает никогда.

Сообщение отредактировал x736C - Jul 25 2009, 19:27
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 25 2009, 19:41
Сообщение #42


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(x736C @ Jul 25 2009, 23:24) *
Понял, что имел в виду aaarrr.

В целочисленном исчислении нет знака?
-1234567/123456= 0 ?
Все зависит от компилятора, конечно.

Такая («12345/123456») ситуация, как привел aaarrr, когда делимое меньше делителя,
в приведенной мной последовательности вычислений не возникает никогда.

Нет, может быть: рассуждения относяться к формуле U=((double)(rez))/Kd; - чтоб она правильно работала rez - надо перевести в double.
rez может быть от 0 до 0хFFFFFF, а Kd=0х800000
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jul 25 2009, 19:44
Сообщение #43


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(x736C @ Jul 25 2009, 23:24) *
Такая («12345/123456») ситуация, как привел aaarrr, когда делимое меньше делителя,
в приведенной мной последовательности вычислений не возникает никогда.

Дык мы же не про вашу последовательность говорили, а про это:

Цитата(x736C @ Jul 25 2009, 20:54) *
Не приводите перед делением rez к типу double. У вас абсолютно целочисленное деление на (2^23 - 1).
Все в signed long.

Ладно, не важно, если long long все равно нет.

2 Leonmezon:
Тогда оставьте в плавучке одно умножение, а еще лучше поручите все вычисления принимающей стороне.
Go to the top of the page
 
+Quote Post
x736C
сообщение Jul 25 2009, 20:02
Сообщение #44


Профессионал
*****

Группа: Участник
Сообщений: 1 273
Регистрация: 3-03-06
Пользователь №: 14 942



Понятно. Запутался слегка.

Из Kd можно убрать лишнюю единичку, на точность не влияет.


Код
Kd = 0x7FFFFF
   U=U-Kd;    // Отнимаем Kd  - для сдвига в биполярный сигнал
   rez=(signed long)(U*KU);  // Изменяем масштаб и преобразуем в микровольты и возвращаем результат
   U=((signed long)(rez))/Kd;

   rez=rez-K; //Учитываем смещение в каждом из каналов АЦП: 1К -  К11; 2К- К12
   return (rez);

А так?

Сообщение отредактировал x736C - Jul 25 2009, 20:11
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 25 2009, 20:21
Сообщение #45


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(aaarrr @ Jul 25 2009, 23:44) *
Дык мы же не про вашу последовательность говорили, а про это:


Ладно, не важно, если long long все равно нет.

2 Leonmezon:
Тогда оставьте в плавучке одно умножение, а еще лучше поручите все вычисления принимающей стороне.

Принимающей стороне нельзя (там программа должна быть абсолютно одинаковая в 50 комплектах).
Оставлю одно операцию с double.
Возможно только в будущем (зимой) получиться перейти на целочисленную математику, я списывался с ImageCraft - они наняли програмистов под Xmega (пишут генератор кода,примеры..., какие утилиты - возможно и добавять новые типы данных, сейчас есть только double 8 байтный профессиональной версии, но он не решает задачи). (да обязательно требование от заказчика - лицензия, а на IAR перейти - не вариант, дорого).
Спасибо за подсказки.

Цитата(x736C @ Jul 26 2009, 00:02) *
Понятно. Запутался слегка.

Из Kd можно убрать лишнюю единичку, на точность не влияет.


Код
Kd = 0x7FFFFF
   U=U-Kd;    // Отнимаем Kd  - для сдвига в биполярный сигнал
   rez=(signed long)(U*KU);  // Изменяем масштаб и преобразуем в микровольты и возвращаем результат
   U=((signed long)(rez))/Kd;

   rez=rez-K; //Учитываем смещение в каждом из каналов АЦП: 1К -  К11; 2К- К12
   return (rez);

А так?

Не получиться, необходмо 6 байт в rez=(signed long)(U*KU); , а есть только 4! (При максимальном значении 10 и -10 В).
Ладно, как не крути - 1 с плавующей умножени все равно необходимо. (В любом случае лучше чем 4!).
Go to the top of the page
 
+Quote Post
x736C
сообщение Jul 25 2009, 20:45
Сообщение #46


Профессионал
*****

Группа: Участник
Сообщений: 1 273
Регистрация: 3-03-06
Пользователь №: 14 942



Понятно. Это как раз то, чего я не мог понять в диалоге между вами и aaarrr.
Ну удачи вам.
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 27 2009, 10:45
Сообщение #47


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(x736C @ Jul 26 2009, 00:45) *
Понятно. Это как раз то, чего я не мог понять в диалоге между вами и aaarrr.
Ну удачи вам.


Время исполнения кода (в симуляторе) снизилось на 31%. (Много времени занимает деление - попробую и его убрать, на сдвиг).
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jul 27 2009, 13:07
Сообщение #48


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Leonmezon @ Jul 27 2009, 14:45) *
Время исполнения кода (в симуляторе) снизилось на 31%. (Много времени занимает деление - попробую и его убрать, на сдвиг).

А зачем Вы его (деление) вообще оставили?
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 27 2009, 16:18
Сообщение #49


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(aaarrr @ Jul 27 2009, 17:07) *
А зачем Вы его (деление) вообще оставили?

Согласен, деление увеличивает время исполнения в 2 раза:
Начальный вариант: - 2976 циклов;
Мой вариант - 2021 циклов;
Ваш вариант (без деления но в double) - 1000 циклов, впорос в константе KK сколько знаков после запятой оставлять? И второй Kd - может быть тип long - это как то влияет на размер кода (теоретически)?
Вот тестовый файл:
Код
//ICC-AVR application builder : 27.07.2009 20:16:20
// Target : M640
// Crystal: 14.7456Mhz

#include <iom640v.h>
#include <macros.h>

void main(void)
{
   unsigned long A, B, C;
   signed long rez;
   double U, KU, Kd, KK;
   A=128;
   B=25;
   C=55;

// Начальный вариант
   rez=(C+(B<<8)+(A<<16));
   KU=1.077;
   U=(((double)(rez))*20)/0xFFFFFF; // Получаем напряжение от 0 до 20 В
   // Отнимаем 10 В - для сдига в биполярный сигнал - получаем изменение напряжения от -10 до 10В
   U=U-10;
   U=U*KU;
   // Преобразуем в микровольты и возращаем результат
   rez=(signed long)(U*1000000);
    
// Мой вариант
   KU=10770000;
   Kd=8388608;  
    U=(C+(B<<8)+(A<<16));
   // Далее преобразуем с типу double и Преобразуем к напряжению
   U=U/Kd;
   U=U-1;    // Отнимаем 1  - для сдига в биполярный сигнал
   rez=(signed long)(U*KU);  // Изменяем масштаб и преобразуем в микровольты и возращаем результат
  
  
   // Предложенный вариант
  KU=10770000;
  Kd=8388608;
  KK=1.2838840484619140625; // KK=KU/Kd
   U=(C+(B<<8)+(A<<16));
   U -= Kd; // Отнимаем 0x800000  - для сдига в биполярный сигнал
   rez = (signed long)(U*KK); // Изменяем масштаб и преобразуем в микровольты и возращаем результат
  
  while(1)
{;}
  }
Go to the top of the page
 
+Quote Post
rezident
сообщение Jul 27 2009, 17:11
Сообщение #50


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Leonmezon @ Jul 27 2009, 22:18) *
Вот тестовый файл:
А вы только кол-во циклов сравнивали или результат тоже? В смысле, что программа правильно (или хотя бы одинаково smile.gif ) считает всеми способами? А то могу подсказать где кроется потенциальная ошибка. Константы отличные (отличающиеся) от типа int (от диапазона переменной типа int на данной архитектуре, в данном компиляторе) следует обозначать явным образом.
типа unsigned int - 32769U
типа long int - 12345678L
типа unsigned long int - 12345678UL
типа long long int - 1234567890LL
типа unsigned long long int - 1234567890ULL
типа float - 1.234567f В противном случае вот здесь константа в формате double может подставляться и вас спасаетвыручает только то, что float и double в вашем компиляторе одинаковой размерности (32 бита).
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 27 2009, 17:39
Сообщение #51


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(rezident @ Jul 27 2009, 21:11) *
А вы только кол-во циклов сравнивали или результат тоже? В смысле, что программа правильно (или хотя бы одинаково smile.gif ) считает всеми способами? А то могу подсказать где кроется потенциальная ошибка. Константы отличные (отличающиеся) от типа int (от диапазона переменной типа int на данной архитектуре, в данном компиляторе) следует обозначать явным образом.
типа unsigned int - 32769U
типа long int - 12345678L
типа unsigned long int - 12345678UL
типа long long int - 1234567890LL
типа unsigned long long int - 1234567890ULL
типа float - 1.234567f В противном случае вот здесь константа в формате double может подставляться и вас спасаетвыручает только то, что float и double в вашем компиляторе одинаковой размерности (32 бита).

1. Результат проверил - одинаковый, с точностью до 1 еденицы числа (т.е. если в первом случае 12345678 то во втором и третьем (одинаково) 12345678 или 12345677 - иногда меняеться на 1 еденицу конечный результат - а это +-1 мкВ - меньше чем мзр. АЦП)
2. ImageCraft не требует указания явного обозначения констант, достаточно указать тип переменной и ее значение. (Да и не понимает он таких указаний - я попробывал, препроцессор дает ошибку).
3. Да только в тестовом я так записал константы: реально они пишуться как глобальные константы перед main() - пока ошибок небыло.
Код
const double Kd=8388608;


Сообщение отредактировал Leonmezon - Jul 27 2009, 17:46
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jul 27 2009, 18:01
Сообщение #52


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Leonmezon @ Jul 27 2009, 20:18) *
впорос в константе KK сколько знаков после запятой оставлять?

Вам должно быть виднее. На сколько, например, 1.077 отражает реальность? Я бы не стал писать больше пяти.

Цитата(Leonmezon @ Jul 27 2009, 20:18) *
И второй Kd - может быть тип long - это как то влияет на размер кода (теоретически)?

Логично сначала вычесть в целых числах, затем умножить с плавающей запятой.

Код
  Kd=8388608;
  KK=1.2838840484619140625; // KK=KU/Kd
  rez=(C+(B<<8)+(A<<16));
  U = rez - Kd; // Отнимаем 0x800000  - для сдига в биполярный сигнал
  rez = (signed long)(U*KK); // Изменяем масштаб и преобразуем в микровольты и возращаем результат
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 27 2009, 20:12
Сообщение #53


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(aaarrr @ Jul 27 2009, 22:01) *
Вам должно быть виднее. На сколько, например, 1.077 отражает реальность? Я бы не стал писать больше пяти.


Логично сначала вычесть в целых числах, затем умножить с плавающей запятой.

Код
  Kd=8388608;
  KK=1.2838840484619140625; // KK=KU/Kd
  rez=(C+(B<<8)+(A<<16));
  U = rez - Kd; // Отнимаем 0x800000  - для сдвига в биполярный сигнал
  rez = (signed long)(U*KK); // Изменяем масштаб и преобразуем в микровольты и возвращаем результат

1. 1,077 отражает разброс С2-29 резисторов в входный аналоговых цепях - расчетное естественно, думаю есть смысл ограничиться 7 знаками (на время не все равно не влияет)
2. Логичнее, да и время выполнения уменьшаться на 21%.
Спасибо.

И все таки хотелось вернуться к первоначальному вопросу:
можно ли уменьшить время выполнения (естественно без учета ожидания флага от UART) кода преобразования и отправки байт по порту в функции void RS232(void) ? (Фактически можно ли как по другому long разбить на 4 байта с большей скоростью и тем же результатам (чтоб не переписывать программу на ЭВМ).

Сообщение отредактировал Leonmezon - Jul 27 2009, 20:16
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jul 27 2009, 20:15
Сообщение #54


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Leonmezon @ Jul 28 2009, 00:12) *
И все таки хотелось вернуться к первоначальному вопросу:
можно ли уменьшить время выполнения (естественно без учета ожидания флага от UART) кода преобразования и отправки байт по порту в функции void RS232(void) ? (Фактически можно ли как по другому long разбить на 4 байта с большей скоростью и тем же результатам (чтоб не переписывать программу на ЭВМ).

По сравнению со временем ожидания флага все остальные расходы пренебрежимо малы. Фактически более 95% процессорного времени в этой процедуре пускается на ветер.
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 27 2009, 20:19
Сообщение #55


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(aaarrr @ Jul 28 2009, 00:15) *
По сравнению со временем ожидания флага все остальные расходы пренебрежимо малы.

Да, но пока я жду флаг - работают другие функции (в первую очередь прием новых данных): т.е. я имею ввиду что, написать функциию так, чтобы время ее выполнения равнялось фактически время ожидание флага умноженое на количество переданных байт (близко конечно).
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jul 27 2009, 20:26
Сообщение #56


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Leonmezon @ Jul 28 2009, 00:19) *
т.е. я имею ввиду что, написать функциию так, чтобы время ее выполнения равнялось фактически время ожидание флага умноженое на количество переданных байт (близко конечно).

По сравнению с тем временем, что Вы уже отыграли на сокращении вычислений, это 0.

Ну, модифицируйте цикл в передаче, полкопейки может быть выйграете:
Код
     for(i=0; i<600; i++)
     {
        long d = B1[i];

        UDR0 = (unsigned char)d;
        while (!(UCSR0A & (1<<UDRE0)));
        UDR0 = (unsigned char)(d >> 8);
        while (!(UCSR0A & (1<<UDRE0)));
        UDR0 = (unsigned char)(d >> 16);
        while (!(UCSR0A & (1<<UDRE0)));
        UDR0 = (unsigned char)(d >> 24);
        while (!(UCSR0A & (1<<UDRE0)));
     }
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 27 2009, 20:54
Сообщение #57


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(aaarrr @ Jul 28 2009, 00:26) *
По сравнению с тем временем, что Вы уже отыграли на сокращении вычислений, это 0.

Ну, модифицируйте цикл в передаче, полкопейки может быть выйграете:

Нет, выиграша нет (сдвиг на 24 требует почти 200 циклов).
А если немного переиначить вопрос: весь проект планируеться перевести на Xmega -в нем за счет DMA возможно будет получить выигреш ? Не сильно меняя при этом логику работы программы.
Причина редактирования: Излишнее цитирование.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jul 27 2009, 20:58
Сообщение #58


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Leonmezon @ Jul 28 2009, 00:54) *
Нет, выиграша нет (сдвиг на 24 требует почти 200 циклов).

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

Цитата(Leonmezon @ Jul 28 2009, 00:54) *
А если немного переиначить вопрос: весь проект планируеться перевести на Xmega -в нем за счет DMA возможно будет получить выигреш ? Не сильно меняя при этом логику работы программы.

Ровным счетом то же самое Вы можете получить и сейчас, если перенесете работу с UART на прерывания.
Go to the top of the page
 
+Quote Post
rezident
сообщение Jul 28 2009, 16:01
Сообщение #59


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Leonmezon @ Jul 27 2009, 23:39) *
3. Да только в тестовом я так записал константы: реально они пишуться как глобальные константы перед main() - пока ошибок небыло.
Код
const double Kd=8388608;
Если вы объявляете их как инициализированные константы, то да, указывать не нужно. Т.к. тип этих констант вы уже определили. А вот если бы вы вдруг воспользовались командами препроцессора
Код
#define Kd 8388608
то грабли бы сработали в полный рост. laughing.gif
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 28 2009, 16:24
Сообщение #60


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(rezident @ Jul 28 2009, 20:01) *
Если вы объявляете их как инициализированные константы, то да, указывать не нужно. Т.к. тип этих констант вы уже определили. А вот если бы вы вдруг воспользовались командами препроцессора
Код
#define Kd 8388608
то грабли бы сработали в полный рост. laughing.gif

Не сработали biggrin.gif , я не люблю #define - через полгода сам не поймешь что писал. (А выдел я таких писателей - переименовывают названия порта чтоб легче - а потом куча вопросов че да как).
Лучше ответить на вопросов - DMA в Xmega может реально ускорить выполнения функции отправки байт (хотя массив с данными и так в ОЗУ находиться) - т.е. делать пересылку автоматом (я запустил и все пока не закончатся).


Цитата(aaarrr @ Jul 28 2009, 00:58) *
Что-то слабо верится, что компилятор настолько туп. Сдвиг на 24 - это просто взять нужный байт. Или оптимизация выключена?


Ровным счетом то же самое Вы можете получить и сейчас, если перенесете работу с UART на прерывания.

Оптимизация выключена (не могу обновить свою версию компилятора на расширенную) - так что нечего удивительного.

Сообщение отредактировал Leonmezon - Jul 28 2009, 16:25
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jul 28 2009, 16:26
Сообщение #61


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Leonmezon @ Jul 28 2009, 20:24) *
Лучше ответить на вопросов - DMA в Xmega может реально ускорить выполнения функции отправки байт (хотя массив с данными и так в ОЗУ находиться) - т.е. делать пересылку автоматом (я запустил и все пока не закончатся).

Выбросьте из процедуры отправки все ожидания флага UART, и подсчитайте симулятором, что останется.
Еще раз говорю: это 0, ловить тут абсолютно нечего.
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 28 2009, 16:39
Сообщение #62


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(aaarrr @ Jul 28 2009, 20:26) *
Выбросьте из процедуры отправки все ожидания флага UART, и подсчитайте симулятором, что останется.
Еще раз говорю: это 0, ловить тут абсолютно нечего.

Я уже это сделал, но на переключенния задач все равно уходит время, а так его можно было бы уменьшить. И второе: думаю добавить простой цифровой фильтр: (режекторный готов - но он огромен для МК (на первый взгляд): необходимо перемножать массив на матрицу коэффициентов - явно могу не уложиться в 200-300 мс ) и второй - попробовать использовать медианный фильтр (может получиться меньше). Хотя этот вопрос еще требует проработки - какой из двух вариантов имеет наименьшую фазовую нелинейность.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jul 28 2009, 16:47
Сообщение #63


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



А может, взять нормальные средства (можно и бесплатные) и, возможно, контроллер помощнее? На AVR и ICC свет клином не сошелся, как это ни странно.
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 28 2009, 16:57
Сообщение #64


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(aaarrr @ Jul 28 2009, 20:47) *
А может, взять нормальные средства (можно и бесплатные) и, возможно, контроллер помощнее? На AVR и ICC свет клином не сошелся, как это ни странно.

AVR не хочеться без нужды менять (тем более я его использую процентов на 20-30), думаю возможностей Xmega должно хватить на простой цифровой фильтр.
ICC сейчас меняю на новую версию с оптимизацией (кода и глобальной), но пока ну очень трудно обяснить нашему дистрибьютеру что хочу - у них человек уволился, а нового кто сображает пока нет - радует что еще и макетки не готовы по Xmega.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jul 28 2009, 17:07
Сообщение #65


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Leonmezon @ Jul 28 2009, 20:57) *
AVR не хочеться без нужды менять (тем более я его использую процентов на 20-30), думаю возможностей Xmega должно хватить на простой цифровой фильтр.

Поменять AVR на XMega и поменять на что-то другое (дешевле и лучше, ага) - по-моему, принципиальной разницы по трудозатратам нет.
Go to the top of the page
 
+Quote Post
Rst7
сообщение Jul 28 2009, 17:14
Сообщение #66


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Цитата
На AVR и ICC свет клином не сошелся, как это ни странно.


Особенно на ICC

Кстати, адептам целочисленных вычислений хотелось бы напомнить, что правильное умножение float*float практически эквивалентно перемножению long*long. В реализации для процессоров, не имеющих аппаратного деления (AVR в их числе) деление float'ов и long'ов тоже несильно отличается. О(1), не побоимся этого слова.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
Leonmezon
сообщение Jul 28 2009, 17:35
Сообщение #67


Частый гость
**

Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686



Цитата(aaarrr @ Jul 28 2009, 21:07) *
Поменять AVR на XMega и поменять на что-то другое (дешевле и лучше, ага) - по-моему, принципиальной разницы по трудозатратам нет.

Зато есть финансовая разница! (Уже сейчас по Xmega есть все для начала работы (кроме макеток конечно - но я уже писал, это не просто макетка - на ней будет все чтобы сделать готовое изделие (то же направление)).
Основным сдерживающим фактором перехода на другой МК - это требования заказчика (по направлению измерения сейсмосигналов) - НИ какой цифровой обработки!!! (Не знаю, согласиться на простой фильтр или нет - а то может зря код оптимизировали). А без цифры - AVR за глаза хватает.
Да и переход на Xmega - вообще то довольно таки не трудный (DMA я и так не знаю в любом МК -все равно изучать, а шифрование - мне даром не нужно - специфика применения устройства) - остальные вопросы: АЦП, ЦАП, таймеры, порты, UART, SPI, прерывания, часы .... простые программы уже написал - жду железа чтоб пробовать. А большая часть кода - вообще не будет меняться при переходе.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Jul 28 2009, 23:47
Сообщение #68


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Rst7 @ Jul 28 2009, 21:14) *
Кстати, адептам целочисленных вычислений хотелось бы напомнить, что правильное умножение float*float практически эквивалентно перемножению long*long. В реализации для процессоров, не имеющих аппаратного деления (AVR в их числе) деление float'ов и long'ов тоже несильно отличается. О(1), не побоимся этого слова.

Зато появляется некоторый оверхед на перегнать туда-назад.

Цитата(Leonmezon @ Jul 28 2009, 21:35) *
Основным сдерживающим фактором перехода на другой МК - это требования заказчика (по направлению измерения сейсмосигналов) - НИ какой цифровой обработки!!!

Это, скорее, не сдерживающий фактор smile.gif
Просто колупаться с обкоцанным ICC - это как-то уж совсем не комильфо.
Go to the top of the page
 
+Quote Post
defunct
сообщение Jul 29 2009, 00:18
Сообщение #69


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(Leonmezon @ Jul 25 2009, 19:24) *
Если вот так записать код, насколько будет быстрее первоначального?

Думаю что ни на сколько.
На мой взгляд основной тормоз у вас это блокировка отпраки данных длинным обработчиком INT6 (SPI +вычисления).

Если переделать алгоритм работы программы, а именно.

1. передачу по UART сделать по прерыванию.
2. Int6 сделать максимально возможно коротким - только взводить флажек готовности считывания АЦП.
3. Всю галиматью, с вычислениями и считыванием данных с АЦП через SPI, переместить в основной цикл программы. Выполнять ее тогда когда флажек готовности считывать АЦП установлен, после чего сбрасывать этот флажек.

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

Цитата(Leonmezon @ Jul 27 2009, 19:18) *
Начальный вариант: - 2976 циклов;
Мой вариант - 2021 циклов;

Даже начальный вариант с 2971 циклов, с лихвой годится для обработки любого тормозного сигма-дельта АЦП.
Банальная арифметка.
У Вас 3 АЦП, пусть 1KSPS, тогда всего циклов нужно:
2971 * 3 * 1000 = 8.913M

т.е. если будете тактировать МК частотой 14.7456Mhz, МК должен простаивать ~50% времени, даже в первоначальном варианте.
У вас же я так понимаю вообще 500SPS. Если же имеют место тормоза, проблема не в нехватке ресурса, не в проце и не в компиляторе, а неправильном распределении ресурса. (программа построена неверно).
Go to the top of the page
 
+Quote Post

5 страниц V   1 2 3 > » 
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 02:04
Рейтинг@Mail.ru


Страница сгенерированна за 0.02289 секунд с 7
ELECTRONIX ©2004-2016