Перейти к содержанию
    

Счет по прерыванию таймера0

Ну почему я не могу так написать.

На семисегментник не выводится число из массива Исходник

 

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

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

 

#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]; 
}

 

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

 

 

Думается мне, что придется считать количество поднятых статусных флагов таймера...

488 поднятий и секунда в кармане. Надо пробовать...

:maniac:

Изменено пользователем IgorKossak
[codebox] для длинного кода, [code] - для короткого!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Попробовал. Таймер считает медленно.

Написал условие в цикле майна...

 

 

if ((TIFR0)&(1<<TOV0)) // Если флаг таймера Т0 поднят и запущено прерывание по переполнению... 
        {
            unsigned int temp;
            temp = ++tmsec;
            s = temp;
            data[3]=codes[s];
            // Таймер считает медленно...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не могу найти способ правильно считать и выводить на семисегментрик такие вот значения таймеров
Вы бы написали, в чем именно выражается "неработа" вашей программы. Было бы несколько проще.

 

Первая причина: у вас прерывание происходит каждые 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. Соотвественно вся остальная часть прерывания у вас не исполняется никогда.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...