Jump to content

    
Sign in to follow this  
krokodandi

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

Recommended Posts

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

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

 

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

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

 

#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:

Edited by IgorKossak
[codebox] для длинного кода, [code] - для короткого!

Share this post


Link to post
Share on other sites

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

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

 

 

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

Share this post


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

 

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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this