mills() на AVR Studio

Обсуждаем контроллеры компании Atmel.
Ответить
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Вс окт 30, 2016 14:11:16

Сообщение BIOS23 »

помогите разобратся, я плавно перехожу с ардуины на чистый С, и очень хотелось бы для своего удобства реализовать функцию millis которая возвращает текущее время со старта програмы как на ардуино. На просторах интернета наше библиотеку (спс добрым людям) но коректно работать отказывается на Атмеге8.
Вот что было в библиотеке:

Код: Выделить всё


#include "timers.h"

//------------------------------ function, for counting time-------------------------------//
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )

// Предделитель устанавливается таким образом, что timer0 тик каждые 64 тактов, а обработчик переполнения вызывается каждые 256 тиков.
#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))

// Целое число миллисекунд в переполнение TIMER0
#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)

// Дробное число миллисекунд на переполнение TIMER0. мы сдвиг вправо
// На три, чтобы соответствовать эти цифры в байт. (Для тактовой частоты мы заботимся
// О - 8 и 16 МГц - это не потеря точности).
#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
#define FRACT_MAX (1000 >> 3)

volatile unsigned long timer0_overflow_count = 0;
volatile unsigned long timer0_millis = 0;
static unsigned char timer0_fract = 0;

ISR(TIMER0_OVF_vect) 
{
	timer0_millis += 1;
	timer0_fract += 3;
	if (timer0_fract >= 125) 
	{
		timer0_fract -= 125;
		timer0_millis += 1;
	}
	timer0_overflow_count++;
}


unsigned long millis(void)
{
	unsigned long m;
	uint8_t oldSREG = SREG;

// Запретить прерывания в то время как мы читаем timer0_millis или мы могли бы получить
// Несовместимым значение (например, в середине записи в timer0_millis)
	cli();
	m = timer0_millis;
	SREG = oldSREG;

	return m;
}

void timer0_Init(void)
{
	TCCR0 = (1<<CS00)|(1<<CS01);				// делитель таймера 64
	TIMSK = (1<<TOIE0);						// включаем прерывание при переполнении
}
//---------------------------------------millis function end--------------------------------------//

Код: Выделить всё


#ifndef TIMERS_H
#define TIMERS_H
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
#include <inttypes.h>

void timer0_Init(void);
unsigned long millis(void);

#endif //TIMERS_H

пред функцией Main() нужно инициализировать настройки таймера 1 вызвав timer0_Init(); а потом в главном цикле дергать millis() которая должна вернуть текущее время, но у меня она возвращает постоянно значение 0.
помогите пожалуйста, так как из выше приведенного кода я понимаю лиш процентов 70%

Добавлено after 6 hours 20 minutes 16 seconds:
помогите пожалуйста, как вы реализуете отсчет времени?
Реклама
Электрический кот
Аватара пользователя
Сообщения: 1031
Зарегистрирован: Чт июн 20, 2013 00:00:58
Откуда: москва, м.Сходненская

Сообщение Mishany »

В начале проги надо дописать
#define F_CPU частота мкUL
Реклама
Модератор
Аватара пользователя
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

BIOS23 писал(а):я плавно перехожу с ардуины на чистый С
Теперь, самое время настало плавно переходить на чтение документаций и выкинуть из головы метод тыка.
BIOS23 писал(а):как вы реализуете отсчет времени?
Таймерами. Курим доку на используемый камушек.
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Вс окт 30, 2016 14:11:16

Сообщение BIOS23 »

у меня есть
#define F_CPU 1000000 // частота камня 1 Mhz
Атмега 8, с заводскими настройками 1 Mhz ведь от внутреннего генератора (кварц не ставлю и фьюзы пока не трогал, стремно запороть, у меня пока что тольк один МК)
Реклама
Эиком - электронные компоненты и радиодетали
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение COKPOWEHEU »

А точно ли вам нужно время с момента старта программы? Для чего вы его используете?
Реклама
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Вс окт 30, 2016 14:11:16

Сообщение BIOS23 »

мне бы хотелось иметь универсальную функцию которую можно было бы дергать и узнавать время. Тогда можно было бы использовать вот такую удобную конструкцию:

Код: Выделить всё

 if (millis() < Timer) Timer = millis();

if ((millis() - Timer) >= (long) Delay * 1000 )
{
    Timer = millis();

// выполняем код

}



это с ардуины осталось, очень привычно и удобно.
я конечно понимаю что каждый тик дергать millis несовсем этично, но в простеньких проэктах очень удобно и не заморочливо.

Добавлено after 4 hours 19 minutes 8 seconds:
протестировав код пришел к выводу что не вызывается вектор прерывания
ISR(TIMER0_OVF_vect)
в чем может быть проблема, кто ни буть может подсказать ?
Реклама
Электрический кот
Аватара пользователя
Сообщения: 1031
Зарегистрирован: Чт июн 20, 2013 00:00:58
Откуда: москва, м.Сходненская

Сообщение Mishany »

А это нормально спрашивать где что не работает, если даже текст программы выложить не в состоянии?
Нам тут самим еще надо придумывать что вы там понаписали и почему это не работает?
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Вс окт 30, 2016 14:11:16

Сообщение BIOS23 »

я выложил текст в первом посте.

дело движется! ISR(TIMER0_OVF_vect) вызывается отлично, нужно было разрешить глобальные прерывания: sei();

но теперь остался вопрос с частотой камня или делителем таймера 0 что бы настроить реальное время.
Как точно можно узнать на какой частоте работает атмега8 с заводскими настройками? так как фюзы я не трогал и побаиваюсь трогать :) подозреваю что 1Mhz, но хотелось бы быть уверенным.

Добавлено after 1 hour 4 minutes 41 second:
нашел информацию:
- микроконтроллер AVR ATmega-8 при поставке с завода работает на тактовой частоте 0,91—1,1 МГц;

Подробнее здесь: http://www.ruselectronic.com/news/chita ... e-atmega8/

теперь буду думать как высчитать точно время, что бы millis() возвращала 1000 миллисекунд за 1000 миллисекунд (1сек).
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение COKPOWEHEU »

Да поставьте уже кварц! Если не хотите возиться с фузами - часовой, на 32768 Гц и на асинхронном таймере считайте точное время.
Частота дефолтного генератора вроде настроена с точностью 1% при комнатной температуре и 3% по всему диапазону. Правда, не уверен, возможно требуется программная калибровка по записанным в память константам.
Уточнил по даташиту. По умолчанию настроено именно на 1 МГц, поигравшись с OSCCAL можно подстроить в пределах указанного вами диапазона.
Последний раз редактировалось COKPOWEHEU Вс ноя 20, 2016 09:56:35, всего редактировалось 1 раз.
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Вс окт 30, 2016 14:11:16

Сообщение BIOS23 »

для меня пока что точность не обязательно, мне главное придумать удобный алгоритм что бы можно было в виде библиотеки преносить с камня на камень.
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение COKPOWEHEU »

Прикиньте для начала целесообразность. Глобальный отсчет времени лично мне пригодился всего пару раз. Куда чаще нужен вызов процедуры с заданным интервалом (обработка клавиатуры, хотя бы) или фиксированная задержка.
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Вс окт 30, 2016 14:11:16

Сообщение BIOS23 »

в своей практике мне очень часто нужно выполнять действие по истечении интервала времени.
ну на данный момент мне нужно сделать регулируемую задержку по времени, регулировать можно потенциометром время задержки. В програме будет повторятся дейсвие в цыкле по истечении выставленого времени потенциометром. До этого я использовал millis() которая возвращает время со старта програмы в Ардуино. Удобней для себя нечего не нашел по качто, может вы что подскажете.
Используя вот такую конструкцию:

Код: Выделить всё


if (millis() < Timer) Timer = millis();

if ((millis() - Timer) >= (long) Delay * 1000 )
{
    Timer = millis();

// выполняем код

}

Электрический кот
Аватара пользователя
Сообщения: 1031
Зарегистрирован: Чт июн 20, 2013 00:00:58
Откуда: москва, м.Сходненская

Сообщение Mishany »

Выложил в первом посте?
В упор не вижу
у меня есть
#define F_CPU 1000000 // частота камня 1 Mhz
В каком месте то это у тебя есть? Наверное там же где и нехватало sei();
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Вс окт 30, 2016 14:11:16

Сообщение BIOS23 »

в первом посте есть код из 2х файлов (которые я нашел на просторах инета),
файл timer.c - содержит тело методов реалезации функции millis(),
и файл timer.h - выступает в роли интерфейса как я понял.

ну и допустим тело моей програмы в файле myProgram.c

Код: Выделить всё


#define F_CPU 1000000 // частота камня 1 Mhz (микроконтроллер AVR ATmega-8 при поставке с завода работает на тактовой частоте 0,91—1,1 МГц;  http://www.ruselectronic.com/news/chitaem-datashit-na-primere-atmega8/)

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

void Setup()
{
	timer0_Init(); // инициализируем таймер ноль для подщета времени
	
 sei(); // разрешить глобальные прерывания
		
	_delay_ms(100);
}



int main(void)
{
	Setup();	
		
    while(1)
    {
        if (millis() >= 3000) 
        {
             // выполним чего ни буть спустя 3 сек после включения МК
         }

    }
}
Модератор
Аватара пользователя
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

При таком раскладе, файлу timer.c будет неведомо задефайненное F_CPU в файле myProgram.c. Очень странно, что вообще что-то скомпилировалось.
Вероятнее всего, где-то в глобальной области висит эта переменная, передаваемая самой IDE. Нужно смотреть настройки, чтобы убедиться в этом.
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Вс окт 30, 2016 14:11:16

Сообщение BIOS23 »

я постарался разобраться, и как по мне то вот этот код незадействован походу вообще

Код: Выделить всё


#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )

// Предделитель устанавливается таким образом, что timer0 тик каждые 64 тактов, а обработчик переполнения вызывается каждые 256 тиков.
#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))

// Целое число миллисекунд в переполнение TIMER0
#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)

// Дробное число миллисекунд на переполнение TIMER0. мы сдвиг вправо
// На три, чтобы соответствовать эти цифры в байт. (Для тактовой частоты мы заботимся
// О - 8 и 16 МГц - это не потеря точности).
#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
#define FRACT_MAX (1000 >> 3)



потому и скомпилировалось
Модератор
Аватара пользователя
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

А, ну тогда - да. Если F_CPU не используется, то будет по-барабану на его отсутствие. Что логично :)
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1231
Зарегистрирован: Ср янв 29, 2014 08:41:31
Откуда: Баку

Сообщение Zhuk72 »

Эти ардуины... :kill:
BIOS23 писал(а):в своей практике мне очень часто нужно выполнять действие по истечении интервала времени.
Для этого совершенно не нужно считать время от старта. Достаточно завести таймер на время, подходящее для всех процедур, и в прерывании щелкать счетчиками. Скажем, каждое прерывание нужно опрашивать какой-то вход, каждое пятое прерывание опрашивать кнопку, каждое восьмое мигать светодиодом и т.д. Вот на все эти "каждое n-ное прерывание" заведите счетчики и в прерывании делайте

Код: Выделить всё

    if (xxx_cnt) xxx_cnt--;    // счетчик до начала xxx процедуры
      else xxx_start = 1;    // флаг запуска xxx процедуры
А в основном цикле проверяйте флаги и при их активности очищайте, затем опять заправляйте счетчик и делайте xxx процедуру.

P.S. Код выше можно записать в сокращенном виде, но так понятнее.
Каждый имеет право на свое личное ошибочное мнение.

У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
Контактная информация:
Ответить

Вернуться в «AVR»