Вы еще не программируете микроконтроллеры? Тогда мы идем к вам!

Здравствуйте, уважаемые Хабражители!

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

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

1. Программатор

На рынке предлагается много вариантов — от самых дешевых ISP (In-System Programming) программаторов за несколько долларов, до мощных программаторов-отладчиков за пару сотен. Не имея большого опыта в этом деле, для начала я решил попробовать один из самых простых и дешевых — USBasp. Купил в свое время на eBay за $12, сейчас можно найти даже за $3-4. На самом деле это китайская версия программатора от Thomas Fischl. Что могу сказать про него? Только одно — он работает. К тому же поддерживает достаточно много AVR контроллеров серий ATmega и ATtiny. Под Linux не требует драйвера.



Для прошивки надо соединить выходы программатора VCC, GND, RESET, SCK, MOSI, MISO с соответствующими выходами микроконтроллера. Для простоты я собрал вспомогательную схему прямо на макетной плате:

image


Слева на плате — тот самый микроконтроллер, который мы собираемся прошивать.

2. Микроконтроллер

С выбором микроконтроллера я особо не заморачивался и взял ATmega8 от Atmel — 23 пина ввода/вывода, два 8-битных таймера, один 16-битный, частота — до 16 Мгц, маленькое потребление (1-3.6 мА), дешевый ($2). В общем, для начала — более чем достаточно.

image


Под Linux для компиляции и загрузки прошивки на контроллер отлично работает связка avr-gcc + avrdude. Установка тривиальная. Следуя инструкции, можно за несколько минут установить все необходимое ПО. Единственный ньюанс, на который следует обратить внимание — avrdude (ПО для записи на контроллер) может потребовать права супер-пользователя для доступа к программатору. Выход — запустить через sudo (не очень хорошая идея), либо прописать специальные udev права. Синтаксис может отличаться в разных версиях ОС, но в моем случае (Linux Mint 15) сработало добавление следующего правила в файл /etc/udev/rules.d/41-atmega.rules:

# USBasp programmer
SUBSYSTEM=="usb", ATTR{idVendor}=="16c0", ATTR{idProduct}=="05dc", GROUP="plugdev", MODE="0666"


После этого, естественно, необходим перезапуск сервиса
service udev restart

Компилировать и прошивать без проблем можно прямо из командной строки (кто бы сомневался), но если проектов много, то удобнее поставить плагин AVR Eclipse и делать все прямо из среды Eclipse.

Под Windows придется поставить драйвер. В остальном проблем нет. Ради научного интереса попробовал связку AVR Studio + eXtreme Burner в Windows. Опять-таки, все работает на ура.

Начинаем программировать


Программировать AVR контроллеры можно как на ассемблере (AVR assembler), так и на Си. Тут, думаю, каждый должен сделать свой выбор сам в зависимости от конкретной задачи и своих предпочтений. Лично я в первую очередь начал ковырять ассемблер. При программировании на ассемблере архитектура устройства становится понятнее и появляется ощущение, что копаешься непосредственно во внутренностях контроллера. К тому же полагаю, что в особенно критических по размеру и производительности программах знание ассемблера может очень пригодиться. После ознакомления с AVR ассемблером я переполз на Си.

После знакомства с архитектурой и основными принципами, решил собрать что-то полезное и интересное. Тут мне помогла дочурка, она занимается шахматами и в один прекрасный вечер заявила, что хочет иметь часы-таймер для партий на время. БАЦ! Вот она — идея первого проекта! Можно было конечно заказать их на том же eBay, но захотелось сделать свои собственные часы, с блэк… эээ… с индикаторами и кнопочками. Сказано — сделано!

В качестве дисплея решено было использовать два 7-сегментных диодных индикатора. Для управления достаточно было 5 кнопок — “Игрок 1”, “Игрок 2”, “Сброс”, “Настройка” и “Пауза”. Ну и не забываем про звуковую индикацию окончания игры. Вроде все. На рисунке ниже представлена общая схема подключения микроконтроллера к индикаторам и кнопкам. Она понадобится нам при разборе исходного кода программы:



Разбор полета


Начнем, как и положено, с точки входа программы — функции main. На самом деле ничего примечательного в ней нет — настройка портов, инициализация данных и бесконечный цикл обработки нажатий кнопок. Ну и вызов sei() — разрешение обработки прерываний, о них немного позже.

int main(void)
{
	init_io();
	init_data();
	sound_off();
	sei();

	while(1)
	{
		handle_buttons();
	}
	return 0;
}

Рассмотрим каждую функцию в отдельности.

void init_io()
{
	// set output
	DDRB = 0xFF;
	DDRD = 0xFF;

	// set input
	DDRC = 0b11100000;

	// pull-up resistors
	PORTC |= 0b00011111;

	// timer interrupts
	TIMSK = (1<<OCIE1A) | (1<<TOIE0);

	TCCR0 |= (1 << CS01) | (1 << CS00);

	TCCR1B = (1<<CS12|1<<WGM12);

	//OCRn =  (clock_speed / prescaler) * seconds - 1
	OCR1A = (F_CPU / 256) * 1 -1;
}


Настройка портов ввода/вывода происходит очень просто — в регистр DDRx (где x — буква, обозначающая порт) записивается число, каждый бит которого означает, будет ли соответствующий пин устройством ввода (соответствует 0) либо вывода (соответствует 1). Таким образом, заслав в DDRB и DDRD число 0xFF, мы сделали B и D портами вывода. Соответственно, команда DDRC = 0b11100000; превращает первые 5 пинов порта C во входные пины, а оставшиеся — в выходные. Команда PORTC |= 0b00011111; включает внутренние подтягивающие резисторы на 5 входах контроллера. Согласно схеме, к этим входам подключены кнопки, которые при нажатии замкнут их на землю. Таким образом контроллер понимает, что кнопка нажата.

Далее следует настройка двух таймеров, Timer0 и Timer1. Первый мы используем для обновления индикаторов, а второй — для обратного отсчета времени, предварительно настроив его на срабатывание каждую секунду. Подробное описание всех констант и метода настройки таймера на определенноый интервал можно найти в документации к ATmega8.

Обработка прерываний

ISR (TIMER0_OVF_vect)
{
	display();

	if (_buzzer > 0)
	{
		_buzzer--;
		if (_buzzer == 0)
			sound_off();
	}
}

ISR(TIMER1_COMPA_vect)
{
	if (ActiveTimer == 1 && Timer1 > 0)
	{
		Timer1--;
		if (Timer1 == 0)
			process_timeoff();
	}

	if (ActiveTimer == 2 && Timer2 > 0)
	{
		Timer2--;
		if (Timer2 == 0)
			process_timeoff();
	}
}


При срабатывании таймера управление передается соответствующему обработчику прерывания. В нашем случае это обработчик TIMER0_OVF_vect, который вызывает процедуру вывода времени на индикаторы, и TIMER1_COMPA_vect, который обрабатывает обратный отсчет.

Вывод на индикаторы

void display()
{
	display_number((Timer1/60)/10, 0b00001000);
	_delay_ms(0.25);

	display_number((Timer1/60)%10, 0b00000100);
	_delay_ms(0.25);

	display_number((Timer1%60)/10, 0b00000010);
	_delay_ms(0.25);

	display_number((Timer1%60)%10, 0b00000001);
	_delay_ms(0.25);

	display_number((Timer2/60)/10, 0b10000000);
	_delay_ms(0.25);

	display_number((Timer2/60)%10, 0b01000000);
	_delay_ms(0.25);

	display_number((Timer2%60)/10, 0b00100000);
	_delay_ms(0.25);

	display_number((Timer2%60)%10, 0b00010000);
	_delay_ms(0.25);

	PORTD = 0;
}

void display_number(int number, int mask)
{
	PORTB = number_mask(number);
	PORTD = mask;
}


Функция display использует метод динамической индикации. Дело в том, что каждый отдельно взятый индикатор имеет 9 контактов (7 для управления сегментами, 1 для точки и 1 для питания). Для управления 4 цифрами понадобилось бы 36 контактов. Слишком расточительно. Поэтому вывод разрядов на индикатор с несколькими цифрами организован по следующему принципу:



Напряжение поочередно подается на каждый из общих контактов, что позволяет высветить на соответствующем индикаторе нужную цифру при помощи одних и тех же 8 управляющих контактов. При достаточно высокой частоте вывода это выглядит для глаза как статическая картинка. Именно поэтому все 8 питающих контактов обоих индикаторов на схеме подключены к 8 выходам порта D, а 16 управляющих сегментами контактов соединены попарно и подключены к 8 выходам порта B. Таким образом, функция display с задержкой в 0.25 мс попеременно выводит нужную цифру на каждый из индикаторов. Под конец отключаются все выходы, подающие напряжение на индикаторы (команда PORTD = 0;). Если этого не сделать, то последняя выводимая цифра будет продолжать гореть до следующего вызова функции display, что приведет к ее более яркому свечению по сравнению с остальными.

Обработка нажатий

void handle_buttons()
{
	handle_button(KEY_SETUP);
	handle_button(KEY_RESET);
	handle_button(KEY_PAUSE);
	handle_button(KEY_PLAYER1);
	handle_button(KEY_PLAYER2);
}

void handle_button(int key)
{
	int bit;
	switch (key)
	{
		case KEY_SETUP: 	bit = SETUP_BIT; break;
		case KEY_RESET: 	bit = RESET_BIT; break;
		case KEY_PAUSE: 	bit = PAUSE_BIT; break;
		case KEY_PLAYER1: 	bit = PLAYER1_BIT; break;
		case KEY_PLAYER2: 	bit = PLAYER2_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_SETUP: 	process_setup(); break;
					case KEY_RESET: 	process_reset(); break;
					case KEY_PAUSE: 	process_pause(); break;
					case KEY_PLAYER1: 	process_player1(); break;
					case KEY_PLAYER2: 	process_player2(); break;
				}

				sound_on(15);
			}
		}
	}
	else
	{
		_pressed &= ~key;
	}
}


Эта функция по очереди опрашивает все 5 кнопок и обрабатывает нажатие, если таковое случилось. Нажатие регистрируется проверкой bit_is_clear(BUTTON_PIN, bit), т.е. кнопка нажата в том случае, если соответствующий ей вход соединен с землей, что и произойдет, согласно схеме, при нажатии кнопки. Задержка длительностью DEBOUNCE_TIME и повторная проверка нужна во избежание множественных лишних срабатываний из-за дребезга контактов. Сохранение статуса нажатия в соответствующих битах переменной _pressed используется для исключения повторного срабатывания при длительном нажатии на кнопку.
Функции обработки нажатий достаточно тривиальны и полагаю, что в дополнительных комментариях не нуждаются.

Полный текст программы
#define F_CPU 						4000000UL

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


#define DEBOUNCE_TIME 					20

#define BUTTON_PIN 					PINC
#define SETUP_BIT 					PC0
#define RESET_BIT 					PC1
#define PAUSE_BIT 					PC2
#define PLAYER1_BIT 					PC3
#define PLAYER2_BIT 					PC4

#define KEY_SETUP					0b00000001
#define KEY_RESET					0b00000010
#define KEY_PAUSE					0b00000100
#define KEY_PLAYER1					0b00001000
#define KEY_PLAYER2					0b00010000


volatile int ActiveTimer = 0;
volatile int Timer1 = 0;
volatile int Timer2 = 0;

volatile int _buzzer = 0;
volatile int _pressed = 0;


// function declarations

void init_io();
void init_data();
int number_mask(int num);
void handle_buttons();
void handle_button(int key);
void process_setup();
void process_reset();
void process_pause();
void process_timeoff();
void process_player1();
void process_player2();
void display();
void display_number(int mask, int number);
void sound_on(int interval);
void sound_off();

// interrupts

ISR (TIMER0_OVF_vect)
{
	display();

	if (_buzzer > 0)
	{
		_buzzer--;
		if (_buzzer == 0)
			sound_off();
	}
}

ISR(TIMER1_COMPA_vect)
{
	if (ActiveTimer == 1 && Timer1 > 0)
	{
		Timer1--;
		if (Timer1 == 0)
			process_timeoff();
	}

	if (ActiveTimer == 2 && Timer2 > 0)
	{
		Timer2--;
		if (Timer2 == 0)
			process_timeoff();
	}
}


int main(void)
{
	init_io();
	init_data();

	sound_off();

	sei();

	while(1)
	{
		handle_buttons();
	}
	return 0;
}

void init_io()
{
	// set output
	DDRB = 0xFF;
	DDRD = 0xFF;

	// set input
	DDRC = 0b11100000;

	// pull-up resistors
	PORTC |= 0b00011111;

	// timer interrupts
	TIMSK = (1<<OCIE1A) | (1<<TOIE0);

	TCCR0 |= (1 << CS01) | (1 << CS00);

	TCCR1B = (1<<CS12|1<<WGM12);

	//OCRn =  (clock_speed / prescaler) * seconds - 1
	OCR1A = (F_CPU / 256) * 1 -1;
}

void init_data()
{
	Timer1 = 0;
	Timer2 = 0;
	ActiveTimer = 0;
}

int number_mask(int num)
{
	switch (num)
	{
		case 0 : return 0xC0;
		case 1 : return 0xF9;
		case 2 : return 0xA4;
		case 3 : return 0xB0;
		case 4 : return 0x99;
		case 5 : return 0x92;
		case 6 : return 0x82;
		case 7 : return 0xF8;
		case 8 : return 0x80;
		case 9 : return 0x90;
	};

	return 0;
}

void process_setup()
{
	Timer1 += 60;
	Timer2 += 60;

	// overflow check (5940 seconds == 99 minutes)
	if (Timer1 > 5940 || Timer2 > 5940)
	{
		Timer1 = 0;
		Timer2 = 0;
	}
}

void process_reset()
{
	init_data();
}

void process_timeoff()
{
	init_data();

	sound_on(30);
}

void process_pause()
{
	ActiveTimer = 0;
}

void process_player1()
{
	ActiveTimer = 2;
}

void process_player2()
{
	ActiveTimer = 1;
}

void handle_button(int key)
{
	int bit;
	switch (key)
	{
		case KEY_SETUP: 	bit = SETUP_BIT; break;
		case KEY_RESET: 	bit = RESET_BIT; break;
		case KEY_PAUSE: 	bit = PAUSE_BIT; break;
		case KEY_PLAYER1: 	bit = PLAYER1_BIT; break;
		case KEY_PLAYER2: 	bit = PLAYER2_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_SETUP: 	process_setup(); break;
					case KEY_RESET: 	process_reset(); break;
					case KEY_PAUSE: 	process_pause(); break;
					case KEY_PLAYER1: 	process_player1(); break;
					case KEY_PLAYER2: 	process_player2(); break;
				}

				sound_on(15);
			}
		}
	}
	else
	{
		_pressed &= ~key;
	}
}

void handle_buttons()
{
	handle_button(KEY_SETUP);
	handle_button(KEY_RESET);
	handle_button(KEY_PAUSE);
	handle_button(KEY_PLAYER1);
	handle_button(KEY_PLAYER2);
}

void display()
{
	display_number((Timer1/60)/10, 0b00001000);
	_delay_ms(0.25);

	display_number((Timer1/60)%10, 0b00000100);
	_delay_ms(0.25);

	display_number((Timer1%60)/10, 0b00000010);
	_delay_ms(0.25);

	display_number((Timer1%60)%10, 0b00000001);
	_delay_ms(0.25);

	display_number((Timer2/60)/10, 0b10000000);
	_delay_ms(0.25);

	display_number((Timer2/60)%10, 0b01000000);
	_delay_ms(0.25);

	display_number((Timer2%60)/10, 0b00100000);
	_delay_ms(0.25);

	display_number((Timer2%60)%10, 0b00010000);
	_delay_ms(0.25);

	PORTD = 0;
}

void display_number(int number, int mask)
{
	PORTB = number_mask(number);
	PORTD = mask;
}

void sound_on(int interval)
{
	_buzzer = interval;

	// put buzzer pin high
	PORTC |= 0b00100000;
}

void sound_off()
{
	// put buzzer pin low
	PORTC &= ~0b00100000;
}



Прототип был собран на макетной плате:



После тестирования прототипа пришло время все это добро разместить в корпусе, обеспечить питание и т.д.



Ниже показан окончательный вид устройства. Часы питаются от 9-вольтовой батарейки типа “Крона”. Потребление тока — 55 мА.



Заключение


Потратив $20-25 на оборудование и пару вечеров на начальное ознакомление с архитектурой микроконтроллера и основными принципами работы, можно начать делать интересные DIY проекты. Статья посвящается тем, кто, как и я в свое время, думает, что начать программировать микроконтроллеры — это сложно, долго или дорого. Поверьте, начать намного проще, чем может показаться. Если есть интерес и желание — пробуйте, не пожалете!

Удачного всем программирования!

P.S. Ну и напоследок, небольшая видео-демонстрация прототипа:

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 63

    +19
    Вспоминается крутая статья уважаемого barsmonster и слова в конце:
    «Вы все еще покупаете 8-и битные AVR-рки по 200 рублей? Тогда ARM идет к вам!»
    Хотя программаторы, видимо, там будут подороже.
      +1
      Спасибо за ссылку, интересная статья!
        +4
        Подойдет SWD программатор-отладчик в составе любой из discovery плат от stm32. Единственный недостаток: дип-корпусов нет.
          +1
          Во первых это не такой уж недостаток, во вторых, в DIP есть LPC1114 (шаг выводов у него привычный — 2.54мм)
          0
          Программатор там делается из любого устройства на чипе FT2232 (и аналоге), которые стоят дешево, а сделать из них можно просто прорву всего.
          В том числе и программатор\отладчик по JTAG.
          Надо будет статью написать про этот чип, наверное.
            +5
              0
              И этого не надо. Надо купить переходник USB<->UART и не мучаться. У подавляющего большинства ARM'ов есть возможность прошивки (или хотя бы BOOT) через UART.
                0
                Прошивка — это не главное. Отладка намного важнее, да и boundary scan тоже весьма полезная вещь, если пользоваться уметь.
                  +1
                  Вот не соглашусь. Чтобы «попробовать микроконтроллеры», отладка совсем даже не нужна. Она (возможно) нужна для работы, но для ознакомления с предметной областью нужен минимум инструментов и — это самое главное — мозг. При обучении очень важно, чтобы программа заработала сначала на эмуляторе, который встроен в ваш мозг, а уж потом — на реальном железе. А у большинства начинающих (по моей статистике) получается наоборот: сначала они при помощи отладчика методом тыка находят работающий вариант (часто даже не открывая datasheet и progmanual), а уж потом — если есть желание, время или упёртость — пытаются понять почему это работает. Должно быть как раз наоборот.

                  Все написаное есть ИМХО, выстраданное на некотором опыте обучения людей embedded разработке и на собственном опыте. Сам я не пользуюсь отладчиком даже в рабочих проектах, хотя не считаю это обязательным. Просто у меня почему-то всего два состояния: либо я пользуюсь отладчиком и выключаю эмулятор в моей голове, либо не пользуюсь отладчиком. У других получается сопрягать и я им завидую :)
                    0
                    При работе с множеством разных (а часто очень-очень разных) МК одновременно выстроить в голове толковый эмулятор каждого у меня не получается, и без отладки в том случае было бы очень грустно. И уже было, когда мне попался доселе неизвестный Infineon XE167FM на ранее незнакомой архитектуре C166, а отладчика к нему не было. Зато был мануал на 2000 страниц и делайн до послезавтра.
                    Можно отлаживать и в уме, и это хорошее упражнение для начинающих при обучении работе с определенным МК с заранее известными ограничениями, багами и хитростями. Но если у тебя большой проект, сложный сам по себе, плюс на эту сложность накладываются определенные особенности МК (описанные либо на 1255 странице мануала, либо на 25 странице Errata sheet, который как раз обновили позавчера), то лучше, на мой взгляд, использовать все возможности по снижению нагрузки на мозг.
                    Без отладки, мне кажется, микроконтролеры можно попробовать, пару раз наткнуться на неожиданное для новичка поведение, сказать про себя «пошла она к черту, эта магия-шмагия», и больше к ним не возвращаться.
                      0
                      Я всё-таки говорил про обучение, а не про работу. Про работу я специально уточнил: отладчик может понадобиться; по крайней мере в некоторых ситуациях.
                      Насчёт «пару раз наткнуться на неожиданное для новичка поведение» у меня другое мнение: для новичка много что будет неожиданным и это ещё не повод заниматься практикой без теории.
              0
              Эхх, а я в своё время программатор сам собирал, через LPT порт. Все теперь стало так просто, что даже подумываю откопать из шкафов паяльник.
                +3
                а я в армии свой первый LPT программатор спаял



              +1
              А есть какие то набора для новичков? Программатор + плата для прототипирования + один(несколько) контроллеров + индикаторы/датчики
              +1
              > Но тогда достать программатор по месту жительства оказалось проблематично, а о покупке через Интернет и речи не было.
              Но а как же «5 проводков»?
                +1
                … или даже программатор Громова.
                  +2
                  А вот здесь человека, начинающего работать с контроллерами, не остановило отсутствие программатора и документации.
                  0
                  Перепрошив это устройство можно сделать игру — рендомные числа по нажатию кнопки выводятся на индикатор. Выигрывает тот, у кого число больше. Можно решать споры или определять очередность подхода к снаряду во время застолья, можно мини-турниры устраивать.
                    +2
                    Что меня удивило на схеме: всё подключено напрямую, никаких резисторов, конденсаторов и т.д. Это ок?
                      0
                      обычно нет, но у современных МК не так просто выжечь ноги и они максимум 20мА отдают. Плюс там не постоянно сегменты светятся, а только часть периода. Так что жить будет.
                        +10
                        Написал бы кто-нибудь эдакий гайдик по подключению всяких компонентов в цифровых схемах: джентльменский набор, исключающий перегрев, перегрузку и т.д.
                          +6
                          Отличная идея, сам бы с удовольствием почитал
                          +10
                          Навскидку:
                          Конденсаторы по питанию — электролиты(+ иногда керамика)
                          Резисторы на светодиоды + тонкости типа «не ставить один резистор на два светодиода если они будут гореть одновременно»
                          Использование транзисторов, когда нужно управлять чем-то, чей ток превышает максимальный ток пина МК (добавить про ULN2003)
                          Осторожное использование регулятора 3.3 вольта на Arduino/Raspberry Pi/и так далее (макс. ток)
                          Защита от перенапряжения на 5 вольт
                          Конденсаторы на землю с каждой ноги резонатора (не знаю, правда, зачем)
                          Подтяжка резисторами линий данных к плюсу или минусу (также кнопок, светодиодов и прочего) и неиспользуемых контактов у микросхем
                          Защита от дребезга контактов
                          Объяснение про ёмкость проводов
                          Защита микросхем и прочего от статики
                          Фильтры напряжения
                          Длина проводов, по которым передаются данные, правильное экранирование
                          Диоды на выходе источников питания для защиты
                          Правильное заземление приборов
                          Советы для траблшутинга (даже и особенно те, что сам заучил из-за горького опыта)
                          Советы по пайке чего-нибудь в ограниченных условиях, вещи, необходимые для пайки, поскольку значительно её облегчают
                          Уход за паяльником
                          Использование различных клеёв — Момент/горячий/эпоксидный — в своих поделках
                          Правильная разводка высокочастотных компонентов

                          Тут многие детали, конечно, опциональны, но всё же… Часть из этого хотел бы узнать сам, ну и объяснения некоторых явлений =) Реально, статья была бы отличной, только у самого не хватит ни знаний теоретических, ни опыта — напишу, а мне в комментариях вышлют кучу поправок и посоветуют не лезть, не зная =( Много кому бы вправила мозги. Я джва года жду такую статью, короче.
                            0
                            Можно не сразу всё написать. Сначала база: как подключить правильно микроконтроллер к источнику (батарейка это или USB или что другое), заземление, подтягивающие резисторы, конденсаторы по питанию, что ставить между портами I/O контроллера и нагрузкой (диодами, дисплеями и т.д.). Всё остальное потом.
                              +3
                              Бро! Так иди к DIHALT'у на сайт, там в принципе есть всё, о чём ты спросил, только может быть не в такой последовательности. Вот к примеру по обвесу контроллера — как раз и объясняется зачем кондёры ставить между vcc и землёй, зачем резистор, зачем катушка. Плюс такие тонкости относительно того же АЦП(точнее косяки на уровне чипа) на так всеми любимой атмега8 — там питание АЦП и VCC связаны внутри чипа, поэтому при использование кристалла для аналоговых замеров лучше брать другую модель. В общем и целом — там есть очень много информации, за что DI отдельное спасибо!
                              Вот та самая статья:
                              easyelectronics.ru/podklyuchenie-mikrokontrollera-likbez.html
                              и их там есть ещё!
                              Может даже тебе оттуда инфу взять, переработать и выложить статью здесь в соавторстве — я не думаю что DI будет против.
                                0
                                Конденсаторы на землю с каждой ноги резонатора — эти конденсаторы являются частью генератора и частью колебательной системы представленной резонатором, от подбора этих емкостей зависит устойчивость генератора и добротность резонатора — а значит и точность генерируемой частоты.
                                0
                                Обеими руками поддержу.
                                  0
                                  Эти «гайды» написаны и переписаны уже десяток раз… загляните на сайт РадиоКот например.
                                0
                                Это Proteus, там это не важно. Я имею в виду, что для быстрого прототипирования можно подключать диоды как есть. Точно так же, как и кварцевый резонатор можно не вешать — он все равно не симулируется. Вообще про баги/особеннопсти Proteus можно целую статью сдулать… и не одну
                                  0
                                  Особенно про симуляцию MAC-уровня с выводом на реальный tap-адаптер…
                                +3
                                Не постесняюсь на себя сослаться — может что интересное для себя вновь прибывшие найдут
                                habrahabr.ru/post/128904/
                                  0
                                  Зачем запитывать пятивольтовый контролер от кроны, рассеивая в тепло лишние 4 вольта? Хватило бы трёх-четырёх батареек AA.
                                    0
                                    В такок корпус можно было бы запихнуть адаптер для зарядки телефонов.
                                      0
                                      Хотелось мобильности…
                                        0
                                        Я рассуждал так: при рабочем напряжении 4.5-5.5 В 3 батарейки вроде как маловато (быстро просядут), а 4 уже много и, скорее всего, надо стабилизировать. А у стабилизатора 7805 рабочее напряжение вроде как от 7 до 20 В. В общем, если эти рассуждения неверны, прошу сильно не пинать и поправить, это не совсем мой профиль.
                                          0
                                          Контроллер контроллеру рознь, конечно. Я запитывал Arduino шестью вольтами (четыре банки по 1,5В) — работал и не дымился. Вот от трёх не пробовал, поэтому не знаю, на каком напряжении вырубится.

                                          Банки можно взять маленькие: половинка ААА или таблетка.
                                            0
                                            Мега 8 может и от 2.7В работать. Вообще минимальное напряжение зависит от рабочей тактовой частоты(см. график зависимости в даташите). В основном напряжение питания определяется минимальным при котором можно засветить светодиоды… красные, обычные — от 1.7В начинают светить, так что без проблем…
                                          0
                                          Пауза должна ставиться одновременным нажатием на кнопки игроков.
                                            0
                                            Спасибо, замечание принято. Я слишком поздно об этом вспомнил.
                                            0
                                            А я бы опрос кнопок повесил на внешнее прерывание, чтобы основной цикл не забивать.
                                            Будет достаточно одного внешнего прерывания, к которому через диоды подключены все кнопки. В момент срабатывания прерывания проводить опрос, какие именно кнопки нажаты.
                                              0
                                              Я думал о внешнем прерывании, но после того, как индикация была вынесена из основного цикла в прерывание и ей нажатие кнопок больше не мешало, решил оставить так.
                                                0
                                                Кнопки лучше опрашивать вместе с выводом на индикатор — автоматически решается проблема с дребезгом. Когда кнопки фиксируются 100 раз в секунду то дребезг может лишь отложить момент нажатия на 1/100 секунды не более. При условии что процесс дребезга длится менее 10мс — это должны быть очень разбитые и неконтачащие кнопки. Причем, в прерывании вывода на индикатор просто считываем состояние кнопок и запоминаем в переменной. А основной цикл уже пусть разбирается с этой переменной — вполне безопасно.
                                                Если в основном цикле сравнивать нынешнее состояние кнопок с предыдущим то можно легко засечь моменты нажатия и отпускания не реагируя на длительно нажатые кнопки — это может быть важно в алгоритмах с запоминанием состояния вроде триггеров, счетчиков…
                                              • UFO just landed and posted this here
                                                  +11
                                                  Спасибо, КО!
                                                    0
                                                    В будущем, буду писать так:
                                                    «ОК, КО, ОК!»
                                                    –1
                                                    Чёрт, опоздал :(
                                                    0
                                                    Ну как же Вы так? Ни транзисторов на выходе пинов МК, управляющих светодиодами, ни резисторов перед светодиодами, кнопки не подтянуты к какому-либо логическому уровню… Советую поизучать базовые советы, иначе будут непонятные глюки и отказы — а это довольно неприятно =(
                                                    Но в целом работа хорошая! Пару допилов — и будет стабильное устройство, которое проработает долго =) Удачи Вам в радиоэлектронике!
                                                      0
                                                      Спасибо за совет. На самом деле кнопки подтянуты внутренними резисторами, это указано в тексте.
                                                        0
                                                        Ой, простите, не заметил, видимо =) Правда, иногда их может и не хватить, как было указано в некоторых прочитанных мной книгах, там рекомендовали для надёжности поставить ещё и внешние. Ну да ладно, думаю, не Ваш случай.
                                                          0
                                                          Внешние обычно ставят не для надежности, а при наличии общей шины и использования выходов в режиме ОК (открытый коллектор). Делается это для того, чтобы не увеличивать токи через выходные транзисторы микросхем.
                                                      0
                                                      В этом случае не обязательно использовать динамическую индикацию — посмотрите в сторону дешифраторов, стоят пару рублей, а головной боли меньше будет.
                                                        0
                                                        А из чего и как вы сделали корпус?
                                                        –1
                                                        Использовав сдвиговые регистры, можно было сэкономить ножки.
                                                          +1
                                                          Их тут и так хватает, зачем?
                                                          +2
                                                          На разных user-friendly дистрах вноде убунты обычно не нужно возиться с udev. Чаще достаточно добавиться в нужную группу (обычно — dialout).
                                                          Обычно так — подключаешь девайс, запускаешь dmesg и смотришь в хвосте лога, что за имя присвоено устройству (например — ttyACM2). Потом делаешь ls -la /dev/ttyACM2 и сразу видишь, у какого пользователя/группы есть права на общение с устройством. Ну и финальные adduser себя в найденную группу с последующим перезапуском сессии окончательно ликвидирует необходимость прописывать правила udev.
                                                            0
                                                            Спасибо, надо будет попробовать
                                                            0
                                                            Подскажите пожалуйста, питание целевой платы при прошивке от программатора осуществляется? На фото не видно, откуда вы питание подвели.
                                                            И где взять такой удобный разъём ISP на плату?
                                                              0
                                                              Подскажите пожалуйста, питание целевой платы при прошивке от программатора осуществляется?

                                                              Да
                                                              И где взять такой удобный разъём ISP на плату?

                                                              Это обычный ISP разъем, припаянный к куску перфорированной платы с выводами на монтажную плату через однорядный коннектор типа такого
                                                                0
                                                                Спасибо! Пойду в чип&дип =)
                                                                  0
                                                                  Удачи!

                                                            Only users with full accounts can post comments. Log in, please.