Протеус + AVR динамическая индикация.

Обсуждаем контроллеры компании Atmel.
Ответить
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 303
Зарегистрирован: Ср май 03, 2017 03:22:26

Сообщение 7seg »

Не могу правильно настроить динамическую индикацию.
В протеусе она как то прерывисто перекулючаеться.
можете подсказать где проблема.?

Код програмы:

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

#define F_CPU   8000000         //Hz

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

#define T0_TICK_RATE    100     // Hz
#define T0_CLK  ((F_CPU)/1024)
#define T0_TICKS  (0x100 - T0_CLK / T0_TICK_RATE)

#define DEBOUNCE_TIME 			20

#define BUTTON_PIN 				PINB
#define POWER_BIT				PB3
#define UP_BIT					PB4
#define DOWN_BIT				PB5

#define KEY_POWER			0b00001000
#define KEY_DOWN			0b00100000
#define KEY_UP				0b00010000

volatile unsigned char data1;
volatile unsigned char data2;
volatile unsigned char value;
volatile int _buzzer = 0;
volatile int _pressed = 0;


void init_io();
void segchar(unsigned char seg);
void handle_button(int key);
void handle_buttons();
void process_power();
void process_up();
void process_down();

int main(void)
{
	value=0;
	init_io();
	sei();
	while(1)
	{
		handle_buttons();
	}
	return 0;
}


void segchar (unsigned char seg)
{
	switch (seg)
	{
		case 1: PORTA = 0b01111100; break;
		case 2: PORTA = 0b10000100; break;
		case 3: PORTA = 0b01000100; break;
		case 4: PORTA = 0b01101000; break;
		case 5: PORTA = 0b01000010; break;
		case 6: PORTA = 0b00000010; break;
		case 7: PORTA = 0b01110100; break;
		case 8: PORTA = 0b00000000; break;
		case 9: PORTA = 0b01000000; break;
		case 0: PORTA = 0b00010000; break;
	}
}

void init_io()
{
	//порт, к которому подкл. сегменты
	PORTA = 0xff;
	DDRA = 0xff;
	//порт, к которому подкл. катод
	DDRB |=(1<<0)|(1<<1)|(1<<2);
	PORTB =0x00;
	//инициализация таймера Т0
	TIMSK = (1<<TOIE0);
	TCCR0 = (1<<CS02)|(0<<CS01)|(1<<CS00);
	TCNT0 =  T0_TICKS;
}

//прерывания таймера Т0 - вывод на индикатор
ISR(TIMER0_OVF0_vect)
{
	static unsigned char count = 0;
	TCNT0 += T0_TICKS;
	//гасим оба разряда
	PORTB &= ~((1<<2)|(1<<0));
	//зажигаем следующий разряд
	if (count == 0)
	{
		segchar(data2);
		PORTB |= ~(1<<2);
	}
	if (count == 1)
	{
		segchar(data1);
		PORTB |= ~(1<<0);
	}
	count++;
	if (count == 2) count = 0;
}

void handle_button(int key)
{
	int bit;
	switch (key)
	{
		case KEY_POWER: 	bit = POWER_BIT; break;
		case KEY_UP: 	bit = UP_BIT; break;
		case KEY_DOWN: 	bit = DOWN_BIT; break;
		default: return;
	}

	if (bit_is_clear(BUTTON_PIN, bit))
	{
		if (_pressed == 0)
		{
			_delay_ms(DEBOUNCE_TIME);
			if (bit_is_clear(BUTTON_PIN, bit))
			{
				_pressed |= key;
				
				// key action
				switch (key)
				{
					case KEY_POWER: process_power(); break;
					case KEY_UP: 	process_up(); break;
					case KEY_DOWN: 	process_down(); break;
				}
			}
		}
	}
	else
	{
		_pressed &= ~key;
	}
}

void handle_buttons()
{
	handle_button(KEY_POWER);
	handle_button(KEY_DOWN);
	handle_button(KEY_UP);
}

void process_power()
{

}
void process_up()
{
	if (value < 99)
	{
		value++;
		unsigned char tmp;
		tmp = value % 10;
		data1 = tmp;
		tmp = value/10;
		data2= tmp;
	}
}
void process_down()
{
	if (value > 0)
	{
		value--;
		unsigned char tmp;
		tmp = value % 10;
		data1 = tmp;
		tmp = value/10;
		data2= tmp;
	}
}

Вложения
RM03.rar
Atmel Studio
(29.07 КБ) 173 скачивания
RMproteus.rar
протеус
(42.27 КБ) 217 скачиваний
andrei23061996@gmail.com
.................................................................................................................
Реклама
Друг Кота
Аватара пользователя
Сообщения: 3872
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Сообщение Engineer_Keen »

Во-первых у вас CLKDIV8 стоит, так что частота не 8, а 1 МГц, при этом частота обновления индикатора 6 Гц, что само по себе не особо много. Так что либо убирайте фьюз CLKDIV8, либо (что лучше, и не надо будет трогать фьюз в реальном устройстве) настраивайте при старте регистр CLKPR программно.
Во-вторых в свойствах индикатора можно уменьшить minimum trigger time, например в 100 раз.

Ну и по-хорошему, прежде чем переключать разряды все сегменты надо гасить, иначе будет засветка лишних сегментов.
Неправильно собранная из неисправных деталей схема нуждается в отладке и сразу не работает... (С)
Реклама
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 303
Зарегистрирован: Ср май 03, 2017 03:22:26

Сообщение 7seg »

[uquote="Engineer_Keen",url="/forum/viewtopic.php?p=3096260#p3096260"]Во-первых у вас CLKDIV8 стоит, так что частота не 8, а 1 МГц, при этом частота обновления индикатора 6 Гц, что само по себе не особо много. Так что либо убирайте фьюз CLKDIV8, либо (что лучше, и не надо будет трогать фьюз в реальном устройстве) настраивайте при старте регистр CLKPR программно.
Во-вторых в свойствах индикатора можно уменьшить minimum trigger time, например в 100 раз.

Ну и по-хорошему, прежде чем переключать разряды все сегменты надо гасить, иначе будет засветка лишних сегментов.[/uquote]


CLKDIV8 изменил в протеусе, правдо он стал на цпу жаловаться но это не критично. А вот можно приимер кода как внести поправку по поводу гашения сегментов.
andrei23061996@gmail.com
.................................................................................................................
Друг Кота
Аватара пользователя
Сообщения: 3872
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Сообщение Engineer_Keen »

в принципе у вас и так сначала гасятся оба разряда, а уже потом включается один из них, я не особо внимательно посмотрел на код поначалу, но можно сделать чтобы выключались сначала и все сегменты, это если засветка все-таки будет заметна.
Спойлер

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

ISR(TIMER0_OVF0_vect)
{
   static unsigned char count = 0;
   TCNT0 += T0_TICKS;
   //гасим оба разряда
   PORTB &= ~((1<<2)|(1<<0));
   PORTA = 0b11111110; //и тут тоже гасим
   //зажигаем следующий разряд
   if (count == 0)
   {
      PORTB |= ~(1<<2); //сначала включаем разряд
      segchar(data2); //потом сегменты
   }
   if (count == 1)
   {
      PORTB |= ~(1<<0);
      segchar(data1);
   }
   count++;
   if (count == 2) count = 0;
}
Неправильно собранная из неисправных деталей схема нуждается в отладке и сразу не работает... (С)
Реклама
Эиком - электронные компоненты и радиодетали
Модератор
Аватара пользователя
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

Мы ставим прямые транзисторы эмиттером на плюс и пытаемся их открыть единичками ? :facepalm:
RM03.rar
(71.17 КБ) 179 скачиваний
Реклама
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 303
Зарегистрирован: Ср май 03, 2017 03:22:26

Сообщение 7seg »

Пришлось сменить мк на 461. это мой первый опыт с мк. я понимаю что у меня должно быть на выходах инверсный сигнал , сейчас пытаюсь разобраться как это сделать.




Можете помочь разобраться с инициализацией таймера Т0, под эту тиню. еще нашел одну свою прошлую ошибку. Писал прогу под тюню 26 , а протеус был на 261. после изучения датиша понял что они уж слишком разные. сейчас переписываю под 461.
// дефыйны и инкулюды

#define F_CPU 8000000 //Hz
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#define T0_TICK_RATE 100 // Hz
#define T0_CLK ((F_CPU)/1024)
#define T0_TICKS (0x100 - T0_CLK / T0_TICK_RATE)

//инициализация таймера Т0
TIMSK = (1<<TOIE0);
TCCR0B = (1<<CS02)|(0<<CS01)|(0<<CS00); // правка на 461
TCNT0L = T0_TICKS; //правка на 461

Если честно то роль дефайнов не очень понимаю.
Как я понял это формула для таймера Т0 но как она работает не разобрался. Она была найдена мной на просторах интернета.



//прерывания таймера Т0 - вывод на индикатор
ISR(TIMER0_OVF_vect) //правка на 461
{
static unsigned char count = 0;
TCNT0L += T0_TICKS; //правка на 461
//гасим оба разряда
PORTB |=(1<<PB0);
PORTB |=(1<<PB2);
PORTA = 0b11111110;
//зажигаем следующий разряд
if (count == 0)
{
segchar(data2);
PORTB &= ~(1<<2);
}
if (count == 1)
{
segchar(data1);
PORTB &= ~(1<<0);
}
count++;
if (count == 2) count = 0;
}

Пока вроде все работает в протеусе. но что то мне подсказывает где то косяк тут есть.


Пока весь мой код.
Спойлер

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

#define F_CPU   8000000          //Hz

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

#define T0_TICK_RATE    100     // Hz
#define T0_CLK  ((F_CPU)/1024)
#define T0_TICKS  (0x100 - T0_CLK / T0_TICK_RATE)

#define DEBOUNCE_TIME 			20

#define BUTTON_PIN 				PINB
#define POWER_BIT				PB3
#define UP_BIT					PB4
#define DOWN_BIT				PB5

#define KEY_POWER			0b00001000
#define KEY_DOWN			0b00100000
#define KEY_UP				0b00010000

#define  En_INT0      GIMSK|=(1<<6);      // включаем прерывание INT0
#define  Dis_INT0     GIMSK&=~(1<<6);     // выключаем прерывание INT0

volatile unsigned char data1;
volatile unsigned char data2;
volatile unsigned char value;
volatile int _buzzer = 0;
volatile int _pressed = 0;

void init_io();
void segchar(unsigned char seg);
void handle_button(int key);
void handle_buttons();
void process_power();
void process_up();
void process_down();
/*
//настройка внешнего прерывния INT0
void int0_init( void )
{
	//настраиваем на срабатывание INT0 по переднему фронту
	MCUCR |= (1<<ISC01)|(0<<ISC00);
	//разрешаем внешнее прерывание INT0
	En_INT0
}
*/
/*
ISR(INT0_vect)
{ 
	int i=0;
	int tempMS=value/100;
	for (;;)
	{
	i++;
	_delay_us(5);
	if (tempMS<=i){break;}
	}
	PORTB|=(1<<PB1);
	_delay_us(1);
	PORTB &=(0<<PB1);
	_delay_us(1);
	PORTB|=(1<<PB1);
	_delay_us(1);
	PORTB &=(0<<PB1);
	_delay_us(1);
	PORTB|=(1<<PB1);
	_delay_us(1);
	PORTB &=(0<<PB1);
	_delay_us(1);
}
*/
int main(void)
{
	//int0_init();
	value=0;
	init_io();
	sei();
	while(1)
	{
		handle_buttons();
	}
	return 0;
}


void segchar (unsigned char seg)
{
	switch (seg)
	{
		case 1: PORTA = 0b01111100; break;
		case 2: PORTA = 0b10000100; break;
		case 3: PORTA = 0b01000100; break;
		case 4: PORTA = 0b01101000; break;
		case 5: PORTA = 0b01000010; break;
		case 6: PORTA = 0b00000010; break;
		case 7: PORTA = 0b01110100; break;
		case 8: PORTA = 0b00000000; break;
		case 9: PORTA = 0b01000000; break;
		case 0: PORTA = 0b00010000; break;
	}
}

void init_io()
{
	//порт, к которому подкл. сегменты
	PORTA = 0xff;
	DDRA = 0xff;
	//порт, к которому подкл. катод
	DDRB |=(1<<0)|(1<<1)|(1<<2);
	PORTB =0x00;
	//инициализация таймера Т0
	TIMSK = (1<<TOIE0);
	TCCR0B = (1<<CS02)|(0<<CS01)|(0<<CS00);  // правка на 461
	TCNT0L =  T0_TICKS;  //правка на  461
	//иницилизация прерываний
	
}

//прерывания таймера Т0 - вывод на индикатор
ISR(TIMER0_OVF_vect)  //правка на 461 
{
	static unsigned char count = 0;
	TCNT0L += T0_TICKS; //правка на 461 
	//гасим оба разряда
	PORTB |=(1<<PB0);
	PORTB |=(1<<PB2);
	PORTA = 0b11111110;	
	//зажигаем следующий разряд
	if (count == 0)
	{
		segchar(data2);
		PORTB &= ~(1<<2);
	}
	if (count == 1)
	{
		segchar(data1);
		PORTB &= ~(1<<0);
	}
	count++;
	if (count == 2) count = 0;
}

void handle_button(int key)
{
	int bit;
	switch (key)
	{
		case KEY_POWER: bit = POWER_BIT; break;
		case KEY_UP: 	bit = UP_BIT; break;
		case KEY_DOWN: 	bit = DOWN_BIT; break;
		default: return;
	}

	if (bit_is_clear(BUTTON_PIN, bit))
	{
		if (_pressed == 0)
		{
			_delay_ms(DEBOUNCE_TIME);
			if (bit_is_clear(BUTTON_PIN, bit))
			{
				_pressed |= key;
				
				// key action
				switch (key)
				{
					case KEY_POWER: process_power(); break;
					case KEY_UP: 	process_up(); break;
					case KEY_DOWN: 	process_down(); break;
				}
			}
		}
	}
	else
	{
		_pressed &= ~key;
	}
}

void handle_buttons()
{
	handle_button(KEY_POWER);
	handle_button(KEY_DOWN);
	handle_button(KEY_UP);
}

void process_power()
{
	
}
void process_up()
{
	if (value < 99)
	{
		value++;
		unsigned char tmp;
		tmp = value % 10;
		data1 = tmp;
		tmp = value/10;
		data2= tmp;
	}
}
void process_down()
{
	if (value > 0)
	{
		value--;
		unsigned char tmp;
		tmp = value % 10;
		data1 = tmp;
		tmp = value/10;
		data2= tmp;
	}
}

Добавлено after 3 minutes 58 seconds:
по внешнему прерыванию пока что разбираюсь.
andrei23061996@gmail.com
.................................................................................................................
Реклама
Модератор
Аватара пользователя
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

7seg писал(а):я понимаю что у меня должно быть на выходах инверсный сигнал
Т.е. Вы заведомо знали, что неправильно управляете ключами и, вместо вопроса "как проинвертировать выхода", задаёте вопрос "почему не работает" ? :facepalm:
У Вас проблемы с азами электроники, а Вы смешали всё в кучу, вместе с кашей из кода и выкладываете нам её сюда.
Прежде, чем писать код под железо, нужно знать как оно работает.
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 303
Зарегистрирован: Ср май 03, 2017 03:22:26

Сообщение 7seg »

Я просто долго разбирался с битовыми операциями. Сейчас более мение понял вроде.

ISR(TIMER0_OVF_vect) //правка на 461
{
static unsigned char count = 0;
TCNT0L += T0_TICKS; //правка на 461
//гасим оба разряда
PORTB |=(1<<PB0);
PORTB |=(1<<PB2);
PORTA = 0b11111110;
//зажигаем следующий разряд
if (count == 0)
{
segchar(data2);

PORTB &= ~(1<<2);
}
if (count == 1)
{
segchar(data1);
PORTB &= ~(1<<0);
}
count++;
if (count == 2) count = 0;
}

PORTB &= ~(1<<2); передаем 2 биту порта б 1 потом ее инвертируем , и логическим умножением передаем 2 биту порта б ноль.
Правильно я код интерпретировал или нет ?
andrei23061996@gmail.com
.................................................................................................................
Ответить

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