|
Скорость выполнения кода на 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)) ) { }; } } } }
Причина редактирования: Оформление цитаты исходника.
|
|
|
|
|
 |
Ответов
(30 - 44)
|
Jul 25 2009, 16:54
|
Профессионал
    
Группа: Участник
Сообщений: 1 273
Регистрация: 3-03-06
Пользователь №: 14 942

|
Я написал просто деление. Дальше в скобках уточнил, что процедура деления в вашем случае достаточно быстрая. Не надо рассматривать это, как ухищрение. Не приводите перед делением rez к типу double. У вас абсолютно целочисленное деление на (2^23 - 1). Все в signed long.Напишите, пожалуйста, позже в теме, насколько уменьшилось время выполнения процедуры. Интересно. На какой частоте работает контроллер? Цитата(Leonmezon @ Jul 25 2009, 20:24)  И можно что то сделать с отниманием 1 (или она мало занимает кода). Думаю, что это не тот случай, чтоб оптимизировать вычитание единицы. Оставьте так
Сообщение отредактировал x736C - Jul 25 2009, 16:57
|
|
|
|
|
Jul 25 2009, 17:01
|
Частый гость
 
Группа: Участник
Сообщений: 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 мс прогнать через фильтр. (Фильтр пишу не я - человек на них собаку съел - но просит запас по времени на работу фильтра)
|
|
|
|
|
Jul 25 2009, 17:28
|
Профессионал
    
Группа: Участник
Сообщений: 1 273
Регистрация: 3-03-06
Пользователь №: 14 942

|
1. Как оцениваете время выполнения функции? Симулятор не может посчитать? 2. Результат будет правильным. Типы менять туда-сюда не надо в вашем случае. 3. 28 — огромная частота  4.1. Если вы поверите в прерывания, то сможете многое выполнять параллельно. Например, работать с данными и отсылать их одновременно, выполняя что-то третье. 4.2. 200-300 мс — огромное время  4.3. 1 сек — «..200 выборок за 1 сек прогнать через...» «...успеть 200-300 мс прогнать через...» Сколько в итоге? Если не секрет, какого рода данные с датчика? Что-то периодичное? Почему такие точности? P. S. Неужели ассемблер окончательно отмирает
Сообщение отредактировал x736C - Jul 25 2009, 17:29
|
|
|
|
|
Jul 25 2009, 18:19
|
Частый гость
 
Группа: Участник
Сообщений: 191
Регистрация: 11-02-09
Из: Краснодар
Пользователь №: 44 686

|
Цитата(x736C @ Jul 25 2009, 21:28)  1. Как оцениваете время выполнения функции? Симулятор не может посчитать? 2. Результат будет правильным. Типы менять туда-сюда не надо в вашем случае. 3. 28 — огромная частота  4.1. Если вы поверите в прерывания, то сможете многое выполнять параллельно. Например, работать с данными и отсылать их одновременно, выполняя что-то третье. 4.2. 200-300 мс — огромное время  4.3. 1 сек — «..200 выборок за 1 сек прогнать через...» «...успеть 200-300 мс прогнать через...» Сколько в итоге? Если не секрет, какого рода данные с датчика? Что-то периодичное? Почему такие точности? P. S. Неужели ассемблер окончательно отмирает  1. Я и на симулятор не могу дома (компилятор не компилирует код - только до 4 кБ - а у меня больше - на работе - лицензия - тогда и проверю). 2. Насчет типов - проверю. 3. 28 - это не много. 4.1. На прерывания - нельзя, ввиду того что на прерываниях сидят 3 АЦП, плюс прерывание синхронизации от GPS. 4.2. Не очень верно написал: по внешнему такту, а запускаю 3 АЦП на оцифровку данных - с частотой 200 Гц - получаю за 1 сек - 600 значений (три канала) и останавливаюсь на 10 мкс, приходит новый такт и процесс повторяться по АЦП, при этом данные принятые за предыдущею секунду передаются по RS232 (надо успеть до нового такта). Т.е. получаем трехканальную систему синхронной оцифровки которая работает с задержкой во времени на 1 сек. (Заказчика устраивает). 4.3. Датчик - сейсмодатчик, последний с динамическим диапазоном 145 дБ (но самый верх можно не мерять - но выше 9 балов по шкале Рихтера можно не мерять...) 5. На ассемблере - это тяжка написать, если только не критические функции...
|
|
|
|
|
Jul 25 2009, 18:23
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(x736C @ Jul 25 2009, 21:28)  2. Результат будет правильным. Типы менять туда-сюда не надо в вашем случае. Не будет. Цитата(x736C @ Jul 25 2009, 21:28)  P. S. Неужели ассемблер окончательно отмирает  Ну и причем тут ассемблер? 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-х битной арифметики, безо всякого ущерба для конечного результата.
|
|
|
|
|
Jul 25 2009, 18:43
|
Профессионал
    
Группа: Участник
Сообщений: 1 273
Регистрация: 3-03-06
Пользователь №: 14 942

|
Цитата(aaarrr @ Jul 25 2009, 22:23)  Не будет.
Ну и причем тут ассемблер? То есть поделить signed long на signed long нельзя? Каким будет результат при отрицательном значении делимого? Не знал этого, спасибо за замечание. По поводу ассемблера имел в виду не то, что надо все и вся на нем писать, а то что иногда надо понимать то, что выполняет Си-комплилятор, понимая процесс чуть глубже. Опыт использования ассемблера в этом смысле только плюс.
|
|
|
|
|
Jul 25 2009, 18:48
|
Гуру
     
Группа: Свой
Сообщений: 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-х битный?
|
|
|
|
|
Jul 25 2009, 19:11
|
Частый гость
 
Группа: Участник
Сообщений: 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
|
|
|
|
|
Jul 25 2009, 19:24
|
Профессионал
    
Группа: Участник
Сообщений: 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
|
|
|
|
|
Jul 25 2009, 19:41
|
Частый гость
 
Группа: Участник
Сообщений: 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
|
|
|
|
|
Jul 25 2009, 19:44
|
Гуру
     
Группа: Свой
Сообщений: 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: Тогда оставьте в плавучке одно умножение, а еще лучше поручите все вычисления принимающей стороне.
|
|
|
|
|
Jul 25 2009, 20:02
|
Профессионал
    
Группа: Участник
Сообщений: 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
|
|
|
|
|
Jul 25 2009, 20:21
|
Частый гость
 
Группа: Участник
Сообщений: 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!).
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|