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

 
 
> WinAVR, _delay_ms(), строки и оптимизация.
Laksus
сообщение Nov 5 2010, 19:17
Сообщение #1


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

Группа: Участник
Сообщений: 146
Регистрация: 16-05-05
Пользователь №: 5 069



Програмка для ATmega32, WinAVR-20100110.
Инициализируется USART для передачи.
После этого хочу отправить через USART несколько групп символов. С паузой между группами в несколько секунд.
Задержки решил сделать через _delay_ms(2000).

Оказалось, что если оптимизация "OPT = s", то правильно передается только последняя строка, а вместо остальных строк передается мусор. Насколько я понял указатель ставится на адрес ноль, а не на адрес строки.
Если отключить оптимизацию ("OPT = 0"), то все строки передаются правильно.

Если вместо _delay_ms() использую самодельную задержку delay_sec(uint8_t T){for..{for..{for..{for..{asm("nop")}}}}},
то все строки передаются нормально и при "OPT = s"

Большой проблемы нет, так как с самдельной задержкой вроде бы работает.
Но хотелось бы узнать причину, чтобы не получить проблем в дальнейшем.
_______
Как правильно использовать _delay_ms(), чтобы работало и при оптимизации?

Код
//код . . .

char *StringLCD;
char Hello_1[]= "11111111111111111111111111111111";
char Hello_2[]= "22222222222222222222222222222222";

//------------------------------------------------------
int main(void)
{
init();

UDR= Address_1;// пошлем адрес
StringLCD= Hello_1;
UCSRB|= (1<<UDRIE);//и отправим нужную строку
_delay_ms(2000);

UDR= Address_1;// пошлем адрес
StringLCD= Hello_2;
UCSRB|= (1<<UDRIE);//и отправим нужную строку
_delay_ms(2000);

for(;;);
return 0;
}
//------------------------------------------------------
ISR(USART_UDRE_vect)
{
    static uint8_t    j= 0;
    if(j< 32)
    {
        UDR= StringLCD[j++];
    }
    else
    {
        j=0;
        UCSRB&= ~(1<<UDRIE);
    }
}
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
artymen
сообщение Nov 5 2010, 19:46
Сообщение #2


Участник
*

Группа: Участник
Сообщений: 66
Регистрация: 6-11-09
Из: г. Омск
Пользователь №: 53 464



Функции из util/delay.h имеют одну пакость, из доков:
Цитата
Note:
In order for these functions to work as intended, compiler optimizations must be enabled, and the delay time must be an expression that is a known constant at compile-time. If these requirements are not met, the resulting delay will be much longer (and basically unpredictable), and applications that otherwise do not use floating-point calculations will experience severe code bloat by the floating-point library routines linked into the application.
При отключенной оптимизации ("OPT = 0") задержка получается бОльшей, чем надо, и более того, непредсказуемой.
А вообще похоже на то, что у вас первая строка не успевает передасться полностью к началу передачи второй. Либо скорость уарта настолько низкая, что двух секунд (даже болльше) не хватает, либо прерывания UDRE задерживает остальной код (другие прерывания, установка/снятие флага разрешения прерывания и т.п.). По-хорошему, так конечно не делается. Перед второй отправкой нужно дождаться завершения первой, например так:
Код
...
while (j != 0);
UDR= Address_1;// пошлем адрес
StringLCD= Hello_2;
...
, предварительно сделав j глобальной переменной.

Сообщение отредактировал artymen - Nov 5 2010, 19:51


--------------------
"Сознание своего несовершенства приближает к совершенству"
Гёте
Go to the top of the page
 
+Quote Post
Laksus
сообщение Nov 5 2010, 22:52
Сообщение #3


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

Группа: Участник
Сообщений: 146
Регистрация: 16-05-05
Пользователь №: 5 069



Цитата(artymen @ Nov 5 2010, 22:46) *
... похоже на то, что у вас первая строка не успевает передасться полностью к началу передачи второй. Либо скорость уарта настолько низкая, что двух секунд (даже болльше) не хватает, либо прерывания UDRE задерживает остальной код (другие прерывания, установка/снятие флага разрешения прерывания и т.п.). По-хорошему, так конечно не делается. Перед второй отправкой нужно дождаться завершения первой, например так: ...

Нет, скорость передачи 9600, это примерно один байт за миллисекунду. В группе 33 байта, итого порядка 33 мсек.
А пауза между группами 2000 мсек. Других прерываний кроме ISR(USART_UDRE_vect) нет, и другого кода тоже нет.
Я все убрал, чтобы выделить непонятный для меня глюк в чистом виде.

Попробовал ставить проверку глобального счетчика передаваемых байт while(j), а задержку уменьшил до 111 мсек.
Если ставлю задержку в виде for(..){.. for(..){ for(..) { asm("nop");}}}, то в реальном устройстве циферки мерехтят (100 пар групп, передается примерно за 30 сек), в симуляторе тоже все нормально.

А если меняю задержку на _delay_ms();, то в реальном идет в течении 30 сек мусор, а затем приходит последняя строка.

То есть каждая из предыдущих двухсот передач тоже состоит из 33 знаков идущих непрерывно, затем пауза 100 мсек, первый знак каждой группы == Address_1, так как я его шлю отдельно, а затем указателю StringLCD не присваивается значение нужной строки, а он остается равен нулю и с этого, нулевого, адреса забираются случайные байты для передачи.

Я не профессионал, ни в микроконтроллерах, ни в программировании. Время от времени делаю простенькие устройства для себя. Поэтому подозреваю, что где-то сморозил глупость, а где не пойму.

________________________
Цитата(Genadi Zawidowski @ Nov 5 2010, 22:48) *
У функции _delay_ms() есть ограничение на максимальное время задержки. Посмотрите её исходник (или заголовочный файл) - там это написано было.
цитата из "C:\WinAVR\avr\include\util\delay.h"
" The maximal possible delay is 262.14 ms / F_CPU in MHz.

When the user request delay which exceed the maximum possible one,
_delay_ms() provides a decreased resolution functionality. In this
mode _delay_ms() will work with a resolution of 1/10 ms, providing
delays up to 6.5535 seconds (independent from CPU frequency). The
user will not be informed about decreased resolution."

То есть до задержки 6,5 сек отрабатываются при любой частоте кварца.
Мне нужно 2...3 секунды. Так что вписываюсь в ограничение.
_______

Сообщение отредактировал Laksus - Nov 5 2010, 22:59
Go to the top of the page
 
+Quote Post
ASZ
сообщение Nov 5 2010, 23:09
Сообщение #4


Местный
***

Группа: Свой
Сообщений: 302
Регистрация: 24-07-06
Из: Донецк, Украина
Пользователь №: 19 042



Может, это снобизм, но принципиально не использую ф-цию _delay_ms().
Использую службу времени, организованную на одном из таймеров.
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- Laksus   WinAVR, _delay_ms(), строки и оптимизация.   Nov 5 2010, 19:17
- - Genadi Zawidowski   У функции _delay_ms() есть ограничение на максимал...   Nov 5 2010, 19:48
- - artymen   Посмотрите, укладывается ли полученный бинарник во...   Nov 6 2010, 05:12
|- - Сергей Борщ   Цитата(artymen @ Nov 6 2010, 08:12) GCC (...   Nov 6 2010, 06:44
|- - MrYuran   Цитата(Сергей Борщ @ Nov 6 2010, 09:44) К...   Nov 6 2010, 07:37
- - artymen   ЦитатаФигня полная. Прекрасно следит. А если у вас...   Nov 6 2010, 10:32
- - alexeyv   Маленькое замечание по поводу кода: КодUDR= Addre...   Nov 8 2010, 05:07
- - Сергей Борщ   Цитата(artymen @ Nov 6 2010, 12:32) Возмо...   Nov 8 2010, 09:08
|- - Laksus   Цитата(Сергей Борщ @ Nov 8 2010, 12:08) ....   Nov 8 2010, 22:16
||- - Qwertty   Цитата(Laksus @ Nov 9 2010, 02:16) Просто...   Nov 8 2010, 23:06
||- - Сергей Борщ   Цитата(Laksus @ Nov 9 2010, 00:16) ___ vo...   Nov 10 2010, 08:33
||- - Laksus   Цитата(Сергей Борщ @ Nov 10 2010, 11:33) ...   Nov 10 2010, 11:15
||- - Сергей Борщ   Цитата(Laksus @ Nov 10 2010, 13:15) но в ...   Nov 10 2010, 11:55
|- - alexeyv   Цитата(Сергей Борщ @ Nov 8 2010, 14:08) О...   Nov 9 2010, 04:23
- - Marian   При уровне оптимизации -Os, компилятор выкидывает ...   Nov 8 2010, 14:56


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

 


RSS Текстовая версия Сейчас: 3rd August 2025 - 15:10
Рейтинг@Mail.ru


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