krokodandi 0 8 июля, 2015 Опубликовано 8 июля, 2015 (изменено) · Жалоба Ну почему я не могу так написать. На семисегментник не выводится число из массива Исходник Не могу найти способ правильно считать и выводить на семисегментрик такие вот значения таймеров Может у кого завалялся правильный алгоритм или код? #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: Изменено 8 июля, 2015 пользователем IgorKossak [codebox] для длинного кода, [code] - для короткого! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
krokodandi 0 8 июля, 2015 Опубликовано 8 июля, 2015 · Жалоба Попробовал. Таймер считает медленно. Написал условие в цикле майна... if ((TIFR0)&(1<<TOV0)) // Если флаг таймера Т0 поднят и запущено прерывание по переполнению... { unsigned int temp; temp = ++tmsec; s = temp; data[3]=codes[s]; // Таймер считает медленно... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 117 9 июля, 2015 Опубликовано 9 июля, 2015 · Жалоба Не могу найти способ правильно считать и выводить на семисегментрик такие вот значения таймеровВы бы написали, в чем именно выражается "неработа" вашей программы. Было бы несколько проще. Первая причина: у вас прерывание происходит каждые 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. Соотвественно вся остальная часть прерывания у вас не исполняется никогда. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться