Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Счет по прерыванию таймера0
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
krokodandi
Ну почему я не могу так написать.
На семисегментник не выводится число из массива Исходник

Не могу найти способ правильно считать и выводить на семисегментрик такие вот значения таймеров
Может у кого завалялся правильный алгоритм или код?

CODE
#define F_CPU 8000000UL

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

short unsigned int k = 0;
volatile unsigned int tic=0;
volatile char tic1=0,tic2=0, tic3=0;
unsigned int Day = 0, Hh = 0, h = 0, Mm = 0, m = 0, Ss = 0, s = 0, ms = 0;

Массивы для вывода

const unsigned char codes[10]={0x14,0xD7,0x4C,0x45,0x87,0x25,0x24,0x57,0x4,0x5}; // 0-1-2-3-4-5-6-7-8-9
unsigned char counter[4]={0x08,0x04,0x02,0x01};
unsigned char data[4]={0x14,0x14,0x14,0x14};

ISR(TIMER0_OVF_vect)
{
//отключаем, считаем от нуля до трех, переключаем разряд и снова включаем
PORTC=255;
(k == 3) ? k = 0 : k++;
PORTD = data[k];
PORTC = counter[k];
// сразу для обоих портов =)

tic=tic+1; //каждые 488 преравания таймера это секунда
if (tic >= 488)
{
tic1 = tic/488; // Секунды
tic=0;
}

if (tic1 >= 60)
{
tic2 = tic1/60; // Минуты
tic1 = 0;
}

if (tic2 >= 60)
{
tic3 = tic2/24; // Часы
tic2 = 0;
}

if (tic3 >= 24) // Сутки
{
tic3 = 0;
}
}


void init_timer (void)
{

TIMSK0 = (1<<TOIE0);
TCCR0B = (0<<CS02)|(1<<CS01)|(1<<CS00); //8.000.000/64 = 125.000 тиков в сек. (0-1-1 - делитель на 64)

}



int main (void)
{
cli();
DDRC = 255; // готовим порты
DDRD = 255;
PORTD = 0;
init_timer (); // готовим таймер/счетчик 0
sei ();

//Главный цикл...
while(1)
{


s = tic1; // эта переменная - полноценная секунда!
m = tic2; // минута
h = tic3; // час

//Day = tic3; // день

//далее попытка вывести s в разряд...
data[3]=codes[s];

}
return 1;
}


Но если написать так, подставив глобальную переменную tsec и вернув data[3]=codes[tsec]; в прерывание, почемуто так все работает..
Как вообще можно вытащить значение глобальной переменной из прерывания?
Я ведь хотел выбрать из неё значение tsec++;
Тогда, можно было бы считать секунды минутами а минуты часами и тд
Код
ISR(TIMER0_OVF_vect)
{
    tic=tic+1; //каждые 488 преравания таймера это секунда
            
    if (tic >= 488)
    {
        tsec++;
        tic=0; // Секунды
        
    }
    
         data[3]=codes[tsec];
}


Получается, что вывод ни дисплей я могу писать либо в прерывании, либо в теле - функцией angry.gif


Думается мне, что придется считать количество поднятых статусных флагов таймера...
488 поднятий и секунда в кармане. Надо пробовать...
maniac.gif
krokodandi
Попробовал. Таймер считает медленно.
Написал условие в цикле майна...


Код
if ((TIFR0)&(1<<TOV0)) // Если флаг таймера Т0 поднят и запущено прерывание по переполнению...
        {
            unsigned int temp;
            temp = ++tmsec;
            s = temp;
            data[3]=codes[s];
            // Таймер считает медленно...
Сергей Борщ
Цитата(krokodandi @ Jul 8 2015, 19:08) *
Не могу найти способ правильно считать и выводить на семисегментрик такие вот значения таймеров
Вы бы написали, в чем именно выражается "неработа" вашей программы. Было бы несколько проще.

Первая причина: у вас прерывание происходит каждые 64 такта процессора. Время исполнения вашего обработчика гораздо больше этих 64 тактов, особенно учитывая, что вы в нем постоянно пишете/читаете volatile-переменные. volatile заставляет компилятор при каждом обращении считывать/записывать такую переменную в память. То есть в коде

Код
    tic=tic+1; //каждые 488 преравания таймера это секунда
    if (tic >= 488)
    {
        tic1 = tic/488;   // Секунды
        tic=0;
    }
у вас считывается tic, прибавляется единица, результат записывается в память. Потом он тут же считывается обратно из памяти и сравнивается с 488. Потом снова считывается из памяти и делится (операция небыстрая, прямо скажем). Если уж работаете с volatile (а здесь оно необходимо), то заведите временную переменную, считайте в нее свою volatile-переменную, работайте с временной переменной и в конце вычислений запишите временную обратно в volatile. Так вы сильно сократите и ускорите свою программу. Я бы на вашем месте вообще оставил в прерывании только tic=tic+1, а в основном цикле делал все остальные действия если она изменилась. И еще - поскольку у вас tic имеет размер больше однгого байта, между чтениями байтов этой переменной в основном цикле может произойти прерывание, которое изменит tic. Поэтому вне прерывания надо считывать tic либо с запрещенными прерываниями, либо дважды. И если результаты обоих чтений одинаковы - использовать, а если разные (произошло прерывание) - повторить чтение снова.

Вторая причина:
Код
tic1 = tic/488;   // Секунды

Эту строку можно заменить на tic1 = 1. Соотвественно вся остальная часть прерывания у вас не исполняется никогда.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.