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

 
 
> 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
 
Start new topic
Ответов
ReAl
сообщение Nov 18 2008, 18:27
Сообщение #2


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

Группа: Свой
Сообщений: 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
Сообщение #3


Местный
***

Группа: Свой
Сообщений: 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 Текстовая версия Сейчас: 29th July 2025 - 17:48
Рейтинг@Mail.ru


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