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

 
 
5 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> Скорость выполнения кода на 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
Непомнящий Евген...
сообщение 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

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

 


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


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