Страница 41 из 72
Re: Таймеры/счётчики в AVR
Добавлено: Сб окт 14, 2017 09:19:18
akl
fulky писал(а):сделать по вектору TIMER1_COMPA и через сравнение с OCR1A??
Да. Правда непонятно зачем задействовать ещё одно прерывание.
Как записать в ваших кыржиках не знаю, но сделал бы так
Код: Выделить всё
F_CPU=8000000
OCR0A=250*F_CPU/1000000/8-1; задание 250мкс интервала
T_HOUR=3600*1000000/250
T_MIN=60*1000000/250
T_SEC=1000000/250
T1=HOUR1*T_HOUR+MIN1*T_MIN+SEC1*T_SEC
T2=HOUR2*T_HOUR+MIN2*T_MIN+SEC2*T_SEC
Похожая задача была
здесь
Re: Таймеры/счётчики в AVR
Добавлено: Вс окт 29, 2017 08:05:29
7seg
Есть у кого функция задержки времени без _delay_ms ,на таймере если еще и на нулевом то вобще гуд ). камень мк atmega8. Задержки до от 100ms до 10s.
Re: Таймеры/счётчики в AVR
Добавлено: Вс окт 29, 2017 10:35:57
akl
Задержка на T0 ATmega8
Спойлер
Код: Выделить всё
.include "m8def.inc"
.equ F_CPU=8000000 ;тактовая частота 8 МГц
.equ D=100000*F_CPU/1000000 ; для примера 100мс
.equ D_HIGH=$70 ; ячейки, хранящие задержку D/256
.equ D_MIDL=$71 ; ячейки, хранящие задержку D/256
.equ D_LOW =$72 ;
.cseg
.org 0
RJMP START ;переход на обработку сброса
.org 9
T0_OVER:
SUBI R27,BYTE1(1)
SBCI R26,BYTE2(1)
SBCI R25,BYTE3(1)
BRNE NO_DELAY
RET
NO_DELAY:
RETI
START:
LDI ZH, high(RAMEND) ;Инциализация стека
LDI ZL, low(RAMEND) ;
OUT SPH,ZH ;
OUT SPL,ZL ;
LDI R25,BYTE3(D/256) ; для примера
LDI R26,BYTE2(D/256) ; для примера
LDI R27,BYTE1(D/256) ;
STS D_HIGH,R25 ;
STS D_MIDL,R26 ;
STS D_LOW,R27 ;
GO:
LDS R25,D_HIGH ; загрузка D/256
LDS R26,D_MIDL ;
LDS R27,D_LOW
LDI R21,1<<SE
OUT MCUCR,R21
LDI R21,1<<TOIE0
OUT TIMSK,R21
OUT TIFR,R21
LDI R21,1<<CS00 ;F_CPU/1
OUT TCCR0,R21
SEI
WAIT:
SLEEP
BRIE WAIT
RJMP GO
.EXIT
Re: Таймеры/счётчики в AVR
Добавлено: Вс окт 29, 2017 11:57:13
7seg
Наверно гуд задержка реализована) , асм просто не знаю (. ее можно как ассемблерную вставку в си использовать ?
Re: Таймеры/счётчики в AVR
Добавлено: Вс окт 29, 2017 12:17:35
ARV
7seg писал(а):Есть у кого функция задержки времени без _delay_ms ,на таймере если еще и на нулевом то вобще гуд
а самому написать - не гуд?
настраиваете таймер на прерывания через любой подходящий вашим интересам интервал, например, если шаг задержки 1 мс, то и интервал прерываний таймера тоже разумно сделать 1 мс.
заводите себе глобальную переменную-стетчик, например delay. размер этой переменной должен вмещать нужную вам предельно большую задержку. т.е. если вы хотите до 10 секунд, а период тиков таймера 1 мс, максимальная задержка будет 10000 тиков таймера, т.е. переменная будет uint16_t delay; если счетчик вышел больше 1 байта, то дополнительно заводите себе переменную-флаг timeout (однобайтную!), которая и будет означать истечение задержки.
ну и теперь делаете обработчик прерываний таймера
Код: Выделить всё
ISR(TIMER0_OVF_vect){ // я дли примера взял по переполнению, можно любое иное прерывание
if(delay){
delay--;
timeout = 1;
}
}
еще делаете функцию установки задержки
Код: Выделить всё
#include <util/atomic.h>
void set_delay(uint16_t ms){
timeout = 0;
ATOMIC_BLOCK(ATOMIC_RESTORE_STATE){
delay = ms;
}
}
вот почти и все. в нужном вам месте вызываете эту функцию set_delay и затем время от времени проверяете timeout - как только эта переменная станет не равна нулю - задержка истекла.
Код: Выделить всё
while(1){ // главный цикл
if(timeout){
PORTB ^= _BV(PB0); // мигаем светодиодом на порту PB0
set_delay(1000); // с периодом 2 секунды
}
// а тут занимается остальными делами в главном цикле
}
если delay у вас однобайтным вышел, то timeout не требуется, можно смотреть сразу на delay: обнулилась - время вышло. ну и atomic.h в этом случае не требуется
Re: Таймеры/счётчики в AVR
Добавлено: Вс окт 29, 2017 17:21:33
Demiurg
[uquote="7seg",url="/forum/viewtopic.php?p=3218815#p3218815"]Есть у кого функция задержки времени без _delay_ms ,на таймере если еще и на нулевом то вобще гуд ). камень мк atmega8. Задержки до от 100ms до 10s.[/uquote]
1-ый вариант:автоматное программирование и программные таймеры. Почитайте
цикл статей. Будет очень полезно. Я многое почерпнул там.
2-ой вариант: настраивается самый ненужный таймер на 1 мс. В основном цикле проверять признак того, что таймер оттикал 1 мс и дальше работает ваша фантазия.
soft_timer.h
Спойлер
Код: Выделить всё
//==================
#ifndef SOFT_TIMERS_H
#define SOFT_TIMERS_H
#include "soft_timers.h"
#include "main_def_func.h"
//==================
//==================
#define ST_TCNT TCNT2
#define ST_TIMSK TIMSK
#define ST_OCIE OCIE2
#define ST_OCR OCR2
#define ST_TCCR TCCR2
#define CS0 CS20
#define CS1 CS21
#define CS2 CS22
//==================
//==================
typedef struct soft_timer
{
bool status;
u08 sys_tick_prev;
u16 cnt; // Counter.
u16 period; // Period.
} soft_timer;
//==================
//==================
void init_soft_timers (void);
#define handle_soft_timer(a) _handle_soft_timer (&a)
bool _handle_soft_timer (void *ptr_timer);
#define set_soft_timer(a,b,c) _set_soft_timer (&a, b, c)
void _set_soft_timer (void *ptr_timer, u16 time, u16 period);
#define reset_soft_timer(a) _reset_soft_timer (&a)
void _reset_soft_timer (void *ptr_timer);
//==================
//==================
extern bool tick;
void Main_Timer_Init (void);
bool Main_Get_Tick (void);
//==================
#endif
soft_timer.c
Спойлер
Код: Выделить всё
//==================
// Реализация программных таймеров.
// Примечание. Важно!!!!!!!!!!!!!!!
// При смене состояния конечного автомата нужно сбросить
// все таймеры, которые используются в этом состоянии. Иначе может быть
// следующая ситуация: если таймер уже использовался в
// текущем состоянии и флаг EN установлен, то по окончании времени
// выполнится соответствующий код.
//--------------------- Пример использования -----------------------------
// set_soft_timer (ST_LED_2_BLINK, 50, 50); // Установка таймера.
// if (handle_soft_timer (ST_LED_2_BLINK)) // Проверка таймера.
//==================
//==================
#include "soft_timers.h"
//==================
//==================
static u08 sys_tick;
//==================
//==================
#pragma vector = TIMER2_COMP_vect
__interrupt void SysTimerComp (void)
{
ST_OCR += 250;
sys_tick++;
}
//==================
//==================
void init_soft_timers (void)
{
sys_tick = 0;
ST_TCNT = 0;
ST_OCR = 250;
ST_TCCR |= (1<<CS2);
set_bit (ST_TIMSK, ST_OCIE);
}
//------------------------------------------------------------------------
void _set_soft_timer (void *ptr_timer, u16 time, u16 period)
{
struct soft_timer *ptr = ptr_timer;
ptr -> status = true;
if (time == 0)
ptr -> sys_tick_prev = ~sys_tick;
else
ptr -> sys_tick_prev = sys_tick;
ptr -> cnt = time;
ptr -> period = period;
}
//------------------------------------------------------------------------
bool _handle_soft_timer (void *ptr_timer)
{
struct soft_timer *ptr = ptr_timer;
if (ptr -> status)
{
if (ptr -> sys_tick_prev != sys_tick)
{
ptr -> sys_tick_prev = sys_tick;
if (ptr -> cnt == 0)
{
if (ptr -> period != 0) ptr -> cnt = ptr -> period;
return true;
}
else
{
ptr -> cnt--;
if (ptr -> cnt == 0)
{
if (ptr -> period != 0) ptr -> cnt = ptr -> period;
return true;
}
}
}
}
return false;
}
void _reset_soft_timer (void *ptr_timer)
{
struct soft_timer *ptr = ptr_timer;
ptr -> status = 0;
ptr -> sys_tick_prev = 0;
ptr -> cnt = 0;
ptr -> period = 0;
}
//==================
Примеры использования
тут.
Re: Таймеры/счётчики в AVR
Добавлено: Пн окт 30, 2017 02:07:19
akl
[uquote="7seg",url="/forum/viewtopic.php?p=3218952#p3218952"]... ее можно как ассемблерную вставку в си использовать ?[/uquote] Если выдержать соглашение использования вставок, можно.
Re: Таймеры/счётчики в AVR
Добавлено: Пн окт 30, 2017 07:42:45
7seg
Все таки решил попробовать что нибудь свое сотворить.)
Создал таймер прерывание каждую ms, в нем и соответственно подсчет ms,ss,mm. ( на самом деле таймера допустимы и с условным временем,то есть 1s может быть примерно равна 1s ).
Также написал пару функций OffAfterTimeSS и OnAfterTimeSS ,ВключитьЧерезУказаноеВремя и выключить соответственно.
Но есть одна переменная которая отвечает за фиксирование времени отсчета TimeCountingON и очевидно что при вызове функции более чем одного раза она изменяться и функция OnAfterTimeSS/OffAfterTimeSS перестает работать коректо.
Как более правильно зафиксировать время TimeCountingON фиксировать ?
Код: Выделить всё
ISR (TIMER0_OVF_vect)
{
TCNT0=125;
VarMS++;
if(VarMS==1000)
{
VarSS++;
VarMS=0;
}
if (VarSS==60)
{
VarMM++;
VarSS=0;
}
if (VarMM==60)
{
VarMM=0;
}
}
uint8_t FlagTImeON=0; //Флаг для захвата времени отсчета.
uint8_t TimeCountingON=0;//Время Отсчета
uint8_t FlagTImeOff=0;
uint8_t TimeCountingOff=0;
uint8_t OnAfterTimeSS(uint8_t TimeSS,uint8_t CurrentFlag)
{
if (FlagTImeON==0)
{
TimeCountingON=VarSS; //Время Отсчета
FlagTImeON=1;
}
uint8_t TimeCurrent=VarSS; //Текущие время
uint8_t OutFlag=0;
if ((TimeCurrent-TimeCountingON) == TimeSS)
{
OutFlag=1;
}
else OutFlag=CurrentFlag;
return OutFlag;
}
uint8_t OffAfterTimeSS(uint8_t TimeSS,uint8_t CurrentFlag)
{
if (FlagTImeOff==0)
{
TimeCountingOff=VarSS; //Время Отсчета
FlagTImeOff=1;
}
uint8_t TimeCurrent=VarSS; //Текущие время
uint8_t OutFlag=0;
if ((TimeCurrent-TimeCountingOff) == TimeSS)
{
OutFlag=0;
FlagTImeON=0;
}
else OutFlag=CurrentFlag;
return OutFlag;
}
}
Re: Таймеры/счётчики в AVR
Добавлено: Пн окт 30, 2017 10:16:48
Ivanoff-iv
попробуй как в ардуинах - переменная (R.O.) отсчитывает время от включения, а когда нужен интервал - берешь свою переменную, в момент начала интервала записываешь в неё значение "часов", а продолжительность интервала = "часы"-"момент начала интервала". этих моментов можно сколько угодно наделать, не сбивая "часов".
Re: Таймеры/счётчики в AVR
Добавлено: Пн окт 30, 2017 10:32:40
7seg
Я примерно по такому принципу выше и делал. но как в функции организовать "момент начала интервала" ?) что бы при повторном вызове функции (пока к примеру первый ее вызов еще не отработал) этот момент не перезаписался.
Re: Таймеры/счётчики в AVR
Добавлено: Пн окт 30, 2017 10:59:23
Ivanoff-iv
сорри пропустил, с телефона неудобно ког понимать, увидел...
а до скольки раз планируется запускать функции?
Re: Таймеры/счётчики в AVR
Добавлено: Пн окт 30, 2017 11:19:45
7seg
неизвестно.(
Re: Таймеры/счётчики в AVR
Добавлено: Пн окт 30, 2017 13:19:14
Ivanoff-iv
[uquote="7seg",url="/forum/viewtopic.php?p=3219833#p3219833"]неизвестно.([/uquote] тут динамическим выделением памяти попахивает... а хоть максимально сколько?
взять по максимуму и раздуть массив, по мне, будет проще.
хотя... может кто чего и насоветует
Re: Таймеры/счётчики в AVR
Добавлено: Пн окт 30, 2017 14:04:13
7seg
А работает ли функция malloc() на avr си ?
Re: Таймеры/счётчики в AVR
Добавлено: Вт окт 31, 2017 08:59:04
Ivanoff-iv
да, но память контроллера не безгранична
Re: Таймеры/счётчики в AVR
Добавлено: Вт окт 31, 2017 09:12:06
7seg
Уже почитал что использовать функции динамического выделения опасно на мк.
примерно прикинул что одновременно таймеров больше5 шт работать не будет. Поэтому пробую загонять данные в массив из 10 элементов(двух кратный запас).
Но пока как то коряво получается (.
Код:
Код: Выделить всё
volatile uint16_t VarMS=0;
volatile uint8_t VarSS=0;
volatile uint8_t VarMM=0;
ISR (TIMER0_OVF_vect)
{
TCNT0=125;
VarMS++;
if(VarMS==1000)
{
VarSS++;
VarMS=0;
}
if (VarSS==60)
{
VarMM++;
VarSS=0;
}
if (VarMM==60)
{
VarMM=0;
}
}
volatile uint8_t FlagTIme[10]={0};
volatile uint8_t TimeCountingON[10]={0};
uint8_t OnAfterTimeSS(uint8_t TimeSS,uint8_t CurrentFlag)
{
uint8_t NumberTimer=0;
if (CurrentFlag==0)
{
if (FlagTIme[NumberTimer]==0)
{
TimeCountingON[NumberTimer]=VarSS; //Время Отсчета
FlagTIme[NumberTimer]=1;
}
else
{
NumberTimer++;
if (NumberTimer==10)
{
NumberTimer=0;
}
}
}
uint8_t TimeCurrent=VarSS; //Текущие время
uint8_t OutFlag=0;
if ((TimeCurrent-TimeCountingON[NumberTimer]) == TimeSS)
{
OutFlag=1;
}
else
{
OutFlag=CurrentFlag;
}
return OutFlag;
}
Re: Таймеры/счётчики в AVR
Добавлено: Вт окт 31, 2017 10:46:01
Ivanoff-iv
а может тогда как в микроволновке - обратный отсчет
Код: Выделить всё
ISR (TIMER0_OVF_vect)
{
for (i=0,i<10,i++)
{
if (M[i])
{
M[i]--;
if (!(M[i])) "действие";
};
};
}
тут М - массив на 10 элементов
при каждом переполнении цикл пробегает по массиву, находит элементы !=0 их убавляет, и если среди них есть "дотикавшие" выполняет действие. (для включения и выключения разные циклы).
функцию для внесения задания: перебор до первого "0" и внесение в ячейку M
значения задержки (в количестве переполнений)
и часы общие не понадобятся.
Добавлено after 1 hour 4 minutes 24 seconds:
Код: Выделить всё
void set_t (unsigned int time)
{
for (i=0,i<10,i++)
{
if (!(M[i])) {M[i]=time; break;};
};
}
примерно так. тоже для включения и выключения разные функции. если будут перебраны все 10 таймеров и не найдётся свободного - изменения в расписание внесены не будут.
Re: Таймеры/счётчики в AVR
Добавлено: Вт окт 31, 2017 13:34:46
vispower
братцы, подскажите неучу, научился кексы закачивать в аруину уно, следующий этап написать простенькую прогу на Ассемблере. в пробнике проинициализировал Т2 на сравнение, прерывание приходит, идет на обработку по вектору, но в стеке записан какой то левый адрес т.е. по ret возвращается не в цикл-ожидание окуда вылетел по прерыванию, а гораздо выше. Почему так?
Re: Таймеры/счётчики в AVR
Добавлено: Вт окт 31, 2017 13:51:09
Demiurg
1 - Скорее всего не инициализирован стек.
2 - Вольфганг Трамперт - AVR-RISC микроконтроллеры фирмы ATMEL.
Re: Таймеры/счётчики в AVR
Добавлено: Вт окт 31, 2017 13:57:02
vispower
[uquote="Demiurg",url="/forum/viewtopic.php?p=3220868#p3220868"]1 - Скорее всего не инициализирован стек.
2 - Вольфганг Трамперт - AVR-RISC микроконтроллеры фирмы ATMEL.[/uquote]
стек проинициализировал по мануалу, а вот второе не понял.