|
|
  |
Скорость выполнения кода на atmega640 |
|
|
|
Jul 24 2009, 11:12
|
Частый гость
 
Группа: Участник
Сообщений: 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)) ) { }; } } } }
Причина редактирования: Оформление цитаты исходника.
|
|
|
|
|
Jul 24 2009, 14:17
|
Частый гость
 
Группа: Участник
Сообщений: 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(); } }
Причина редактирования: Оформление цитаты исходника.
|
|
|
|
|
Jul 24 2009, 14:27
|

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

|
Цитата(Leonmezon @ Jul 24 2009, 17:17)  2. Прерывания - нельзя - эта функция работает постоянно... Вот именно по этой причине и нужны ПРЕРЫВАНИЯ или,как минимум буферизация, иначе эта фигня не "работает постоянно" а тупо жрет время в ожидании передачи байта. Проблема в том, что система постороена неправльно и никакими ASM тут ничем не поможешь. Цитата на ассемблер перейти не могу - его не знаю И Си тоже
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jul 24 2009, 14:30
|
Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153

|
я что-то не пойму. Вы не успеваете отправлять со скоростью 115200? В функции особо ускорять нечего. Она просто сует байты УАРТу и ждет, пока они отошлются. Если она не успевает их слать - возможно у вас какие-то "долгоиграющие" прерывания работают... Цитата(zltigo @ Jul 24 2009, 18:27)  Вот именно по этой причине и нужны ПРЕРЫВАНИЯ или,как минимум буферизация, иначе эта фигня не "работает постоянно" а тупо жрет время в ожидании передачи байта. Проблема в том, что система постороена неправльно и никакими ASM тут ничем не поможешь. Дык у топикстартера в главном цикле только эта функция и работает... А остальное, как я понял, в прерываниях. Если и эту функциональность перетащить в прерывания - разве получится какой-то выигрыш?
|
|
|
|
|
Jul 24 2009, 14:37
|

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

|
Цитата(Непомнящий Евгений @ Jul 24 2009, 17:30)  Дык у топикстартера в главном цикле только эта функция и работает... А остальное, как я понял, в прерываниях. Очень сильно сомневаюсь: Цитата // Бесконечный цикл с приемом данных и передачей по RS232 нет там прерываний. Совсем. Moderator: Тему перенес.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jul 24 2009, 15:52
|
Частый гость
 
Группа: Участник
Сообщений: 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); }
Причина редактирования: Оформление цитаты исходника.
|
|
|
|
|
Jul 24 2009, 15:59
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Оптимизацию советую начать отсюда: Код U=(((double)(rez))*20)/Kd; // Получаем напряжение от 0 до 20 В Работа с длинной плавучкой в прерывании, мягко говоря, изрядно все затормозит. Ускорить void RS232(void) не получится - если он не отрабатывает за 200 с небольшим миллисекунд при скорости UART 115200, значит ему мешают тормозные прерывания. P.S. Пожалуйста, пользуйтесь тегами [сode][/сode], иначе вашу программу просто никто не станет читать.
|
|
|
|
|
Jul 24 2009, 16: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
|
|
|
|
|
Jul 24 2009, 16:24
|

Беспросветный оптимист
     
Группа: Свой
Сообщений: 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 =)
|
|
|
|
|
Jul 24 2009, 17:02
|
Частый гость
 
Группа: Участник
Сообщений: 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? (здесь можно что то выиграть)
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|