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

 
 
 
Reply to this topicStart new topic
> WinAVR, задержки > 250мс, Help, me!!!
Alex_NEMO
сообщение Nov 16 2008, 17:28
Сообщение #1


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

Группа: Свой
Сообщений: 106
Регистрация: 13-05-05
Пользователь №: 4 977



Помаленьку осваиваю AVR, пишу в WinAVR. Всякие простейшие "моргалки", вроде освоил, решил светофор сбацать. Вроде элементарно, но в

WinAVR столкнулся с проблемами с задержками > 250 ms.

Версия WinAVR - 20070525, все проверялось в Proteus 7.2SP6.
Вот, что получилось:
Код
//Электронный светофор, =AVR.
// cpu: ATMega8
// speed: 1 mhz

#include <avr/io.h>
#include <util/delay.h>

#define F_CPU 1000000UL

int main(void)  {        //Начало программы  

    // Инициализация портов
    PORTB=0x20;
    DDRB=0x1F;
    PORTC=0x00;
    DDRC=0x00;
    PORTD=0x00;
    DDRD=0x00;
        
    while (1) //Бесконечный цикл                                        
        {
            PORTB |= _BV(PB0);        // Уст. пин 0 порта B в "1" - вкл. красный
            PORTB |= _BV(PB3);        // Уст. пин 3 порта B в "1" - вкл. зеленый для пеших
            _delay_ms(250);        // Пауза 3 сек. - пока горит  красный
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            PORTB |= _BV(PB1);        // Уст. пин 1 порта B в "1"-  вкл. желтый
            _delay_ms(250);
            _delay_ms(250);
            PORTB &= ~_BV(PB0);        // Уст. пин 0 порта B в "0" - выкл. красный
            PORTB &= ~_BV(PB3);        // Уст. пин 3 порта B в "0" - выкл. зеленый для пеших
            _delay_ms(250);        // Пауза 1 сек. - пока горит  желтый
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            PORTB &= ~_BV(PB1);        // Уст. пин 1 порта B в "0"-  выкл. желтый
            PORTB |= _BV(PB2);        // Уст. пин 1 порта B в "1"-  вкл. зеленый
            PORTB |= _BV(PB4);        // Уст. пин 3 порта B в "1" - вкл. красный для пеших
            _delay_ms(250);        // Пауза 3.5 сек. - пока горит  зеленый
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            PORTB &= ~_BV(PB2);        // Уст. пин 2 порта B в "0"-  выкл. зеленый
            PORTB |= _BV(PB1);        // Уст. пин 1 порта B в "1"-  вкл. желтый
            PORTB &= ~_BV(PB4);        // Уст. пин 3 порта B в "0" - выкл. красный для пеших
            _delay_ms(250);        // Пауза 1 сек. - пока горит  желтый
            _delay_ms(250);
            _delay_ms(250);
            _delay_ms(250);
            PORTB &= ~_BV(PB1);        // Уст. пин 1 порта B в "0"-  выкл. желтый
        } //
}
Т.е., что бы получить требуемые задержки, как я думал, типа _delay_ms(3000), _delay_ms(1000) и _delay_ms(4500), прошлось делать "порно" в виде последовательных команд _delay_ms(250);
То же самое - в CVAVR - все ОК:
Код
/*****************************************************
Project : TrafficLights
Version : 1 alpha
Date    : 16.11.2008
Author  : Freeware, for evaluation and non-commercial use only
Chip type           : ATmega8
Program type        : Application
Clock frequency     : 8,000000 MHz
Memory model        : Small
External RAM size   : 0
Data Stack size     : 256
*****************************************************/

#include <mega8.h>
#include <delay.h>

void main(void)
{

// Input/Output Ports initialization
PORTB=0x20;
DDRB=0x1F;
PORTC=0x00;
DDRC=0x00;
PORTD=0x00;
DDRD=0x00;

while (1)
      {
      // Place your code here
      PORTB.0 = 1;        // Уст. пин 0 порта B в "1" - вкл. красный
      delay_ms(3000);        // Пауза 3 сек. - пока горит  красный
      PORTB.0 = 0;           // Уст. пин 0 порта B в "0" - выкл. красный
      PORTB.1 = 1;        // Уст. пин 1 порта B в "1"-  вкл. желтый
      delay_ms(1000);        // Пауза 1 сек. - пока горит  желтый
      PORTB.1 = 0;            // Уст. пин 1 порта B в "0"-  выкл. желтый
      PORTB.2 = 1;        // Уст. пин 1 порта B в "1"-  вкл. зеленый
      delay_ms(4500);        // Пауза 1 сек. - пока горит  зеленый
      PORTB.2 = 0;            // Уст. пин 2 порта B в "0"-  выкл. зеленый
      PORTB.1 = 1;        // Уст. пин 1 порта B в "1"-  вкл. желтый
      delay_ms(1000);        // Пауза 1 сек. - пока горит  желтый
      PORTB.1 = 0;            // Уст. пин 1 порта B в "0"-  выкл. желтый
      };
}

Здесь - все четко - в Preteus'е все переключается(правильные задержки) как надо!

В чем косяк в случае с WinAVR?!! Как решать проблему?!!
Go to the top of the page
 
+Quote Post
ReAl
сообщение Nov 16 2008, 21:41
Сообщение #2


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



1) почитать документацию на _delay_ms() используемой версии, увидеть в ограничение макс. времени в зависимости от частоты процессора
2) взять хоть немного более свежую версию (WinAVR-0071221 сгодится) - там упор уже в 6,5секунды независимо от частоты.
3) написать свою delay_msec(unsigned msec) { while(msec--) _delay_ms(1); }


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
Aesthete Animus
сообщение Nov 16 2008, 22:17
Сообщение #3


Местный
***

Группа: Свой
Сообщений: 222
Регистрация: 9-06-07
Пользователь №: 28 317



...
4) не использовать задержки
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Nov 17 2008, 00:37
Сообщение #4


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



5) А использовать таймеры и прерывания. И проц не вешается, и Вам с пользой - быстрее освоите потроха.
Go to the top of the page
 
+Quote Post
Alex_NEMO
сообщение Nov 17 2008, 13:01
Сообщение #5


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

Группа: Свой
Сообщений: 106
Регистрация: 13-05-05
Пользователь №: 4 977



Цитата(ReAl @ Nov 17 2008, 00:41) *
1) почитать документацию на _delay_ms() используемой версии, увидеть в ограничение макс. времени в зависимости от частоты процессора
2) взять хоть немного более свежую версию (WinAVR-0071221 сгодится) - там упор уже в 6,5секунды независимо от частоты.
3) написать свою delay_msec(unsigned msec) { while(msec--) _delay_ms(1); }

1) The maximal possible delay is 262.14 ms / F_CPU in MHz. Т.е. При тактовой 1МГц получим не более 262 мс всего.
2) ОК, попробую или предлагаемую 0071221 или последнюю доступную с оффсайта.
3) уже понял и пример нашел, и своя идея созрела, попробуем. Просто хотелось минимума кода.
Цитата(Aesthete Animus @ Nov 17 2008, 01:17) *
...
4) не использовать задержки

Каким образом, можно пример для моего случая?
Цитата(_Pasha @ Nov 17 2008, 03:37) *
5) А использовать таймеры и прерывания. И проц не вешается, и Вам с пользой - быстрее освоите потроха.

Была такая мысля, но я пока "чайник" - чуть попозже, как освою прерывания/таймеры/счетчики.
Go to the top of the page
 
+Quote Post
Aesthete Animus
сообщение Nov 17 2008, 14:52
Сообщение #6


Местный
***

Группа: Свой
Сообщений: 222
Регистрация: 9-06-07
Пользователь №: 28 317



Цитата(Alex_NEMO @ Nov 17 2008, 16:01) *
Каким образом, можно пример для моего случая?

Использовать таймеры - именно это я имел ввиду. Все остальное от лукавого.

[spoiler="Сделать можно например так"]
Код
#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint16_t timer_ms;

// Вызывается каждую милисекунду
SIGNAL(SIG_OUTPUT_COMPARE2)
{
    if (timer_ms) --timer_ms;
}

void inline delay_set(uint16_t ms)
{
    cli();
    timer_ms = ms;
    sei();
}

void inline delay_wait()
{
    while (timer_ms);
}


int main(void)
{
    // Предполагается, что F_CPU = 16МГц
    TCCR2 = (1 << WGM21)|(1 << CS22); // CTC режим, прескаллер 64
    OCR2 = 249;
    TIMSK = (1 << OCIE2);
    sei();

    delay_set(1024);
    delay_wait();

    for (;;) {}
    
}
[/spoiler]
Go to the top of the page
 
+Quote Post
Alex_NEMO
сообщение Nov 17 2008, 16:28
Сообщение #7


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

Группа: Свой
Сообщений: 106
Регистрация: 13-05-05
Пользователь №: 4 977



Цитата(Aesthete Animus @ Nov 17 2008, 17:52) *
Использовать таймеры - именно это я имел ввиду. Все остальное от лукавого.

Спасибо, бум разбираться/пробовать!
Go to the top of the page
 
+Quote Post
Alex_NEMO
сообщение Nov 18 2008, 15:54
Сообщение #8


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

Группа: Свой
Сообщений: 106
Регистрация: 13-05-05
Пользователь №: 4 977



Цитата(ReAl @ Nov 17 2008, 00:41) *
2) взять хоть немного более свежую версию (WinAVR-0071221 сгодится) - там упор уже в 6,5секунды независимо от частоты.

Да, установка WinAVR-20071221 - помогла, спасибо!
Ещё в ходе эксперементов родилась такая подпрограмка:
Код
float delay_s(float t)   {
uint8_t i, j;
   j = t * 100;
   for(i=0;i<j;i++)
   _delay_ms(10);
}

вызывал так: delay_s(5); или delay_s(3.5);
На глаз, все правильно считает!
Только один вопрс - при компиляции выскакивает один Warning: control reaches end of non-void function
- чем ему закрывающая скобка не нравится в моей ф-ции? Или это "особенности" компилера из разряда "странностей"?!! laughing.gif
Go to the top of the page
 
+Quote Post
Aesthete Animus
сообщение Nov 18 2008, 16:17
Сообщение #9


Местный
***

Группа: Свой
Сообщений: 222
Регистрация: 9-06-07
Пользователь №: 28 317



Цитата(Alex_NEMO @ Nov 18 2008, 18:54) *
Только один вопрс - при компиляции выскакивает один Warning: control reaches end of non-void function
- чем ему закрывающая скобка не нравится в моей ф-ции? Или это "особенности" компилера из разряда "странностей"?!! laughing.gif

..Потому что функция ваша имеет возращаемый тип (не void функция), но return-а в ней нет
А вообще, во-первых, не используйте числа с плавающей точкой без очень сильной на то необходимости. А во вторых, ну не поместится в однобайтовую переменную i число, скажем, 350!
Go to the top of the page
 
+Quote Post
Alex_NEMO
сообщение Nov 18 2008, 16:52
Сообщение #10


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

Группа: Свой
Сообщений: 106
Регистрация: 13-05-05
Пользователь №: 4 977



Цитата(Aesthete Animus @ Nov 18 2008, 19:17) *
..Потому что функция ваша имеет возращаемый тип (не void функция), но return-а в ней нет
А вообще, во-первых, не используйте числа с плавающей точкой без очень сильной на то необходимости. А во вторых, ну не поместится в однобайтовую переменную i число, скажем, 350!

Понял, спасибо за помощь, понял свои ошибки!
А float использовал только для "универсальности" (напр., для получения 3,5 сек.).
Итого, получилось:
Код
float delay_s(float t)   {
uint16_t i, j;
    j = t * 100;
   for(i=0;i<j;i++)
   _delay_ms(10);
    return 0;
}
Теперь - все ОК!
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Nov 18 2008, 18:04
Сообщение #11


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(Alex_NEMO @ Nov 18 2008, 20:52) *
А float использовал только для "универсальности" (напр., для получения 3,5 сек.).

Ну так и используйте uint32_t на крайняк - если даже использовать микросекундное (!) разрешение - получите больше часа максимальную задержку.
Стока не живут даже в коллайдере biggrin.gif
А плавучка - это же страшно ресурсоемко и медленно на данной архитектуре.
ЗЫ:
можно сразу идти дальше и завести себе тип timer_t, разрядность которого можно менять в зависимости от требований проекта.
Код
/*Нужное откомментить*/
// typedef uint8_t timer_t
// typedef uint16_t timer_t
// typedef uint32_t timer_t


А дальше - очень рекомендую написать это простенькое прерывание в посте Aesthete Animus и по аналогии - чтением тиков таймера можно управлять независимо несколькими десятками светофоров.
Go to the top of the page
 
+Quote Post
Aesthete Animus
сообщение Nov 18 2008, 18:22
Сообщение #12


Местный
***

Группа: Свой
Сообщений: 222
Регистрация: 9-06-07
Пользователь №: 28 317



2_Pasha
+1

А вообще, кто-то верно сказал, что Бог придумал только целые числа, все остальное придумал человек.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Nov 18 2008, 18:27
Сообщение #13


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Против uint32_t ничего не имею smile.gif
Однако плавучка тоже имеет право на жизнь (вкупе с uint16_t или uint32_t - не важно).
Дело в том, что если времена не передаются извне или вычисляются в программе, а жёстко заданы на момент компиляции, то всю плавучку можно спрятать в compile-time (собственно, util/delay.h так и делает).
Зато просто удобно писать плавающее число.

delay_s.h
Код
#ifndef DELAY_S_H
#define DELAY_S_H

#include <util/delay.h>

static inline void delay_s(float s)
{
    uint16_t i = s * 100;
    if(i) do _delay_ms(10); while(--i);
}
#endif


d.c
Код
#include "delay_s.h"

void foo()
{
    delay_s(3.5);
}


avr-gcc -Os -DF_CPU=8000000UL -mmcu=atmega48 d.c
Код
foo:
    ldi r18,lo8(350)  ; вот оно uint16_t i = s * 100 - две команды загрузки и всё
    ldi r19,hi8(350)
.L2:
    ldi r24,lo8(20000)
    ldi r25,hi8(20000)
/* #APP */
    1: sbiw r24,1
    brne 1b
/* #NOAPP */
    subi r18,lo8(-(-1))
    sbci r19,hi8(-(-1))
    brne .L2
    ret


Другое дело, что это же (и тоже с плавучкой) можно сделать и через задержку в циклах с макросом SEC_TO_CYCLES(), который принимает плавающее число, множит/делит c учётом F_CPU (всё во время компиляции!) и выдаёт uint16_t или uint32_t неких попугайных циклов, принимаемых нужной функцией.
Но это достаточно вкусовой вопрос.

p.s. Сам я первое, что пишу для новой платы - это таймерное прерывание, свободно бегущий таймер и отработку таймаутов ( ну это вот if(timeout) --timeout; как в приведенном примере прерывания), иногда таких таймаутов несколько для разных задач, какие-то в тиках, какие-то в уже секундах. Но "случаи бывают всякие" и я бы не стал с порога отвергать задержки по месту и аккуратно применённый float, который заканчивает свою жизнь в compile-time.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
Aesthete Animus
сообщение Nov 18 2008, 18:40
Сообщение #14


Местный
***

Группа: Свой
Сообщений: 222
Регистрация: 9-06-07
Пользователь №: 28 317



Цитата(ReAl @ Nov 18 2008, 21:27) *
Против uint32_t ничего не имею smile.gif
Однако плавучка тоже имеет право на жизнь (вкупе с uint16_t или uint32_t - не важно).

Но "случаи бывают всякие" и я бы не стал с порога отвергать задержки по месту и аккуратно применённый float, который заканчивает свою жизнь в compile-time.

Дадада smile.gif Согласен. Но только так - когда флоат существует только в исходнике. Любые попытки задавать длину задержки в рантайме приведут к неприятным последствиям.

Что касается задержек, то при всей моей неприязни к ним, я не знаю, как к примеру выдерживать интервалы для софтового 1-wire, кроме как с их помощью. Но и там они все задаются во время компиляции.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 21st July 2025 - 14:31
Рейтинг@Mail.ru


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