Использование внешних прерываний + Таймера Т0.

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

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

Здравствуйте форумчане, может кто подсказать как организовать использования двух типов прерываний на одном МК.

Используются внешние прерывания для определения перехода фазы через ноль.

За его обработку у меня отвечает INT0
Спойлер

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

//настройка внешнего прерывния INT0
void int0_init( void )
{
	//настраиваем на срабатывание INT0 по переднему фронту
	MCUCR |= (1<<ISC01)|(0<<ISC00);
	//разрешаем внешнее прерывание INT0
	En_INT0
}

ISR(INT0_vect)
{ 
	int i=100;
	int tempMS=(value+1);
	for (;;)
	{
		i--;
		_delay_us(10);
		if (i<=tempMS)
		{
			break;
		}
	}
	int k;
	for(k=0; k<5; k++)
	{
	PORTB |= (1<<1);
	_delay_us(2);
	PORTB &= ~(1<<1);
	_delay_us(2);
	}
}
Внутрение прерывания которые отвечают за индикацию используют Таймер Т0.
Спойлер

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

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)|(1<<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;
}
Но при испытаниях в протеусе , при внешних прерываниях в 100гц. Складывается такое ощущения что обработка кнопок сильно зависает от прерываний по INT0.

Можно ли сделать на МК ATTINY461 организовать подобие много поточности. Чтобы 2 типа прерываний оказывали друг на друга минимальное влияние ?..

Весь код:
Спойлер

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

#define F_CPU   8000000          //Hz

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

#define T0_TICK_RATE    200     // 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);
#define  Dis_INT0     GIMSK&=~(1<<6);     // выключаем прерывание INT0

volatile unsigned char data1=0;
volatile unsigned char data2=0;
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=100;
	int tempMS=(value+1);
	for (;;)
	{
		i--;
		_delay_us(10);
		if (i<=tempMS)
		{
			break;
		}
	}
	int k;
	for(k=0; k<5; k++)
	{
	PORTB |= (1<<1);
	_delay_us(2);
	PORTB &= ~(1<<1);
	_delay_us(2);
	}
}

int main(void)
{
	value=0;
	init_io();
	sei();
	int0_init();
	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)|(1<<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;
	}
}

Вложения
Для Ф.rar
Proteus + AtmelStudio
(58.71 КБ) 245 скачиваний
Последний раз редактировалось 7seg Пт май 05, 2017 09:27:38, всего редактировалось 1 раз.
andrei23061996@gmail.com
.................................................................................................................
Реклама
Родился
Сообщения: 18
Зарегистрирован: Чт ноя 24, 2016 20:16:46

Сообщение krash_artem »

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

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

Это просто моя наработка для регулирования яркостью лампы через симистор путем путем детектирования нуля при переходе фазы через нейтраль. а дальше отсчет времени на включение симистра по процентам. Конечно дальше хотел заменить делай на таймеры и записывать значение в переменные т1 и т2 - это 2 перехода Через ноль.
А включение высчитывать по формуле (т2-n1)/100 - это и есть 1% мощности.

Походу надо в целом пересмотреть подход. Хотя еще думаю о вложенных прерываниях но это кажется как то не очень разумно.
andrei23061996@gmail.com
.................................................................................................................
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18783
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Во-первых, у вас в прерываниях сплошь и рядом обращения к функциям, причем даже к библиотечным. Это не кошерная практика. Как минимум, сделайте все функции, к которым идут обращения из прерываний, static, но лучше обойдитесь без них вообще.
Во-вторых, логика у вас сильно хромает. Делать обработку кнопок поочередно?! Впервые такое встречаю.
Ну и по остальному коду то же самое - зачем в синхронизации с 0 у вас какие-то циклы, задержки? Логика фазового управления (для диммера) должна быть такой или очень похожей на такую: в момент перехода через 0 (в обработчике прерывания то есть) запускаем таймер на отсчет нужной фазы. Когда таймер отсчитает фазу, по его прерыванию включаем импульс управления тиристором и перезапускаем таймер на интервал длительности импульса, по истечению интервала импульс отключаем, таймер останавливаем.
Не забывайте о том, что схема может сильно влиять на поведение программы: как у вас цепь синхронизации с сетью сделана?

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

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 303
Зарегистрирован: Ср май 03, 2017 03:22:26

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

AVR, Большое спасибо за советы. Сейчас есть над чем подумать.

Добавлено after 17 minutes 3 seconds:
Схемка
[img]
http://radiokot.ru/forum/download/file.php?id=284457
[/img]
Вложения
123.JPG
схема
(59.47 КБ) 698 скачиваний
andrei23061996@gmail.com
.................................................................................................................
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18783
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

по схеме тоже предлагаю подумать :) я бы на вашем месте отказался от того огорода с транзисторами, что вы сделали для синхронизации с сетью, а просто со вторичной обмотки трансформатора завел бы через резисторы на входы аналогового компаратора МК сигналы, и вместо INT0 использовал бы прерывание от компаратора.

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

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 303
Зарегистрирован: Ср май 03, 2017 03:22:26

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

Насчет предлагаемых вами изменениях конечно подумаю , если честно не рассматривал с данного ракурса. Но пока охота все-таки через прерывания по ИНТ0 все это сделать.
Эхх первый проект и должен быть таким тяжелым, и лишь тогда что то останется в голове.

Пока решил по изучать датишь на 128мегу( единственный что мне попался на русском). А пока буду его читать заодно по анализирую ответы на форуме.
andrei23061996@gmail.com
.................................................................................................................
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 303
Зарегистрирован: Ср май 03, 2017 03:22:26

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

А есть у кого примеры фазо импульсного управления на аттини ? или примеры димеров ?
andrei23061996@gmail.com
.................................................................................................................
Друг Кота
Аватара пользователя
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Сообщение oleg110592 »

можно обойтись и без прерываний INT0 - ждем пока на ноге порта не будет лог. "0" (переход сетевого напряжения через 0), на таймере организуем задержку, в нужное время подаем импульс на УЭ симистора.
Изображение
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18783
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

[uquote="7seg",url="/forum/viewtopic.php?p=3098817#p3098817"]А есть у кого примеры фазо импульсного управления на аттини ? или примеры димеров ?[/uquote]
допустим, у меня есть. на тини13. я даже многократно схему приводил:
Изображение
можете посмотреть, как синхронизация с сетью реализована - 2 резистора всего-навсего. хоть схема и не от устройства-диммера, сделать диммер - будет точно такая же схема.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

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

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

ARV, А можно на листинг программы взглянуть ? если это не тайна конечно ?
andrei23061996@gmail.com
.................................................................................................................
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18783
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

взглянуть можно, но вряд ли вы разберетесь...
Спойлер

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

/*
 * main.c
 *
 *  Created on: 05.09.2010
 *      Author: ARV
 */
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <avr/sleep.h>
#include <util/delay.h>
#include <avr_helper.h>
#include "rc5.h"

/// рабочий порт для выхода на симистор
#define OUTPORT		PORTB
/// выходной пин порта для управления симистором
#if defined(__AVR_ATtiny2313__)
#define	OUT			_BV(PB7)
#else
#define OUT			_BV(PB4)
#endif
/// длительность выходного импульса управления симистором
#define PULSE_LEN	50
/// действие по совпадению канала А
#define do_comp_A()	if(on) OUTPORT &= ~OUT
/// действие по совпадению канала В
#define do_comp_B()	OUTPORT |= OUT

/// предделитель таймера
#define TMR_DIV		8

#define MAX_P		200
#define PHASE_STEP	5
#define MIN_P		PHASE_STEP
#define PHASE_OFF	(MAX_P + PHASE_STEP)

/// частота следования битов по стандарту RC5 (1778 мкс на 1 бит)
#define F_RC	562UL
/// полное значение делителя таймера 1
#define T1_DIV	(TMR_DIV * CTC)
/// Длительность интервала передачи 1 бита
#define	T1	((F_CPU / T1_DIV / F_RC) + 5)
/// Длительность 1 бита при "соседних" битах 01 или 10
#define	T2	(T1*3UL/2UL)
/// Максимальный интервал протокола
#define	T3	(2UL*T1)
/// Установка сброса для режима СТС
#define CTC			(F_CPU/TMR_DIV/MAX_P/100)

volatile uint8_t 	COUNTER;// = 0;
volatile uint8_t	COMP_A;
volatile uint8_t	COMP_B;
volatile uint16_t	COMP_C;
volatile uint8_t 	timeout;
volatile uint8_t	out_phase = PHASE_OFF;
volatile uint8_t	sel_phase;// = PHASE_OFF;
//volatile uint8_t	ocr_c_enable	= 0;
volatile uint8_t	on = 0;

/// локальная переменная, в которой хранится принятый код
volatile uint16_t rc_code;
/// переменная, накапливающая принимаемые биты
volatile uint16_t code;
/// счетчик принятых бит
volatile uint8_t  count;

EEMEM rc5_t cmd[4] = {
	make_rc5_code(RC5ADDR_PHONO,RC5CMD_STOP),
	make_rc5_code(RC5ADDR_PHONO,RC5CMD_PLAY),
	make_rc5_code(RC5ADDR_PHONO,RC5CMD_VOLPLUS),
	make_rc5_code(RC5ADDR_PHONO,RC5CMD_VOLMINUS)
};

#ifndef TIM0_COMPA_vect
#define TIM0_COMPA_vect TIMER0_COMPA_vect
#endif

/** Прерывание по переполнению таймера.
 * Таймер без делителя, прерывание возникает каждые 256 тактов.
 * Обработчик прерыания реализует виртуальный 16-битный таймер с регистрами сравнения и т.п.
 */
ISR(TIM0_COMPA_vect){
	COUNTER++;							// ведем программный таймер
	if(COUNTER == COMP_A){
		do_comp_A();
	}
	if(COUNTER == COMP_B){
		do_comp_B();
	}
	if(COMP_C){
		if(!--COMP_C){
			// проанализируем число принятых бит
			switch(count){
			case RC5_CODELEN-1:
					// если принято на 1 бит меньше, чем нужно - дополняем нулем
					code <<= 1;
			case RC5_CODELEN:
					// если принято нормальное число бит - обновляем код
					rc_code = ignore_toggle(code);
			default:
					// что бы ни было принято - всегда обнуляется счетчик бит
					// который является признаком готовности к новому приему
					count = 0;
			}
		}
	}
}

#ifndef PCINT0_vect
#define PCINT0_vect PCINT_vect
#endif

/** Прерывание по изменению состояния синхро-пина.
 * Возникает по фронту и спаду синхроимпульса.
 * Реализует синхронизацию с сетью.
 */
ISR(PCINT0_vect){
	uint8_t tmp = COUNTER;				// запоминаем счетчик

	OUTPORT	|= OUT;					// выключаем на всякий случай выход
	COMP_A 	= tmp + out_phase;			// задаем момент включения выходного сигнала
	COMP_B	= tmp + out_phase + PULSE_LEN;
	if(on){
		if(sel_phase > out_phase){
			out_phase += 1;//PHASE_STEP;
		} else if(sel_phase < out_phase){
			out_phase -= 1;//PHASE_STEP;
		}
	}
	if(timeout) timeout--;
}



#ifndef TIMSK0
#define TIMSK0 TIMSK
#endif

#define SND _BV(PB3)
static void beep(void){
	for(uint8_t i=255; i; i--){
		PORTB ^= SND;
		_delay_us(150);
	}
}

static uint16_t get_ir(void){
	uint16_t code = 0;
	
	while(PINB & _BV(PB0)) wdt_reset();
	_delay_us(BIT_TIME / 4.0);
	for(uint8_t i=0; i < RC5_CODELEN; i++){
		wdt_reset();
		code <<= 1;
		if(!(PINB & _BV(PB0))) code |= 1;
		_delay_us(BIT_TIME);
	}
	return code;
}
MAIN(){
	uint8_t	off_phase = MIN_P;
	uint16_t code, oldcode;

	// настройка периферии
	wdt_enable(WDTO_1S);				// сторожа разрешим для страховки
	ACSR	= _BV(ACD);					// компаратор отключается для экономии энергии
	DDRB	= OUT | SND;						// выходной пин
	PORTB	= OUT;
	MCUCR	= _BV(ISC01);				// запрос прерывания по падающему фронту
	TCCR0A	= _BV(WGM01);				// режим СТС
	OCR0A	= CTC;						// порог сброса
	TCCR0B 	= TIMER_CLK_DIV(TMR_DIV);	// делитель таймера

	TIMSK0 	= _BV(OCIE0A);				// прерывания по сбросу таймера
	PCMSK	= _BV(PCINT0);				// 0-й пин используется для синхронизации с сетью
	GIMSK	= _BV(INT0) | _BV(PCIE);	// разрешаем внешний запрос и прерывание по смене уровня пина

	// временно
#if defined(__AVR_ATtiny2313__)
	DDRD = _BV(PD5);
	PORTD = _BV(PD5) | _BV(PD2);
#endif
	sei();
	while(1){

		while(!(code = get_ir())){
			wdt_reset();
			_delay_ms(10);
		}

		if(oldcode != code){
			oldcode = code;
		} else if(timeout) continue;

		// обработка принятого кода
		if(code == eeprom_read_word((void*)&cmd[0])){
			timeout = 200;
			beep();
			if(on){
				off_phase = sel_phase;
			m1:
				sel_phase = PHASE_OFF;
				out_phase = PHASE_OFF;
				on = 0;
			} else {
			m2:
				sel_phase = off_phase;
				on = 1;
			}
		} if(code == eeprom_read_word((void*)&cmd[2])){
			if(!on) goto m2;
			timeout = 5;
			// изменение
			if(sel_phase > PHASE_STEP){
				sel_phase -= PHASE_STEP;
				beep();
			}
		} else if(code == eeprom_read_word((void*)&cmd[3])){
			timeout = 5;
			// изменение
			if(sel_phase < PHASE_OFF){
				beep();
				sel_phase += PHASE_STEP;
			} else {
				off_phase = PHASE_STEP;
				goto m1;
			}
		}
	}
}
только показанный код немного от другого проекта - от проекта диммера с RC5-дистанционным управлением, т.е. схема, что ранее показал, несколько отличается. К сожалению, саму схему я утерял, но принцип синхронизации точно такой же, как и на схеме, и как я текстом описывал.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Сообщение oleg110592 »

[uquote="7seg",url="/forum/viewtopic.php?p=3099565#p3099565"]А можно на листинг программы взглянуть ?[/uquote]
можно листинг на Си и немного теории подсмотреть в документе от Микрочип "PICDIM Lamp Dimmer for the PIC12C508" 1997 года, хоть и для пика, но Си он и в Африке Си. Там диаграмки и схема есть. Прерываний нет.
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 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    1000     // 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);
#define  Dis_INT0     GIMSK&=~(1<<6);     // выключаем прерывание INT0




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

volatile unsigned char sw=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)
{
	sw=1;
	static unsigned char count = 0;
	//гасим оба разр¤да
	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;

}

int main(void)
{
	value=0;
	init_io();
	sei();
	int0_init();
	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=(0<<CS01)|(1<<CS00);   // правка на 461
	TCNT0H=0x00;
	TCNT0L=0xff;  //правка на  461
	//иницилизаци¤ прерываний
	
}

volatile unsigned char lvl=0;
//прерывани¤ таймера “0 - вывод на индикатор
ISR(TIMER0_OVF_vect)  //правка на 461
{
	//cli();
	TCNT0L=0xff; //правка на 461
	if (sw==1)
	{
		lvl++;
		if (lvl==(value))
		{
			for(int k=0; k<5; k++)
			{
				PORTB |= (1<<1);
				_delay_us(10);
				PORTB &= ~(1<<1);
				_delay_us(1);
			}
		}
		
	}
}

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;
	}
}

andrei23061996@gmail.com
.................................................................................................................
Ответить

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