Индикатор с обратным отсчетом на ATmega88PA

Обсуждаем контроллеры компании Atmel.
Ответить
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Сообщение service47 »

Здравствуйте. Имеется программа на Си в Atmel Studio 6, программатор и платка с микроконтроллером ATmega88PA (+datasheet), на которой есть один восьмисегментный индикатор, один светодиод и две кнопки SMD. Программа должна: при запуске отображать на индикаторе цифру 6, при нажатии Кнопки1 уменьшить цифру на 1, при нажатии Кнопки2 увеличить цифру на 1, а при нажатии обоих кнопок одновременно и удержании в течении 3ех секунд запустить алгоритм обратного отсчета, т.е. от того значения, которое на индикаторе и при достижении нуля зажечь светодиодик.

Программа, которая есть: При запуске отображается цифра 6, при нажатии кнопок значение увеличивается и уменьшается на 1 (от 6ти до 1го). Не работает одновременное нажатие кнопок, алгоритм обратного отсчета прописан (если к примеру установлена цифра 5 то через пять секунд загориться светодиод). На неоптимизированность программы внимания не обращать. Нужно прописать в коде так, чтобы при одновременном нажатии двух кнопок запустился алгоритм обратного отсчета. Кнопки управляют прерываниями INT0 и INT1.
Спойлер

Код: Выделить всё


#define F_CPU 1000000UL

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

unsigned char s=6; //Переменная цифры

#define FALSHE 0
#define TRUE 1
volatile _Bool d=FALSHE;


//Программа индикации цифры 6
void ind_6 (unsigned int a)
{
	PORTC &= ~_BV(PC0);
	PORTC &= ~_BV(PC1);
	PORTC |= _BV(PC2);
	PORTC &= ~_BV(PC3);
	PORTC &= ~_BV(PC4);
	PORTB &= ~_BV(PB6);
	PORTB &= ~_BV(PB7);	
}

//Программа индикации цифры 5
void ind_5 (unsigned int a)
{
	PORTC &= ~_BV(PC0);
	PORTC &= ~_BV(PC1);
	PORTC |= _BV(PC2);
	PORTC &= ~_BV(PC3);
	PORTC &= ~_BV(PC4);
	PORTB &= ~_BV(PB6);
	PORTB |= _BV(PB7);
}

//Программа индикации цифры 4
void ind_4 (unsigned int a)
{
	PORTC &= ~_BV(PC0);
	PORTC &= ~_BV(PC1);
	PORTC &= ~_BV(PC2);
	PORTC |= _BV(PC3);
	PORTC &= ~_BV(PC4);
	PORTB |= _BV(PB6);
	PORTB |= _BV(PB7);
}

//Программа индикации цифры 3
void ind_3 (unsigned int a)
{
	PORTC &= ~_BV(PC0);
	PORTC |= _BV(PC1);
	PORTC &= ~_BV(PC2);
	PORTC &= ~_BV(PC3);
	PORTC &= ~_BV(PC4);
	PORTB &= ~_BV(PB6);
	PORTB |= _BV(PB7);
}

//Программа индикации цифры 2
void ind_2 (unsigned int a)
{
	PORTC &= ~_BV(PC0);
	PORTC |= _BV(PC1);
	PORTC &= ~_BV(PC2);
	PORTC &= ~_BV(PC3);
	PORTC |= _BV(PC4);
	PORTB &= ~_BV(PB6);
	PORTB &= ~_BV(PB7);
}

//Программа индикации цифры 1
void ind_1 (unsigned int a)
{
	PORTC |= _BV(PC0);
	PORTC |= _BV(PC1);
	PORTC &= ~_BV(PC2);
	PORTC |= _BV(PC3);
	PORTC &= ~_BV(PC4);
	PORTB |= _BV(PB6);
	PORTB |= _BV(PB7);
}

//Программа индикации цифры 0
void ind_0 (unsigned int a)
{
	PORTC |= _BV(PC0);
	PORTC &= ~_BV(PC1);
	PORTC &= ~_BV(PC2);
	PORTC &= ~_BV(PC3);
	PORTC &= ~_BV(PC4);
	PORTB &= ~_BV(PB6);
	PORTB &= ~_BV(PB7);
}

//Программа задержки
void pause (unsigned int a)
{
	unsigned int i; //декларация переменной для программы задержки
	for (i=a;i>0;i--); //Основной цикл программы задержки
}

void start (unsigned int a)
{
	EIMSK=0b00000000; //запрещаем прерывание int0 и int1 - кнопка
	cli();//запрещение прерываний на время обработки прерывания
	while(s=6){ ind_6(s); _delay_ms(1000); ind_5(s); _delay_ms(1000); ind_4(s); _delay_ms(1000); ind_3(s); _delay_ms(1000); ind_2(s); _delay_ms(1000); ind_1(s); _delay_ms(1000); ind_0(s); PORTD &= ~_BV(PD0); PORTD |= _BV(PD0); _delay_ms(250); PORTD &= ~_BV(PD1); PORTD |= _BV(PD1); PORTD &= ~_BV(PD4);
	PORTD |= _BV(PD4);}
	while(s=5){ ind_5(s); _delay_ms(1000); ind_4(s); _delay_ms(1000); ind_3(s); _delay_ms(1000); ind_2(s); _delay_ms(1000); ind_1(s); _delay_ms(1000); ind_0(s); PORTD &= ~_BV(PD0); PORTD |= _BV(PD0); _delay_ms(250); PORTD &= ~_BV(PD1); PORTD |= _BV(PD1); }
	while(s=4){ ind_4(s); _delay_ms(1000); ind_3(s); _delay_ms(1000); ind_2(s); _delay_ms(1000); ind_1(s); _delay_ms(1000); ind_0(s); PORTD &= ~_BV(PD0); PORTD |= _BV(PD0); _delay_ms(250); PORTD &= ~_BV(PD1); PORTD |= _BV(PD1); }
	while(s=3){ ind_3(s); _delay_ms(1000); ind_2(s); _delay_ms(1000); ind_1(s); _delay_ms(1000); ind_0(s); PORTD &= ~_BV(PD0); PORTD |= _BV(PD0); _delay_ms(250); PORTD &= ~_BV(PD1); PORTD |= _BV(PD1); }
	while(s=2){ ind_2(s); _delay_ms(1000); ind_1(s); _delay_ms(1000); ind_0(s); PORTD &= ~_BV(PD0); PORTD |= _BV(PD0); _delay_ms(250); PORTD &= ~_BV(PD1); PORTD |= _BV(PD1); }
	while(s=1){ ind_1(s); _delay_ms(1000); ind_0(s); PORTD &= ~_BV(PD0); PORTD |= _BV(PD0); _delay_ms(250); PORTD &= ~_BV(PD1); PORTD |= _BV(PD1); }
	sei();//разрешение прерываний
}

ISR(INT1_vect) {
	_delay_ms(150);
	    cli();//запрещение прерываний на время обработки прерывания
	    s=s-1;

	    sei();//разрешение прерываний
							if (INT0 == FALSHE)
							{

							}
							else
							{	start(s);
							}
}

ISR(INT0_vect) {
	_delay_ms(150);
	cli();//запрещение прерываний на время обработки прерывания
	s=s+1;

	sei();//разрешение прерываний
							if (INT1 == TRUE)
							{

							}
							else
							{	start(s);
							}
}

int main(void)
{
	DDRC=0x3f; 
	PORTC=0x00;
	DDRD=0x0C;
	PORTD=0xff;
	DDRB=0xC0;
	PORTB=0x00;


	EICRA  =  (1<<ISC11) | (1<<ISC10) | (1<<ISC01) | (1<<ISC00);// настройка срабатывания прерываний
	PCICR  |= (1<<PCIE2) | (0<<PCIE1) | (0<<PCIE0);// разрешение прерываний с портов...
    PCMSK2=0b10000000; //разрешаем прерывание pcint23
    EIMSK=0b11000011; //разрешаем прерывание int0 и int1 - кнопка
    MCUCR=0b00001111;// int by rising front - для кнопки 1 и 2    
	
    sei(); //Глобальное разрешение прерываний
    while(1)
    {

	if (s > 6) 
	{
		s--;
	}
	else
	{
	}
	
		if (s == 0)
		{
			s++;
		}
		else
		{
		}
		
	
		
	cli(); //запрещение прерываний
	if (s == 6) //Если переменная равна 6
	{
		ind_6(s); //Выводим на индикатор цифру
	}
	else
	{
		if (s == 5) //Если переменная равна 5
		{
			ind_5(s); //Выводим на индикатор цифру
		}
		else
		{
			if (s == 4) //Если переменная равна 4
			{
				ind_4(s); //Выводим на индикатор цифру
			}
			else
			{
				if (s == 3) //Если переменная равна 3
				{
					ind_3(s); //Выводим на индикатор цифру
				}
				else
				{
					if (s == 2) //Если переменная равна 2
					{
						ind_2(s); //Выводим на индикатор цифру
					}
					else
					{
						if (s == 1) //Если переменная равна 1
						{
							ind_1(s); //Выводим на индикатор цифру
						}
						else
						{

						}
					}
				}
			}
		}
	}
		
		sei(); //Разрешить прерывания
		pause(1000); //Пауза
    }
}
ДАТАШИТ на ATmega88: (8Мб) - http://upwap.ru/3044765
Реклама
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1663
Зарегистрирован: Вт апр 03, 2012 20:36:41
Откуда: Сочи

Сообщение Enigm »

Ищите другой алгоритм.
И хорошенько почитайте про прерывания и их условия работы.(как вы собрались обработать, одновременно два прерывания ?)
Реклама
Прорезались зубы
Аватара пользователя
Сообщения: 202
Зарегистрирован: Пн сен 26, 2011 13:48:25
Откуда: Харьков

Сообщение slavokhire5 »

Доброго времени суток:)
Ваш код не смотрел, простите. Уж много очень
По поводу алгоритма опроса 2-х кнопок и именно INT0 и INT1 можно сделать как-то так:

Код: Выделить всё

#define COUNTDOWN 1
#define PLUS             2
#define MINUS           4

volatile char FLAG = 0;

(обработка INT0)
{
      _delay_ms(100);                                                 // возможно слегка не синхронное нажатие 2 кнопки. ждем-с
      char i = 0;
      if (вывод int1 != 1) 
             FLAG |= PLUS;
      while((вывод int0 == 1) && (вывод int1 == 1))
      {
             _delay_ms(100);
             i++;
             if (i >= 30)
             {
                       FLAG |= COUNTDOWN;
                       break;
              }
        }
        вручную очистить флаги прерываний int0 и int1;
} 

}
*вроде бы так
аналогично в обработчике 2-го прерывания.
задержки в прерываниях не красиво, конечно. если есть свободный таймер, можно его взводить на 100мс (или др. время) по прерыванию от INTx и отпускать программу в свободное плавание.
*если зажмете 2 кнопки менее чем на 3с, выполнится то действие, на которое контроллер раньше среагировал
Осилит дорогу идущий
--------------------------
Пишу на Си за еду
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Сообщение service47 »

2 slavokhire5
Спасибо за алгоритм, у вас в условии if фигурная скобка не открыта, сделал, прошил, не работает. Может в обработчиках прерываний напортачил...

Код: Выделить всё

#define COUNTDOWN 1
#define PLUS             2
#define MINUS           4

volatile char FLAG = 0;


ISR(INT1_vect) {
	_delay_ms(150);
	    cli();//запрещение прерываний на время обработки прерывания
		s--;
	    sei();//разрешение прерываний
		
_delay_ms(100);
char i = 0;
if ( PIND2 != 1){
FLAG |= PLUS;
while((PIND3 == 1) && (PIND2 == 1))
{
	_delay_ms(100);
	i++;
	if (i >= 30)
	{
		FLAG |= COUNTDOWN;
		start(s);
		break;
	}
}}		
EIFR = 0b00000000; //External interrupt flag register
}

ISR(INT0_vect) {
	_delay_ms(150);
	cli();//запрещение прерываний на время обработки прерывания
	s++;
	sei();//разрешение прерываний

_delay_ms(100); 
 char i = 0;
 if ( PIND3 != 1){
 FLAG |= PLUS;
while((PIND2 == 1) && (PIND3 == 1))
{
	_delay_ms(100);
	i++;
	if (i >= 30)
	{
		FLAG |= COUNTDOWN;
		start(s);
		break;
	}
}}
EIFR = 0b00000000; //External interrupt flag register
}
Реклама
Эиком - электронные компоненты и радиодетали
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 330
Зарегистрирован: Чт июн 23, 2011 07:55:51

Сообщение korsaj »

Код: Выделить всё

       cli();//запрещение прерываний на время обработки прерывания
       sei();//разрешение прерываний
"Масло масленное" )
Это лишнее, он железом сбрасывается и обратно устонавливается
Реклама
Прорезались зубы
Аватара пользователя
Сообщения: 202
Зарегистрирован: Пн сен 26, 2011 13:48:25
Откуда: Харьков

Сообщение slavokhire5 »

у if нет фигурных скобок, т.к. они там не нужны) если в конструкции if всего одно действие (а у меня одно), то скобки можно не ставить)
поставив скобку, вы изменили алгоритм.
по вашему алгоритму вы проверяете, равен ли PIND2 единице. если не равен, то тут же!! входим в цикл вайл, удостоверяемся еще раз, что не равен и вываливаемся)
я ваш код попробовал слегка подправить. хотя в протеусе не гонял)
Спойлер

Код: Выделить всё

ISR(INT1_vect) 
{
	_delay_ms(150);
	char i = 0;
	if ( PIND2 != 1)
	        FLAG |= PLUS;                             // тут выставляется флаг. основная программа, увидев его после прерывания, увеличивает цифру на индикатор
	while((PIND3 == 1) && (PIND2 == 1))
	{
		_delay_ms(100);
		i++;
		if (i >= 30)
		{
			FLAG |= COUNTDOWN;
			start(s);
			break;
		}
	}
 	EIFR = 0b00000000; //External interrupt flag register
}
Осилит дорогу идущий
--------------------------
Пишу на Си за еду
Реклама
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Сообщение service47 »

Вообщем не работает, хотя теоретически код д.б. рабочий. Прописал в цикле основного тела проги условия на флаги, но после прошивки МК запускается автоматом подпрограмма start(s);, если этот блок while удалить и оставить только условия на флаги плюс и минус, то кнопки тоже не работают.

Код: Выделить всё


#define F_CPU 1000000UL

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

unsigned char s=6; //Переменная цифры

#define COUNTDOWN 1
#define PLUS             2
#define MINUS           4

volatile char FLAG = 0;


//Программа индикации цифры 6
void ind_6 (unsigned int a)
{
	PORTC &= ~_BV(PC0);
	PORTC &= ~_BV(PC1);
	PORTC |= _BV(PC2);
	PORTC &= ~_BV(PC3);
	PORTC &= ~_BV(PC4);
	PORTB &= ~_BV(PB6);
	PORTB &= ~_BV(PB7);	
}

//Программа индикации цифры 5
void ind_5 (unsigned int a)
{
	PORTC &= ~_BV(PC0);
	PORTC &= ~_BV(PC1);
	PORTC |= _BV(PC2);
	PORTC &= ~_BV(PC3);
	PORTC &= ~_BV(PC4);
	PORTB &= ~_BV(PB6);
	PORTB |= _BV(PB7);
}

//Программа индикации цифры 4
void ind_4 (unsigned int a)
{
	PORTC &= ~_BV(PC0);
	PORTC &= ~_BV(PC1);
	PORTC &= ~_BV(PC2);
	PORTC |= _BV(PC3);
	PORTC &= ~_BV(PC4);
	PORTB |= _BV(PB6);
	PORTB |= _BV(PB7);
}

//Программа индикации цифры 3
void ind_3 (unsigned int a)
{
	PORTC &= ~_BV(PC0);
	PORTC |= _BV(PC1);
	PORTC &= ~_BV(PC2);
	PORTC &= ~_BV(PC3);
	PORTC &= ~_BV(PC4);
	PORTB &= ~_BV(PB6);
	PORTB |= _BV(PB7);
}

//Программа индикации цифры 2
void ind_2 (unsigned int a)
{
	PORTC &= ~_BV(PC0);
	PORTC |= _BV(PC1);
	PORTC &= ~_BV(PC2);
	PORTC &= ~_BV(PC3);
	PORTC |= _BV(PC4);
	PORTB &= ~_BV(PB6);
	PORTB &= ~_BV(PB7);
}

//Программа индикации цифры 1
void ind_1 (unsigned int a)
{
	PORTC |= _BV(PC0);
	PORTC |= _BV(PC1);
	PORTC &= ~_BV(PC2);
	PORTC |= _BV(PC3);
	PORTC &= ~_BV(PC4);
	PORTB |= _BV(PB6);
	PORTB |= _BV(PB7);
}

//Программа индикации цифры 0
void ind_0 (unsigned int a)
{
	PORTC |= _BV(PC0);
	PORTC &= ~_BV(PC1);
	PORTC &= ~_BV(PC2);
	PORTC &= ~_BV(PC3);
	PORTC &= ~_BV(PC4);
	PORTB &= ~_BV(PB6);
	PORTB &= ~_BV(PB7);
}

//Программа задержки
void pause (unsigned int a)
{
	unsigned int i; //декларация переменной для программы задержки
	for (i=a;i>0;i--); //Основной цикл программы задержки
}

void start (unsigned int a)
{
	EIMSK=0b00000000; //запрещаем прерывание int0 и int1 - кнопка
	cli();//запрещение прерываний на время обработки прерывания
	while(s=6){ ind_6(s); _delay_ms(1000); ind_5(s); _delay_ms(1000); ind_4(s); _delay_ms(1000); ind_3(s); _delay_ms(1000); ind_2(s); _delay_ms(1000); ind_1(s); _delay_ms(1000); ind_0(s); PORTD &= ~_BV(PD0); PORTD |= _BV(PD0); _delay_ms(250); PORTD &= ~_BV(PD1); PORTD |= _BV(PD1); PORTD &= ~_BV(PD4);
	PORTD |= _BV(PD4);}
	while(s=5){ ind_5(s); _delay_ms(1000); ind_4(s); _delay_ms(1000); ind_3(s); _delay_ms(1000); ind_2(s); _delay_ms(1000); ind_1(s); _delay_ms(1000); ind_0(s); PORTD &= ~_BV(PD0); PORTD |= _BV(PD0); _delay_ms(250); PORTD &= ~_BV(PD1); PORTD |= _BV(PD1); }
	while(s=4){ ind_4(s); _delay_ms(1000); ind_3(s); _delay_ms(1000); ind_2(s); _delay_ms(1000); ind_1(s); _delay_ms(1000); ind_0(s); PORTD &= ~_BV(PD0); PORTD |= _BV(PD0); _delay_ms(250); PORTD &= ~_BV(PD1); PORTD |= _BV(PD1); }
	while(s=3){ ind_3(s); _delay_ms(1000); ind_2(s); _delay_ms(1000); ind_1(s); _delay_ms(1000); ind_0(s); PORTD &= ~_BV(PD0); PORTD |= _BV(PD0); _delay_ms(250); PORTD &= ~_BV(PD1); PORTD |= _BV(PD1); }
	while(s=2){ ind_2(s); _delay_ms(1000); ind_1(s); _delay_ms(1000); ind_0(s); PORTD &= ~_BV(PD0); PORTD |= _BV(PD0); _delay_ms(250); PORTD &= ~_BV(PD1); PORTD |= _BV(PD1); }
	while(s=1){ ind_1(s); _delay_ms(1000); ind_0(s); PORTD &= ~_BV(PD0); PORTD |= _BV(PD0); _delay_ms(250); PORTD &= ~_BV(PD1); PORTD |= _BV(PD1); }
	sei();//разрешение прерываний
}

ISR(INT1_vect) {
_delay_ms(150);
char i = 0;
if ( PIND2 != 1)
FLAG |= MINUS;                             // тут выставляется флаг. основная программа, увидев его после прерывания, уменьшает цифру на индикатор
while((PIND3 == 1) && (PIND2 == 1))
{
	_delay_ms(100);
	i++;
	if (i >= 30)
	{
		FLAG |= COUNTDOWN;
		break;
	}
}
EIFR = 0b00000000; //External interrupt flag register
}

ISR(INT0_vect) {
   _delay_ms(150);
   char i = 0;
   if ( PIND3 != 1)
   FLAG |= PLUS;                             // тут выставляется флаг. основная программа, увидев его после прерывания, увеличивает цифру на индикатор
   while((PIND3 == 1) && (PIND2 == 1))
   {
	   _delay_ms(100);
	   i++;
	   if (i >= 30)
	   {
		   FLAG |= COUNTDOWN;
		   break;
	   }
   }
   EIFR = 0b00000000; //External interrupt flag register
}

int main(void)
{
	DDRC=0x3f; 
	PORTC=0x00;
	DDRD=0x0C;
	PORTD=0xff;
	DDRB=0xC0;
	PORTB=0x00;


	EICRA  =  (1<<ISC11) | (0<<ISC10) | (1<<ISC01) | (0<<ISC00);// настройка срабатывания прерываний
	PCICR  |= (1<<PCIE2) | (0<<PCIE1) | (0<<PCIE0);// разрешение прерываний с портов B (PCINT[7:0]) и D (PCINT[23:16]), и запрет с порта C (PCINT[14:8])
    PCMSK2=0b10000000; //разрешаем прерывание pcint23
    EIMSK=0b11000011; //разрешаем прерывание int0 и int1 - кнопка
    MCUCR=0b00001111;// int by rising front - для кнопки 1 и 2    
	
    sei(); //Глобальное разрешение прерываний
    while(1)
    {

	if (s > 6) 
	{
		s--;
	}
	else
	{
	}
	
		if (s == 0)
		{
			s++;
		}
		else
		{
		}


for (FLAG = MINUS; FLAG == MINUS; FLAG++)
{
	s--;
}
for (FLAG = PLUS; FLAG == PLUS; FLAG--)
{
	s++;
}
while (FLAG = COUNTDOWN)
{
	FLAG = FLAG - 1;
	start(s);
}

	
		
	cli(); //запрещение прерываний
	if (s == 6) //Если переменная равна 6
	{
		ind_6(s); //Выводим на индикатор цифру
	}
	else
	{
		if (s == 5) //Если переменная равна 5
		{
			ind_5(s); //Выводим на индикатор цифру
		}
		else
		{
			if (s == 4) //Если переменная равна 4
			{
				ind_4(s); //Выводим на индикатор цифру
			}
			else
			{
				if (s == 3) //Если переменная равна 3
				{
					ind_3(s); //Выводим на индикатор цифру
				}
				else
				{
					if (s == 2) //Если переменная равна 2
					{
						ind_2(s); //Выводим на индикатор цифру
					}
					else
					{
						if (s == 1) //Если переменная равна 1
						{
							ind_1(s); //Выводим на индикатор цифру
						}
						else
						{

						}
					}
				}
			}
		}
	}
		
		sei(); //Разрешить прерывания
		pause(1000); //Пауза
    }
}
Последний раз редактировалось service47 Чт мар 14, 2013 08:40:09, всего редактировалось 1 раз.
Прорезались зубы
Аватара пользователя
Сообщения: 202
Зарегистрирован: Пн сен 26, 2011 13:48:25
Откуда: Харьков

Сообщение slavokhire5 »

*не выкладывайте такую простыню кода. а то модератор по рукам надает ) "сворачивайте" его тегом quote.
вот так:
Спойлер
вам нужно подучить язык Си. начать можно с книги Брайан Керниган, Деннис Ритчи: Язык программирования C.
у вас очень много лишних действий.
допустим, цифры вы выводите таким образом
Спойлер

Код: Выделить всё

void ind_0 (unsigned int a)
{
   PORTC |= _BV(PC0);
   PORTC &= ~_BV(PC1);
   PORTC &= ~_BV(PC2);
   PORTC &= ~_BV(PC3);
   PORTC &= ~_BV(PC4);
   PORTB &= ~_BV(PB6);
   PORTB &= ~_BV(PB7);
}
во-первых пропущена 5-я нога мк, во-вторых вместо 7-и функций для 7-и цифр можно использовать один массив char на 7 элементов. *в идеале структуру использовать, но я с ними не дружу
при использовании массива ваша конструкция
Спойлер

Код: Выделить всё

if (s == 6) //Если переменная равна 6
   {
      ind_6(s); //Выводим на индикатор цифру
   }
   else
   {
      if (s == 5) //Если переменная равна 5
      {
         ind_5(s); //Выводим на индикатор цифру
      }
      else
      {
         if (s == 4) //Если переменная равна 4
         {
            ind_4(s); //Выводим на индикатор цифру
         }
         else
         {
            if (s == 3) //Если переменная равна 3
            {
               ind_3(s); //Выводим на индикатор цифру
            }
            else
            {
               if (s == 2) //Если переменная равна 2
               {
                  ind_2(s); //Выводим на индикатор цифру
               }
               else
               {
                  if (s == 1) //Если переменная равна 1
                  {
                     ind_1(s); //Выводим на индикатор цифру
                  }
                  else
                  {

                  }
               }
            }
         }
      }
привратится в

Код: Выделить всё

PORTC = digits[s];
, где digits[] - массив просчитанных цифр, s - порядковый номер цифры в массиве

по удобочитаемости кода: не делайте слишком длинных строк! туго читается. а в некоторых конторах и по рукам за такое надают)
при использовании конструкции условия if наличие пустого else совсем не обязательно. если в фигурных скобках ничего не стоит, компилятор просто выкинет else. учитесь писать по возможности кратко
Осилит дорогу идущий
--------------------------
Пишу на Си за еду
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Сообщение service47 »

Спасибо, язык си буду изучать потихоньку.
5-я нога мк это точка на индикаторе и роли не играет.
А насчет описания флагов в основном теле программы можете помочь, а то у меня код такой и после прошивки автоматом запускается подпрограмма start(s); а кнопки увеличения и уменьшения на единичку не работают даже если удалить этот while. Но если в обработчиках прерываний добавить s--; и s++; для каждого соответственно, то цифра как и положено увеличивается и уменьшается.

Код: Выделить всё

for (FLAG = MINUS; FLAG == MINUS; FLAG++)
{
   s--;
}
for (FLAG = PLUS; FLAG == PLUS; FLAG--)
{
   s++;
}
while (FLAG = COUNTDOWN)
{
   FLAG = FLAG - 1;
   start(s);
}
Прорезались зубы
Аватара пользователя
Сообщения: 202
Зарегистрирован: Пн сен 26, 2011 13:48:25
Откуда: Харьков

Сообщение slavokhire5 »

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

Код: Выделить всё

for (FLAG = MINUS; FLAG == MINUS; FLAG++)
{
   s--;
}
смысл флагов немного не такой) по какому-то событию в переменной FLAG выставляем соответствующий бит. и в нужных местах просматриваем переменную. ее не инкриминируют, пользуются битовыми операциями.
в своем for вы присвоили!! переменной FLAG значение MINUS, проверили равна ли она MINUS, а потом ее инкриментировали)

более правильное использование флагов

Код: Выделить всё

if (FLAG & MINUS)      
{
        function();
        FLAG &= ~MINUS;          // после обработки флага убираем его
}

еще раз. учите язык. си за 24, конечно, не выучить, но за неделю-другую по основам можно подтянуться.
Вложения
indicator.c
код переписал. не компилировал (мб ошибки). регистры при инициализации ваши не проверил
(1.86 КБ) 402 скачивания
Осилит дорогу идущий
--------------------------
Пишу на Си за еду
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Сообщение service47 »

Прошил программой. Результат тот же, цикл while с объединением логическим И пинов порта D 2 и 3 не запускается, и еще видимо с массивом напутал т.к. все цифры отображаются нормально, а цифра 6 неправильно. Вобщем я еще до вечера попрограммирую. Тег quote почему-то не прячет код. :)

UP! Замерял тестером напряжение на пине D2 = ~3V, а при нажатой кнопке ~0V.

Код: Выделить всё

#define F_CPU 1000000UL

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

#define COUNTDOWN 1

volatile char FLAG 			= 0;
volatile char s 				= 6; 	//Переменная цифры

// массив знаков на индикатор
char digits[6] = {0b11100001, 0b11101011, 0b11110010, 0b11100010, 0b11101000, 0b11100100, 0b11100100}; //0,1,2,3,4,5,6
char digita[6] = {0b00111111, 0b11111111, 0b00111111, 0b10111111, 0b11111111, 0b10111111, 0b00111111};


ISR(INT1_vect) 
{
	_delay_ms(300);
	char i = 0;
	if ( PIND2 != 1)
		s--;                             		
	while((PIND3 == 1) && (PIND2 == 1))
	{
		_delay_ms(100);
		i++;
		if (i >= 30)
		{
			FLAG |= COUNTDOWN;
			break;
		}
	}
	EIFR = 0b00000000; //External interrupt flag register
}

ISR(INT0_vect) 
{
	_delay_ms(300);
	char i = 0;
	if ( PIND3 != 1)
		s++;                             		
	while((PIND3 == 1) && (PIND2 == 1))
	{
		_delay_ms(100);
		i++;
		if (i >= 30)
		{
			FLAG |= COUNTDOWN;
			break;
		}
	}
	EIFR = 0b00000000; //External interrupt flag register
}


int main(void)
{
	DDRC=0x3f;  //0b00111111
	PORTC=0x00;
	DDRD=0x0C; //0b00001100
	PORTD=0xff;
	DDRB=0xC0; //0b11000000
	PORTB=0x00;


	EICRA  =  (1<<ISC11) | (0<<ISC10) | (1<<ISC01) | (0<<ISC00);		// настройка срабатывания прерываний
	PCICR  |= (1<<PCIE2) | (0<<PCIE1) | (0<<PCIE0);// разрешение прерываний с портов...
	PCMSK2=0b10000000; //разрешаем прерывание pcint23
    EIMSK=0b11000011; //разрешаем прерывание int0 и int1 - кнопка
    MCUCR=0b00001111;// int by rising front - для кнопки 1 и 2    
    sei(); //Глобальное разрешение прерываний
	
	
    while(1)
    {
		if (s > 6) 
			s--;
		else if (s == 0)
			s++;
		if (FLAG == COUNTDOWN)
		{
			cli();						
			while (s > -1)
			{
				PORTC = digits[s];
				PORTB = digita[s];
				_delay_ms(1000);		// слишком длинные задержки функция _delay_ms не любит. нужно проверить для вашего случая
				s--;   
			}
			sei();
			FLAG &= ~ COUNTDOWN;
		}
		PORTC = digits[s];	
		PORTB = digita[s];		
    }
}
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Сообщение service47 »

Удалось сделать чтобы при нажатии кнопок 1 и 2, соответственно увеличивалось и уменьшалось значение на индикаторе на единичку, далее при одновременном нажатии двух кнопок запускается алгоритм обратного отсчета (вот только кнопки сложно нажать одновременно, там отслеживаются флаги прерываний (раза с треьего-пятого получается)), нужно сделать так чтобы после запуска обратного отсчета можно было нажать одновременно две кнопки и при этом обратный отсчет остановился.

Спойлер

Код: Выделить всё

#define F_CPU 1000000UL

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

#define COUNTDOWN 1

volatile char FLAG = 0;
volatile char s = 6; 	//Переменная цифры
volatile char a = 6;
volatile char b = 1;

// массив знаков на индикатор
char digits[9] = {0b11100001, 0b11101011, 0b11110010, 0b11100010, 0b11101000, 0b11100100, 0b11100100, 0b11100011, 0b11100000, 0b11100000}; //0,1,2,3,4,5,6,7,8,9
char digita[9] = {0b00111111, 0b11111111, 0b00111111, 0b10111111, 0b11111111, 0b10111111, 0b00111111, 0b11111111, 0b00111111, 0b10111111};


ISR(INT1_vect)  //MINUS PIND3
{
	_delay_ms(300);
	char i = 0;
	if (PIND3 == 3)   
		{s--;}                             		
	if (EIFR == 0b00000011)
	FLAG |= COUNTDOWN;
	//EIFR = 0b00000000; //External interrupt flag register
}

ISR(INT0_vect)  //PLUS PIND2
{
	_delay_ms(300); 
	char i = 0; 
	if (PIND3 == 3)	
		{s++;}                             		
	if (EIFR == 0b00000011)
	FLAG |= COUNTDOWN;
	//EIFR = 0b00000000; //External interrupt flag register
}


int main(void)
{
	DDRC=0x3f;  //0b00111111
	PORTC=0x00;
	DDRD=0x0C; //0b00001100
	PORTD=0xff;
	DDRB=0xC0; //0b11000000
	PORTB=0x00;

	EICRA  =  (1<<ISC11) | (0<<ISC10) | (1<<ISC01) | (0<<ISC00);	// настройка срабатывания прерываний The falling edge of INT1 generates an interrupt request
	PCICR  |= (1<<PCIE2) | (0<<PCIE1) | (0<<PCIE0);// разрешение прерываний с портов...
	PCMSK2=0b10000000; //разрешаем прерывание pcint23
    EIMSK=0b11000011; //разрешаем прерывание int0 и int1 - кнопка
    MCUCR=0b00001111;// int by rising front - для кнопки 1 и 2    
    sei(); //Глобальное разрешение прерываний
	
    while(1)
    {			
			if (b == 1)
			{s=5;
				FLAG &= ~ COUNTDOWN;
				b++;
			}						
							
		if (s > 9) 
			s--;
		else if (s == 0)
			s++;
		if (FLAG == COUNTDOWN)
		{
			cli();						
			while (s > -1)
			{
				if (s > -1)
				{
					PORTC |= _BV(PC5); // чтобы мигала точка на индикаторе
					_delay_ms(250);
					PORTC &= ~_BV(PC5);
					_delay_ms(250);
				}					
				PORTC = digits[s];
				PORTB = digita[s];
				_delay_ms(1000);	
				s--;   
			}
			sei();
			FLAG &= ~ COUNTDOWN;
		}
		PORTC = digits[s];	
		PORTB = digita[s];		
    }
}
Ответить

Вернуться в «AVR»