AVR Раздел по микроконтроллерам компании Atmel - AVR / ATtiny / ATmega / ATMega128 / ATxmega, вопросы по программированию в AVR studio и все, относящееся к AVR... |
19.01.2024, 01:09
|
|
Почётный гражданин KAZUS.RU
Регистрация: 29.10.2006
Сообщений: 1,446
Сказал спасибо: 99
Сказали Спасибо 317 раз(а) в 233 сообщении(ях)
|
Re: Таймер на AVR ATMEGA128
Опишите задачу полностью: что за таймер, какой дисплей, сколько кнопок и что они должны делать, какие внешние устройства...
|
|
|
|
19.01.2024, 10:57
|
|
Временная регистрация
Регистрация: 07.03.2019
Сообщений: 87
Сказал спасибо: 11
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: Таймер на AVR ATMEGA128
Сообщение от Godzilla82
|
Опишите задачу полностью:
|
Здравствуйте!
Дисплей nokia 5510, камень avr atmega 128/
Обычный таймер обратного отчета. Таймер содержит в себе, миллисекунды, секунды, десятки секунд, минуты, десятки минут.
Есть кнопки для увеличения и уменьшения выбранной части времени. Выбор доли времени осуществляется отдельной кнопкой, по нажатию которой сдвигается курсор от миллисекунд в сторону десятков минут.
Есть еще две кнопки одна кнопку служит для запуска отсчета, вторая для паузы.
Периферии пока ни какой нет. Но в целом это будет несколько реле на разных портах.
Я конечно дико извиняюсь за кашу в коде. Это в силу моего мизерного опыта, я только учусь.
МОжет посмотрите код и дадите пару советов? исходники прикладываю
Текущий вид кода:
Нажмите, чтобы открыть спойлер
PHP код:
|
#define F_CPU 8000000UL #include ‹avr/io.h› #include ‹util/delay.h› #include ‹avr/interrupt.h› #include ‹util/atomic.h› #include ‹stdlib.h› #include ‹avr/sleep.h› #include ‹avr/cpufunc.h› #include "n5110.h"
//------------------------------------------------------------------------------------------------------------------------- // Создаю переменные для получения времени volatile uint32_t dmilliseconds = 0; volatile uint32_t seconds_on_tiki = 0; volatile uint32_t milliseconds = 0; volatile uint32_t seconds = 0; volatile uint32_t tens_of_seconds = 0; volatile uint32_t minutes = 0; volatile uint32_t tens_of_minutes = 0; volatile uint32_t time_in_sec = 0; volatile uint32_t time_in_thensec = 0; volatile uint32_t time_in_min = 0; volatile uint32_t time_in_thenmin = 0; unsigned int milis = 0; volatile uint8_t timer_state = 0; volatile int iterator =1; volatile int count =0,count_line =0; volatile int x1 =0, y1 =0, x2 =0, y2 =0; char line = PIXEL_ON;
//------------------------------------------------------------------------------------------------------------------------- void time (unsigned int tiki) // Создаю функцию для дробления 5х значного числа на разряды { seconds_on_tiki = tiki / 10; // всего секунд в tiki dmilliseconds = tiki % 10; // десятые доли секунды (0..9) minutes = seconds_on_tiki / 60; // минуты (0..99) seconds = seconds_on_tiki % 60; // секунды (0..59) tens_of_minutes = minutes /10; //Десятки минут time_in_min = minutes %10; // минуты tens_of_seconds = seconds/10; time_in_sec = seconds %10; }
void display_timer_state(void) { if (timer_state == 1) { // Timer is ON Lcd_print(0, 3, FONT_1X, (unsigned char *)PSTR("timer ON"));
} else { // Timer is paused Lcd_print(0, 3, FONT_1X, (unsigned char *)PSTR("timer pause")); } } //------------------------------------------------------------------------------------------------------------------------- void timer1_ini(void) //настройка таймера счетчика первого { TCNT1 = 0; // обнуляем счетный регистр OCR1A = 3125; // Указываем число для сравнения в регистр сравнения TIMSK |= (1‹‹OCIE1A); // Включаем бит разрешения сравнения с OCR1A } //------------------------------------------------------------------------------------------------------------------------- void timer1_start(void) //Запуск первого таймера счетчика с предделителем на 256 и разрешением сравнения { TCCR1B |= (1‹‹WGM12)|(1‹‹CS12); } //------------------------------------------------------------------------------------------------------------------------- void timer1_stop(void) //Остановка первого таймера { TCCR1B &= ~((1‹‹WGM12)|(1‹‹CS12)); } //------------------------------------------------------------------------------------------------------------------------- ISR(TIMER1_COMPA_vect) // Создаю макрос тиканья таймера { if (--milis==0) { TCCR1B &=~(1‹‹CS12); milis = 0; //PORTD |= (1‹‹0);
} } //------------------------------------------------------------------------------------------------------------------------- void button_on(void) // Активирую порты D и Е на выход, что бы использовать кнопки { DDRD = 0x00; PORTD |= (1‹‹0) | (1‹‹1) | (1‹‹2) | (1‹‹3); } //------------------------------------------------------------------------------------------------------------------------- void displey_start(void) // Активирую Порт B на выход, для того что бы активировать дисплей { DDRB &= ~((1‹‹PINB0) | (1‹‹PINB1) | (1‹‹PINB2) | (1‹‹PINB3) | (1‹‹PINB4) | (1‹‹PINB5)); PORTB = 0x00; Lcd_init(); Lcd_clear(); Lcd_update(); LcdContrast(62); }
ISR(INT0_vect) { // Изменение значения переменной iterator в зависимости от текущего значения if (count==1) iterator = 10; if (count==2) iterator = 100; if (count==3) iterator = 600; if (count==4) iterator = 6000; if (count›=5) {count = 0; iterator = 1;} } //------------------------------------------------------------------------------------------------------------------------- char buff[20]; int main(void) { // временная переменная для сохранения состояния прерываний unsigned char keep_interrupt_status; // временная переменная для счетчика тиков unsigned int safe_desec; button_on(); displey_start(); timer1_ini(); timer1_start(); // глобальные прерывания включены timer1_stop(); // Настройка прерывания INT0 при нажатии кнопки EIMSK |= (1 ‹‹ INT0); // Разрешение внешнего прерывания INT0 EICRA |= (1 ‹‹ ISC00); // Прерывание INT0 происходит при любом изменении на линии sei(); while (1) { keep_interrupt_status = SREG; // сохранить состояние прерываний cli(); // запрет прерываний safe_desec = milis; // АТОМАРНО копируем счетчик тиков во временную переменную SREG = keep_interrupt_status; // восстановить состояние прерываний
time(safe_desec);
// Формирование строки для вывода на дисплей buff[0] = tens_of_minutes + '0'; // десятки минут (0..9) ASCII buff[1] = time_in_min + '0'; // единицы минут (0..9) ASCII buff[2] = ':'; // разделитель buff[3] = tens_of_seconds + '0'; // десятки секунд (0..5) ASCII buff[4] = time_in_sec + '0'; // единицы секунд (0..9) ASCII buff[5] = ':'; // разделитель buff[6] = dmilliseconds + '0'; // десятые доли секунды (0..9) ASCII buff[7] = '\0'; // NUL-терминатор строки
if (~PIND&(1‹‹4)) { count++; //10, 100, 600, 6000 count_line++; _delay_ms(150); } if (count==1) iterator = 10; if (count==2) iterator = 100; if (count==3) iterator = 600; if (count==4) iterator = 6000; if (count›=5) {count = 0; iterator = 1;} if (count_line==0) {x1=42; y1=9; x2=46; y2=9;} if (count_line==1) {x1=24; y1=9; x2=28; y2=9;} if (count_line==2) {x1=18; y1=9; x2=22; y2=9;} if (count_line==3) {x1=6; y1=9; x2=10; y2=9;} if (count_line==4) {x1=0; y1=9; x2=4; y2=9;} if (count_line›=5) {count_line=0; x1=42; y1=9; x2=46; y2=9;} if (~PIND&(1‹‹0)) { milis+=iterator; //10, 100, 600, 6000
_delay_ms(150); }
if (~PIND&(1‹‹1)) { time(milis); // Обновляем переменные перед увелечением итератора if (tens_of_minutes != 0 || time_in_min != 0 || tens_of_seconds != 0 || time_in_sec != 0 || dmilliseconds != 0) { // Проверяем, что хотя бы одна из переменных не равна нулю milis-=iterator; _delay_ms(150); } if(milis‹=0) milis = 0; } if (tens_of_minutes == 0 && time_in_min == 0 && tens_of_seconds == 0 && time_in_sec == 0 && dmilliseconds == 0) {
line = PIXEL_ON; } if (~PIND&(1‹‹2)) { time(milis); // Обновляем переменные перед запуском таймера if (tens_of_minutes != 0 || time_in_min != 0 || tens_of_seconds != 0 || time_in_sec != 0 || dmilliseconds != 0) { // Проверяем, что хотя бы одна из переменных не равна нулю timer1_start(); line = PIXEL_OFF; } _delay_ms(150); } if (~PIND&(1‹‹3)) { time(milis); // Обновляем переменные перед остановкой таймера if (tens_of_minutes != 0 || time_in_min != 0 || tens_of_seconds != 0 || time_in_sec != 0 || dmilliseconds != 0) { // Проверяем, что хотя бы одна из переменных не равна нулю timer1_stop(); line = PIXEL_ON; } _delay_ms(150); }
Lcd_clear(); char buff[20]; itoa(tens_of_minutes, buff, 10); Lcd_print(0, 0, FONT_1X,(unsigned char *)buff); itoa(time_in_min, buff, 10); Lcd_print(1, 0, FONT_1X,(unsigned char *)buff); Lcd_prints(2, 0, FONT_1X,(unsigned char *)PSTR(":")); itoa(tens_of_seconds, buff, 10); Lcd_print(3, 0, FONT_1X,(unsigned char *)buff); itoa(time_in_sec, buff, 10); Lcd_print(4, 0, FONT_1X,(unsigned char *)buff); Lcd_prints(5, 0, FONT_1X,(unsigned char *)PSTR(":")); itoa(dmilliseconds, buff, 10); Lcd_print(7, 0, FONT_1X,(unsigned char *)buff);
Lcd_line ( x1, y1, x2, y2, line ); Lcd_update(); _delay_ms(50);
} }
|
Из всего этого думаю что надо использовать не блокирующие задержки, то есть перевести обработку нажатия кнопок в нулевой таймер. и часть if превратить функцию, например курсор для выбора времени. Еще заметил странность при работе кнопки уменьшения. Например если выставить 12 секунд, потом начать уменьшать десятки, то в какой то момент таймер перескочит например на 18 часов и так далее
=
Последний раз редактировалось Devil Byte; 19.01.2024 в 17:43.
|
|
|
|
19.01.2024, 21:50
|
|
Почётный гражданин KAZUS.RU
Регистрация: 29.10.2006
Сообщений: 1,446
Сказал спасибо: 99
Сказали Спасибо 317 раз(а) в 233 сообщении(ях)
|
Re: Таймер на AVR ATMEGA128
PHP код:
|
#include ‹io.h›
#include ‹alcd.h›
#include ‹stdio.h›
#define _ALTERNATE_PUTCHAR_
#define KEY_SELECT 0x01
#define KEY_INC 0x02
#define KEY_DEC 0x04
#define KEY_START 0x08
#define KEY_PAUSE 0x10
#define MODE_SELECT 0
#define MODE_RUN 1
#define MODE_PAUSE 2
#define MODE_DONE 3
unsigned char key_pressed = 0;
unsigned char key_previous = 0;
unsigned char key_current = 0;
unsigned char update = 1;
unsigned char timer_mode = 0;
unsigned char timer_select = 0;
signed char time_ts = 0;
signed char time_ss = 0;
signed char time_ds = 1;
signed char time_mm = 0;
signed char time_dm = 0;
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
key_current = ~PIND;
key_pressed |= key_current ^ key_previous & key_current;
key_previous = key_current;
if(timer_mode == MODE_RUN) {
update = 1;
time_ts--;
if(time_ts ‹ 0) {
time_ts = 9;
time_ss--;
if(time_ss ‹ 0) {
time_ss = 9;
time_ds--;
if(time_ds ‹ 0) {
time_ds = 5;
time_mm--;
if(time_mm ‹ 0) {
time_mm = 9;
time_dm--;
if(time_dm ‹ 0) {
time_dm = time_mm = time_ds = time_ss = time_ts = 0;
timer_mode = MODE_DONE;
}
}
}
}
}
}
}
void init(void)
{
DDRD = 0;
PORTD = 0x1F;
// Timer1: 31,250 kHz; 0,1 s; CTC top=OCR1A;
TCCR1A = 0;
TCCR1B = (1‹‹WGM12) | (1‹‹CS12);
OCR1AH = 0x0C;
OCR1AL = 0x34;
TIMSK = (1‹‹OCIE1A);
}
void putchar(char c)
{
lcd_putchar(c);
}
void main(void)
{
unsigned char i;
init();
lcd_init(20);
#asm("sei")
while(1) {
if(key_pressed & KEY_START) {
key_pressed = 0;
update = 1;
switch(timer_mode) {
case MODE_DONE:
timer_mode = MODE_SELECT;
timer_select = 0;
break;
default:
timer_mode = MODE_RUN;
}
}
if(key_pressed & KEY_PAUSE) {
key_pressed = 0;
switch(timer_mode) {
case MODE_RUN:
timer_mode = MODE_PAUSE;
update = 1;
break;
case MODE_PAUSE:
timer_select = 0;
timer_mode = MODE_SELECT;
update = 1;
break;
}
}
if(key_pressed & KEY_SELECT) {
key_pressed = 0;
switch(timer_mode) {
case MODE_SELECT:
if(++timer_select › 4) timer_select = 0;
update = 1;
break;
}
}
if(key_pressed & KEY_INC) {
key_pressed = 0;
update = 1;
if(timer_mode == MODE_SELECT)
switch(timer_select) {
case 0: time_dm++; if(time_dm › 9) time_dm = 0; break;
case 1: time_mm++; if(time_mm › 9) time_mm = 0; break;
case 2: time_ds++; if(time_ds › 5) time_ds = 0; break;
case 3: time_ss++; if(time_ss › 9) time_ss = 0; break;
case 4: time_ts++; if(time_ts › 9) time_ts = 0; break;
}
}
if(key_pressed & KEY_DEC) {
key_pressed = 0;
update = 1;
if(timer_mode == MODE_SELECT)
switch(timer_select) {
case 0: time_dm--; if(time_dm ‹ 0) time_dm = 9; break;
case 1: time_mm--; if(time_mm ‹ 0) time_mm = 9; break;
case 2: time_ds--; if(time_ds ‹ 0) time_ds = 5; break;
case 3: time_ss--; if(time_ss ‹ 0) time_ss = 9; break;
case 4: time_ts--; if(time_ts ‹ 0) time_ts = 9; break;
}
}
if(update) {
update = 0;
lcd_clear();
printf("%d%d:%d%d.%d",time_dm,time_mm,time_ds,time_ss,time_ts);
switch(timer_mode) {
case MODE_PAUSE: lcd_gotoxy(0,1); printf("PAUSE"); break;
case MODE_DONE: lcd_gotoxy(0,1); printf("DONE "); break;
case MODE_SELECT:
i = timer_select;
if(i › 1) i++;
if(i › 4) i++;
lcd_gotoxy(i,0);
_lcd_write_data(0b00001110);
break;
}
}
}
}
|
Последний раз редактировалось Godzilla82; 20.01.2024 в 00:06.
|
|
|
Сказали "Спасибо" Godzilla82
|
|
|
20.01.2024, 20:46
|
|
Временная регистрация
Регистрация: 07.03.2019
Сообщений: 87
Сказал спасибо: 11
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: Таймер на AVR ATMEGA128
Сообщение от Godzilla82
|
PHP код:
|
#include ‹io.h›
#include ‹alcd.h›
#include ‹stdio.h›
|
|
Спасибо! в общем попробовал прокомментировать ваш код, есть какие то непонятные для меня моменты. но в целом все ясно.
Прошу Вас посмотреть, и ответить правильно ли я все понял, и ответить на вопросы в комментариях:
Нажмите, чтобы открыть спойлер
PHP код:
|
#define _ALTERNATE_PUTCHAR_ // не понял что за дефайн для альтернативного вывода символа?
#define KEY_SELECT 0x01 // Значение кнопки для выбора
#define KEY_INC 0x02 // Значение для кнопки инкремента
#define KEY_DEC 0x04 // Значение для кнопки декремента
#define KEY_START 0x08 // Значение для кнопки старт
#define KEY_PAUSE 0x10 // Значение для кнопки пауза
#define MODE_SELECT 0 // Режим выбора времени
#define MODE_RUN 1 // Режим запуска таймера
#define MODE_PAUSE 2 // Режим паузы таймера
#define MODE_DONE 3 // Режим завершения отсчета таймера
unsigned char key_pressed = 0; // Распознавание нажатия клавиши
unsigned char key_previous = 0; // Не понял предназначение этой переменной
unsigned char key_current = 0; // По идее переменная которой должны присваиваться значения пинов порта D
unsigned char update = 1; // Переменная для обновления времени как при выборе времени так и при запущенном таймере
unsigned char timer_mode = 0; // Переменная которая получает значение MODE
unsigned char timer_select = 0; // Понял что переменная позволяет выбирать место установки времени за счет своей итерации,
signed char time_ts = 0; // Десятки секунд
signed char time_ss = 0; // Секунды
signed char time_ds = 1; // Миллисекунды
signed char time_mm = 0; // Минуты
signed char time_dm = 0; // Десятки минут
ISR(TIMER1_COMPA_vect) // в вашем коде написано interrupt [TIM1_COMPA] void timer1_compa_isr(void) ... я честно не понял как это работает, что должнро попасть в прерывания? ведь нельзя определять функцию внутри функции
{
}
void timer1_compa_isr(void) // по идее это функция определения срабатывания кнопок
{
key_current = ~PIND; // Не понял для чего данная переменная каждый раз будет получать инвертированное значение с пинов?
key_pressed |= key_current ^ key_previous & key_current; // В зависимости от результатов получим модификацию переменной key_pressed, но не понимаю как работает это выражение
key_previous = key_current; // Почему такое присвоение? зависит от первого результата?
// Функция работы таймера обратный отсчет
if(timer_mode == MODE_RUN) // Если таймер запущен начинаем уменьшать значения на 1
{
update = 1;
time_ts--;
if(time_ts ‹ 0) {time_ts = 9; time_ss--;} // Если десятки секунд равны нулю, то уменьшаем секунды
if(time_ss ‹ 0) {time_ss = 9; time_ds--;} // Если секунды равны нулю, то уменьшаем миллисекунды
if(time_ds ‹ 0) {time_ds = 5; time_mm--;} // Если десятки секунды равны нулю, то уменьшаем минуты
if(time_mm ‹ 0) {time_mm = 9; time_dm--;} // Если минуты равны нулю, то уменьшаем десятки минут
if(time_dm ‹ 0) // Если десятки минут равны нулю, то можно считать таймер истекшим и приравнять все значения нулю. Затем установить режим таймера как завершенный
{
time_dm = time_mm = time_ds = time_ss = time_ts = 0;
timer_mode = MODE_DONE;
}
}
}
void init(void) // Тут в целом все понятно - функция запуск таймера с настройками и настройка порта D для кнопок
{
DDRD = 0;
PORTD = 0x1F;
// Timer1: 31,250 kHz; 0,1 s; CTC top=OCR1A;
TCCR1A = 0;
TCCR1B = (1‹‹WGM12) | (1‹‹CS12);
OCR1AH = 0x0C;
OCR1AL = 0x34;
TIMSK = (1‹‹OCIE1A);
}
void putchar(char c) // Не совсем понял что за символ, но предполагаю что это символ "земля" для примененного дисплея
{
lcd_putchar(c);
}
int main(void)
{
unsigned char i; // видимо эта переменная нужна для выбранного дисплея
init(); // инициализация таймера и порта кнопок
lcd_init(20); // инициализация вашего дисплея
#asm("sei") // разрешение прерывания. А разве их ненужно потом ни где запрещать?
while(1)
{
// Условный опереатор для определения работы кнопки старт
if(key_pressed & KEY_START) // Здесь проверяем установлен ли бит KEY_START в переменной key_pressed
{
key_pressed = 0; // Если условие истинно то переменной присваивается 0
update = 1; // Значение update = 1. А надо ли каждый раз говорить о том что она равна единице? так как она и так в дефайне =1?
switch(timer_mode) // Оператор нужен для отслеживания и отлавливания timer_mode
{
case MODE_DONE: // Если в этом кейсе словили переменную о завершении работы таймера
timer_mode = MODE_SELECT; // То переводим timer_mode в режим выбора времени для изменения
timer_select = 0; // timer_select присваиваем 0, что бы он встал в самом конце времени
break;
default: // Если первый кейс не сработал
timer_mode = MODE_RUN; // то по умолчанию запускаем работу таймера путем присвоения timer_mode = MODE_RUN
}
}
// Условный оператор для определения работы кнопки старт
if(key_pressed & KEY_PAUSE) // Здесь проверяем установлен ли бит KEY_PAUSE в переменной key_pressed
{
key_pressed = 0;
switch(timer_mode) //
{
case MODE_RUN: // Если в этом кейсе словили переменную о том что таймер в работе
timer_mode = MODE_PAUSE; // то устанавливаем переводим режим таймера в паузу
update = 1;
break;
case MODE_PAUSE: // Получается что после отработки первого кейса должны в этом кейсе словить режим паузы таймера
timer_select = 0;
timer_mode = MODE_SELECT; // и присвоить режим выбора времени, пока стоит пауза
update = 1;
break;
}
}
// Условный оператор для определения работы кнопки выбора времени
if(key_pressed & KEY_SELECT) // Здесь проверяем установлен ли бит KEY_SЕLECT в переменной key_pressed
{
key_pressed = 0; //
switch(timer_mode)
{
//не совсем понял как свич определяет режим селект? за счет того что в других свитчах он выставляется сам?
case MODE_SELECT: // Должны отловить режим таймера селект, но не совсем понимаю как свич должен отследить режим селекта
if(++timer_select › 4) timer_select = 0; // при успешном отлове можем инкрементировать переменную timer_select для смещения курсора
update = 1;
break;
}
}
// Условный оператор для определения работы кнопки увеличения времени
if(key_pressed & KEY_INC) // Здесь проверяем установлен ли бит KEY_INC в переменной key_pressed
{
key_pressed = 0;
update = 1;
if(timer_mode == MODE_SELECT) // Если кнопка увеличения времени нажата и режим таймера в режиме выбора
switch(timer_select) // то в зависимости от значения переменной timer_select будем увеличивать выбранную часть времени
{
case 0: time_dm++; if(time_dm › 9) time_dm = 0; break; //в кейсах ифами не даем перевалить времени за определенные значения
case 1: time_mm++; if(time_mm › 9) time_mm = 0; break;
case 2: time_ds++; if(time_ds › 5) time_ds = 0; break;
case 3: time_ss++; if(time_ss › 9) time_ss = 0; break;
case 4: time_ts++; if(time_ts › 9) time_ts = 0; break;
}
}
// Условный оператор для определения работы кнопки увеличения времени
if(key_pressed & KEY_DEC) // Все тоже самое как и для кнопки увеличения, только в обратном порядке
{
key_pressed = 0;
update = 1;
if(timer_mode == MODE_SELECT)
switch(timer_select)
{
case 0: time_dm--; if(time_dm ‹ 0) time_dm = 9; break;
case 1: time_mm--; if(time_mm ‹ 0) time_mm = 9; break;
case 2: time_ds--; if(time_ds ‹ 0) time_ds = 5; break;
case 3: time_ss--; if(time_ss ‹ 0) time_ss = 9; break;
case 4: time_ts--; if(time_ts ‹ 0) time_ts = 9; break;
}
}
// Не понимаю почему это все заключено в условный оператор?
if(update)
{
update = 0; // почему тут она равна нулю?
lcd_clear(); // дисплей...
printf("%d%d:%d%d.%d",time_dm,time_mm,time_ds,time_ss,time_ts); // дисплей...
switch(timer_mode)
{
case MODE_PAUSE: lcd_gotoxy(0,1); printf("PAUSE"); break; // при режиме паузы, выводим на дисплей сообщение о паузе
case MODE_DONE: lcd_gotoxy(0,1); printf("DONE "); break; // при режиме завершения выводим на дисплей сообщение о завершении
case MODE_SELECT: // вот тут не совсем понятно почему timer_select инкриминируется с помощью i? вроде выше он сам по себе работает
i = timer_select;
if(i › 1) i++; // и вот эти иф не понял что делают?
if(i › 4) i++;
lcd_gotoxy(i,0); // дисплей...
_lcd_write_data(0b00001110); // дисплей...
break;
}
}
}
}
|
Спасибо большое!
|
|
|
|
20.01.2024, 23:06
|
|
Почётный гражданин KAZUS.RU
Регистрация: 29.10.2006
Сообщений: 1,446
Сказал спасибо: 99
Сказали Спасибо 317 раз(а) в 233 сообщении(ях)
|
Re: Таймер на AVR ATMEGA128
Сообщение от Devil Byte
|
PHP код:
|
#define _ALTERNATE_PUTCHAR_ // не понял что за дефайн для альтернативного вывода символа?
|
|
Дефайн, который позволяет написать свою функцию putchar().
Сообщение от Devil Byte
|
PHP код:
|
unsigned char key_previous = 0; // Не понял предназначение этой переменной
|
|
Нужна, чтобы понять, что состояние порта изменилось.
Сообщение от Devil Byte
|
PHP код:
|
unsigned char update = 1; // Переменная для обновления времени как при выборе времени так и при запущенном таймере
|
|
Флаг обновления данных на дисплее. Устанавливаем в 1, если нужно обновить данные на экране.
Сообщение от Devil Byte
|
PHP код:
|
unsigned char timer_select = 0; // Понял что переменная позволяет выбирать место установки времени за счет своей итерации
|
|
Переменная указывает, что именно нужно менять нажатиями кнопок "+" и "-".
Сообщение от Devil Byte
|
PHP код:
|
signed char time_ts = 0; // Десятки секунд
|
|
Десятые доли секунды
Сообщение от Devil Byte
|
PHP код:
|
signed char time_ds = 1; // Миллисекунды
|
|
Десятки секунд
Сообщение от Devil Byte
|
PHP код:
|
ISR(TIMER1_COMPA_vect) // в вашем коде написано interrupt [TIM1_COMPA] void timer1_compa_isr(void) ... я честно не понял как это работает, что должнро попасть в прерывания? ведь нельзя определять функцию внутри функции
|
|
Это конструкция, описывающая функцию прерывания в компиляторе CodeVision AVR.
Сообщение от Devil Byte
|
PHP код:
|
void timer1_compa_isr(void) // по идее это функция определения срабатывания кнопок
|
|
Это функция определяет, как нажатые кнопки, так и выполняет отсчёт времени.
Сообщение от Devil Byte
|
PHP код:
|
key_current = ~PIND; // Не понял для чего данная переменная каждый раз будет получать инвертированное значение с пинов?
|
|
Потому, что кнопки замыкают пин на землю. И нажатая кнопка - это соответствующий бит будет равен нулю.
Сообщение от Devil Byte
|
PHP код:
|
key_pressed |= key_current ^ key_previous & key_current; // В зависимости от результатов получим модификацию переменной key_pressed, но не понимаю как работает это выражение
|
|
текущее значение порта через битовую операцию "исключающее или" с предыдущим значением порта даёт единицы там, где
произошло изменение. Чтобы биты нажатых кнопок не устанавливались при отпускании кнопок, результат проходит через побитовую опрецию "и"
с текущим значением нажатых кнопок (там уже, после инверсии порта, нажатой кнопке соответствует логическая единица).
Сообщение от Devil Byte
|
PHP код:
|
key_previous = key_current; // Почему такое присвоение? зависит от первого результата?
|
|
Просто запоминает предудущее состояние порта для последующего вызова прерывания.
Сообщение от Devil Byte
|
PHP код:
|
if(time_ts ‹ 0) {time_ts = 9; time_ss--;} // Если десятки секунд равны нулю, то уменьшаем секунды if(time_ss ‹ 0) {time_ss = 9; time_ds--;} // Если секунды равны нулю, то уменьшаем миллисекунды if(time_ds ‹ 0) {time_ds = 5; time_mm--;} // Если десятки секунды равны нулю, то уменьшаем минуты if(time_mm ‹ 0) {time_mm = 9; time_dm--;} // Если минуты равны нулю, то уменьшаем десятки минут if(time_dm ‹ 0) // Если десятки минут равны нулю, то можно считать таймер истекшим и приравнять все значения нулю... { time_dm = time_mm = time_ds = time_ss = time_ts = 0; timer_mode = MODE_DONE; }
|
|
Вы опять все не так переписали. Я же даже отступы сделал, чтобы наглядно видно было, какой код к какому циклу относится.
Работать будет, но проверки будут делаться каждый раз, а не только тогда, когда они нужны.
Сообщение от Devil Byte
|
PHP код:
|
void putchar(char c) // Не совсем понял что за символ, но предполагаю что это символ "земля" для примененного дисплея
|
|
Функция, которая вызывается (в частности, функцией printf() для вывода символа на экран.
Я её переписал так, чтобы вывод происходил на дисплей.
Сообщение от Devil Byte
|
PHP код:
|
unsigned char i; // видимо эта переменная нужна для выбранного дисплея
|
|
На экране таймер отображается в виде:
00:00.0
timer_select - это:
0 - для десятков минут
1 - для единиц минут
2 - для десятков секунд
3 - для единиц секунд
4 - для десятой части секунд
Эта переменная нужна для вычисления номера символа, который будет изменяться кнопками "+" и "-":
0 - для десятков минут
1 - для единиц минут
3 - для десятков секунд
4 - для единиц секунд
6 - для десятой части секунд
Сообщение от Devil Byte
|
PHP код:
|
#asm("sei") // разрешение прерывания. А разве их ненужно потом ни где запрещать?
|
|
А зачем? Пусть работают.
Сообщение от Devil Byte
|
PHP код:
|
update = 1; // Значение update = 1. А надо ли каждый раз говорить о том что она равна единице? так как она и так в дефайне =1?
|
|
В каком ещё дефайне?
Если кнопка была нажата, то программа изменила какие-то данные. Соостветственно, нужно отобразить изменения.
Сообщение от Devil Byte
|
PHP код:
|
timer_select = 0; // timer_select присваиваем 0, что бы он встал в самом конце времени
|
|
Чтобы указатель того, что будет меняться кнопками "+" и "-" указывал на десятки минут (в начало строки),
а не в "самый конец времени".
Сообщение от Devil Byte
|
PHP код:
|
case MODE_PAUSE: // Получается что после отработки первого кейса должны в этом кейсе словить режим паузы таймера
|
|
Нет, если отработал первый case, то после break управление переходит на операторы после фунции switch().
Другими словами. Первым нажатием мы переводим таймер в режим паузы, вторым нажатием - в режим выбора времени.
Сообщение от Devil Byte
|
PHP код:
|
//не совсем понял как свич определяет режим селект? за счет того что в других свитчах он выставляется сам?
|
|
При запуске программы он равен MODE_SELECT.
Сообщение от Devil Byte
|
PHP код:
|
// Не понимаю почему это все заключено в условный оператор? if(update)
|
|
Если переменная update не равна нулю, то нужно обновить данные на экране. Их не нужно обновлять 1000 раз в секунду.
Например, если мы в режиме задания времени отсчёта и ничего не нажимаем, то обновлять данные на экране не нужно.
Сообщение от Devil Byte
|
PHP код:
|
update = 0; // почему тут она равна нулю?
|
|
Присваиваем переменной update значение ноль, так как данные на экране сейчас будут обновлены.
И следующее обновление данных будет только тогда, когда в программе она снова установится в 1.
Сообщение от Devil Byte
|
PHP код:
|
case MODE_SELECT: // вот тут не совсем понятно почему timer_select инкриминируется с помощью i? вроде выше он сам по себе работает
|
|
Объяснял выше.
Сообщение от Devil Byte
|
PHP код:
|
_lcd_write_data(0b00001110);
|
|
Включает отображение курсора, который был перемещён на позицию цифры, которая будет меняться кнопками "+" и "-".
Последний раз редактировалось Godzilla82; 21.01.2024 в 13:53.
|
|
|
|
21.01.2024, 13:48
|
|
Временная регистрация
Регистрация: 07.03.2019
Сообщений: 87
Сказал спасибо: 11
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: Таймер на AVR ATMEGA128
Godzilla82, Приветсвую Вас!
Пробую разобраться...
Добавил в if (update) в свитч вывод курсора под цифрами. Но есть баг. Если ставлю таймер на паузу, то курсор не смещается по нажатию кнопки. НО если нажать на паузу два раза, то курсор начинает двигаться.
В чем загвоздка?
Нажмите, чтобы открыть спойлер
PHP код:
|
switch(timer_mode) { case MODE_PAUSE: //lcd_gotoxy(0,1); printf("PAUSE"); break; case MODE_DONE: // lcd_gotoxy(0,1); printf("DONE "); break; case MODE_SELECT: i = timer_select; if(i › 1) i++; if(i › 4) i++; // выставление координат для смещения курсора if (timer_select==4) {x1=42; y1=9; x2=46; y2=9;} if (timer_select==3) {x1=24; y1=9; x2=28; y2=9;} if (timer_select==2) {x1=18; y1=9; x2=22; y2=9;} if (timer_select==1) {x1=6; y1=9; x2=10; y2=9;} if (timer_select==0) {x1=0; y1=9; x2=4; y2=9;} if (timer_select›=5) {timer_select=0; x1=42; y1=9; x2=46; y2=9;} Lcd_line ( x1, y1, x2, y2, line ); Lcd_update(); //_delay_ms(20);
break; }
|
Последний раз редактировалось Devil Byte; 21.01.2024 в 14:22.
|
|
|
|
21.01.2024, 14:28
|
|
Почётный гражданин KAZUS.RU
Регистрация: 29.10.2006
Сообщений: 1,446
Сказал спасибо: 99
Сказали Спасибо 317 раз(а) в 233 сообщении(ях)
|
Re: Таймер на AVR ATMEGA128
Весь код покажите. В этом коде вы break закомментировали.
В том коде, что я приводил так и должно быть. Первое нажатие - просто пауза. А второе - установка времени.
Сообщение от Devil Byte
|
PHP код:
|
i = timer_select; if(i › 1) i++; if(i › 4) i++;
|
|
Зачем этот код, если вы используете timer_select.
Сообщение от Devil Byte
|
PHP код:
|
if (timer_select›=5) {timer_select=0; x1=42; y1=9; x2=46; y2=9;}
|
|
Зачем " ›="? Зачем делаете timer_select=0? Тут нужно только отображение результатов. Менять значения переменных не надо.
Последний раз редактировалось Godzilla82; 21.01.2024 в 14:41.
|
|
|
|
21.01.2024, 15:19
|
|
Временная регистрация
Регистрация: 07.03.2019
Сообщений: 87
Сказал спасибо: 11
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: Таймер на AVR ATMEGA128
Сообщение от Godzilla82
|
Весь код покажите. В этом коде вы break закомментировали.
В том коде, что я приводил так и должно быть. Первое нажатие - просто пауза. А второе - установка времени.
|
А точно, что то я даже внимания и не обратил.... Тоже интересно решение.
Сообщение от Godzilla82
|
Зачем этот код, если вы используете timer_select.
|
Поучается что в принципе i можно исключить?
Сообщение от Godzilla82
|
Весь код покажите. В этом коде вы break закомментировали.
В том коде, что я приводил так и должно быть. Первое нажатие - просто пауза. А второе - установка времени.
Зачем этот код, если вы используете timer_select.
Зачем "›="? Зачем делаете timer_select=0? Тут нужно только отображение результатов. Менять значения переменных не надо.
|
Да понял, просто я наскоряк воткнул кусок из своего кода, и неубрал обнуление селекта. в своем коде я использовал это что бы каждый раз возвращаться в конец/ начало строки.
И еще все таки прошу немного пояснить за кнопки... Тут же явно не указаны пины кнопок. Как происходит определение пина? Почему они имеют именно такое значение:
И не будет ли дребезга на реальном девайсе? просто пока не могу проверить так как на вахте.
Нажмите, чтобы открыть спойлер
[B]#define KEY_SELECT 0x01
#define KEY_INC 0x02
#define KEY_DEC 0x04
#define KEY_START 0x08
#define KEY_PAUSE 0x10/B].
и еще как на таймере при включение появляется единица в десятках часов??
Последний раз редактировалось Devil Byte; 21.01.2024 в 15:28.
|
|
|
|
21.01.2024, 16:59
|
|
Почётный гражданин KAZUS.RU
Регистрация: 29.10.2006
Сообщений: 1,446
Сказал спасибо: 99
Сказали Спасибо 317 раз(а) в 233 сообщении(ях)
|
Re: Таймер на AVR ATMEGA128
Сообщение от Devil Byte
|
Поучается что в принципе i можно исключить?
|
Да
Но можно сделать так:
PHP код:
|
i = timer_select; if(i › 1) i++; if(i › 4) i++; Lcd_line (i * 6, 9, i * 6 + 4, 9, line); Lcd_update();
|
Сообщение от Devil Byte
|
Тут же явно не указаны пины кнопок. Как происходит определение пина? Почему они имеют именно такое значение
|
Как раз тут они явно и указаны. Я не знаю, куда они у вас подключены. Я их подключил на порт D (во вложении я выкладывал файл протеуса и прошивку).
Сообщение от Devil Byte
|
И не будет ли дребезга на реальном девайсе?
|
Тут применён именно антидребезговый алгоритм. Лучше, конечно, опрашивать с интервалом 50 мс, но и 100 сойдёт.
Сообщение от Devil Byte
|
как на таймере при включение появляется единица в десятках часов??
|
При объявлении переменных явно задана.
Только не в десятках часов (у вас вроде как минуты максимум, а не часы), а в десятках секунд.
Последний раз редактировалось Godzilla82; 21.01.2024 в 17:02.
|
|
|
|
21.01.2024, 18:32
|
|
Временная регистрация
Регистрация: 07.03.2019
Сообщений: 87
Сказал спасибо: 11
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: Таймер на AVR ATMEGA128
Сообщение от Godzilla82
|
Как раз тут они явно и указаны.
|
Тогда я не совсем понимаю.... например #define KEY_PAUSE 0x10
В двоичной системе это 22, а в десятичной 16, но в порте D эта кнопка сидит на 4 пине...
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 22:25.
|
|