Программирование контроллеров для начинающих своими руками пошаговая инструкция

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

Время на прочтение
9 мин

Количество просмотров 377K

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

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

Тема микроконтроллеров меня заинтересовала очень давно, году этак в 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. Ну и напоследок, небольшая видео-демонстрация прототипа:

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

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

Что такое Arduino и для чего оно нужно?

Arduino — это электронный конструктор, который позволяет любому человеку создавать разнообразные электро-механические устройства. Ардуино состоит из программной и аппаратной части. Программная часть включает в себя среду разработки (программа для написания и отладки прошивок), множество готовых и удобных библиотек, упрощенный язык программирования. Аппаратная часть включает в себя большую линейку микроконтроллеров и готовых модулей для них. Благодаря этому, работать с Arduino очень просто!

С помощью ардуино можно обучаться программированию, электротехнике и механике. Но это не просто обучающий конструктор. На его основе вы сможете сделать действительно полезные устройства.
Начиная с простых мигалок, метеостанций, систем автоматизации и заканчивая системой умного дома, ЧПУ станками и беспилотными летательными аппаратами. Возможности не ограничиваются даже вашей фантазией, потому что есть огромное количество инструкций и идей для реализации.

проекты на Arduino

проекты на Arduino

Стартовый набор Arduino

Для того что бы начать изучать Arduino необходимо обзавестись самой платой микроконтроллера и дополнительными деталями. Лучше всего приобрести стартовый набор Ардуино, но можно и самостоятельно подобрать все необходимое. Я советую выбрать набор, потому что это проще и зачастую дешевле. Вот ссылки на лучшие наборы и на отдельные детали, которые обязательно пригодятся вам для изучения:

Базовый набор ардуино для начинающих: Купить
Большой набор для обучения и первых проектов: Купить
Набор дополнительных датчиков и модулей: Купить
Ардуино Уно самая базовая и удобная модель из линейки: Купить
Беспаечная макетная плата для удобного обучения и прототипирования: Купить
Набор проводов с удобными коннекторами: Купить
Комплект светодиодов: Купить
Комплект резисторов: Купить
Кнопки: Купить
Потенциометры: Купить

Среда разработки Arduino IDE

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

Язык программирования Ардуино

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

Для программирования Arduino используется упрощенная версия языка C++ с предопределенными функциями. Как и в других Cи-подобных языках программирования есть ряд правил написания кода. Вот самые базовые из них:

  • После каждой инструкции необходимо ставить знак точки с запятой (;)
  • Перед объявлением функции необходимо указать тип данных, возвращаемый функцией или void если функция не возвращает значение.
  • Так же необходимо указывать тип данных перед объявлением переменной.
  • Комментарии обозначаются: // Строчный и /* блочный */

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

Все прошивки для Arduino должны содержать минимум 2 функции. Это setup() и loop().

Функция setup

Функция setup() выполняется в самом начале и только 1 раз сразу после включения или перезагрузки вашего устройства. Обычно в этой функции декларируют режимы пинов, открывают необходимые протоколы связи, устанавливают соединения с дополнительными модулями и настраивают подключенные библиотеки. Если для вашей прошивки ничего подобного делать не нужно, то функция все равно должна быть объявлена. Вот стандартный пример функции setup():

void setup() {
	Serial.begin(9600);	// Открываем serial соединение
	pinMode(9, INPUT);	// Назначаем 9 пин входом
	pinMode(13, OUTPUT); // Назначаем 13 пин выходом
}

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

Функция loop

Функция loop() выполняется после функции setup(). Loop в переводе с английского значит «петля». Это говорит о том что функция зациклена, то есть будет выполняться снова и снова. Например микроконтроллер ATmega328, который установлен в большинстве плат Arduino, будет выполнять функцию loop около 10 000 раз в секунду (если не используются задержки и сложные вычисления). Благодаря этому у нас есть большие возможности.

Макетная плата Breadbord

Вы можете создавать простые и сложные устройства. Для удобства я советую приобрести макетную плату (Breadbord) и соединительные провода. С их помощью вам не придется паять и перепаивать провода, модули, кнопки и датчики для разных проектов и отладки. С беспаечной макетной платой разработка становится более простой, удобной и быстрой. Как работать с макетной платой я рассказывал в этом уроке. Вот список беспаечных макетных плат:

Макетная плата на 800 точек с 2 шинами питания, платой подачи питания и проводами: Купить
Большая макетная плата на 1600 точек с 4 шинами питания: Купить
Макетная плата на 800 точек с 2 шинами питания: Купить
Макетная плата на 400 точек с 2 шинами питания: Купить
Макетная плата на 170 точек: Купить
Соединительные провода 120 штук: Купить

Первый проект на Arduino

Давайте соберем первое устройство на базе Ардуино. Мы просто подключим тактовую кнопку и светодиод к ардуинке. Схема проекта выглядит так:

Управление яркостью светодиода

Управление яркостью светодиода

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

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

 // переменные с пинами подключенных устройств
int switchPin = 8;
int ledPin = 11;

// переменные для хранения состояния кнопки и светодиода
boolean lastButton = LOW;
boolean currentButton = LOW;
boolean ledOn = false;

void setup() {
	pinMode(switchPin, INPUT);
	pinMode(ledPin, OUTPUT);
}

// функция для подавления дребезга
boolean debounse(boolean last) {
	boolean current = digitalRead(switchPin);
	if(last != current) {
		delay(5);
		current = digitalRead(switchPin);
	}
	return current;
}

void loop() {
	currentButton = debounse(lastButton);
	if(lastButton == LOW && currentButton == HIGH) {
		ledOn = !ledOn;
	}
	lastButton = currentButton;
	digitalWrite(ledPin, ledOn);
}

В этом скетче я создал дополнительную функцию debounse для подавления дребезга контактов. О дребезге контактов есть целый урок на моем сайте. Обязательно ознакомьтесь с этим материалом.

ШИМ Arduino

Широтно-импульсная модуляция (ШИМ) — это процесс управления напряжением за счет скважности сигнала. То есть используя ШИМ мы можем плавно управлять нагрузкой. Например можно плавно изменять яркость светодиода, но это изменение яркости получается не за счет уменьшения напряжения, а за счет увеличения интервалов низкого сигнала. Принцип действия ШИМ показан на этой схеме:

ШИМ ардуино

ШИМ ардуино

Когда мы подаем ШИМ на светодиод, то он начинает быстро зажигаться и гаснуть. Человеческий глаз не способен увидеть это, так как частота слишком высока. Но при съемке на видео вы скорее всего увидите моменты когда светодиод не горит. Это случится при условии что частота кадров камеры не будет кратна частоте ШИМ.

В Arduino есть встроенный широтно-импульсный модулятор. Использовать ШИМ можно только на тех пинах, которые поддерживаются микроконтроллером. Например Arduino Uno и Nano имеют по 6 ШИМ выводов: это пины D3, D5, D6, D9, D10 и D11. В других платах пины могут отличаться. Вы можете найти описание интересующей вас платы в этом разделе.

Для использования ШИМ в Arduino есть функция analogWrite(). Она принимает в качестве аргументов номер пина и значение ШИМ от 0 до 255. 0 — это 0% заполнения высоким сигналом, а 255 это 100%. Давайте для примера напишем простой скетч. Сделаем так, что бы светодиод плавно загорался, ждал одну секунду и так же плавно угасал и так до бесконечности. Вот пример использования этой функции:

 // Светодиод подключен к 11 пину
int ledPin = 11;

void setup() {
	pinMode(ledPin, OUTPUT);
}

void loop() {
	for (int i = 0; i < 255; i++) {
		analogWrite(ledPin, i);
		delay(5);
	}

	delay(1000);

	for (int i = 255; i > 0; i--) {
		analogWrite(ledPin, i);
		delay(5);
	}
}

Аналоговые входы Arduino

Как мы уже знаем, цифровые пины могут быть как входом так и выходом и принимать/отдавать только 2 значения: HIGH и LOW. Аналоговые пины могут только принимать сигнал. И в отличии от цифровых входов аналоговые измеряют напряжение поступающего сигнала. В большинстве плат ардуино стоит 10 битный аналогово-цифровой преобразователь. Это значит что 0 считывается как 0 а 5 В считываются как значение 1023. То есть аналоговые входы измеряют, подаваемое на них напряжение, с точностью до 0,005 вольт. Благодаря этому мы можем подключать разнообразные датчики и резисторы (терморезисторы, фоторезисторы) и считывать аналоговый сигнал с них.

Для этих целей в Ардуино есть функция analogRead(). Для примера подключим фоторезистор к ардуино и напишем простейший скетч, в котором мы будем считывать показания и отправлять их в монитор порта. Вот так выглядит наше устройство:

Подключение фоторезистора к Ардуино

Подключение фоторезистора к Ардуино

В схеме присутствует стягивающий резистор на 10 КОм. Он нужен для того что бы избежать наводок и помех. Теперь посмотрим на скетч:

int sensePin = 0; // Пин к которому подключен фоторезистор
 
void setup() {
 analogReferense(DEFAULT); // Задаем опорное значение напряжения. Эта строка не обязательна.
 Serial.begin(9600); // Открываем порт на скорости 9600 бод.
}
 
void loop() {
 Serial.println(analogRead(sensePin)); // Считываем значение и выводим в порт
 delay(500); // задержка для того что бы значений было не слишком много
}

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

Вот мы и рассмотрели основы работы с Arduino. Теперь вы можете сделать простейшие проекты. Что бы продолжить обучение и освоить все тонкости, я советую прочитать книги по ардуино и пройти бесплатный обучающий курс. После этого вы сможете делать самые сложные проекты, которые только сможете придумать.

Микроконтроллер – микросхема, предназначенная для управления электронными устройствами, или по другому – простенький компьютер (микро-ЭВМ), способный выполнять несложные задачи.

Микроконтроллеры AVR: устройство и программирование
Рано или поздно, любой радиолюбитель (я так думаю), приходит к мысли о применении в своих разработках микроконтроллеров. Микроконтроллер позволяет существенно «облегчить» радиолюбительскую конструкцию, сделать ее проще и намного функциональнее.

Что нужно для того, чтобы начать пользоваться всеми возможностями микроконтроллеров? Я считаю, что не так уж и много. Главное в этом деле — желание. Будет желание, будет и результат.

 В этом разделе (и в разделе «Устройство AVR») сайта я постараюсь помочь начинающим «микроконтроллерщикам» сделать первый, он же самый трудный шаг навстречу микроконтроллерам — попробуем разобраться в устройстве и программировании микроконтроллеров AVR семейства ATtiny и ATmega.

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

В своих статьях я буду опираться на материалы из публикаций популярных авторов микроконтроллерной тематики: Рюмика С.М., Белова А.В., Ревича Ю.В., Евстифеева А.В., Гребнева В.В., Мортона Д., Трамперта В., Фрунзе А.В. и Фрунзе А.А. (и многих других), а также материалы радиолюбительских сайтов. Ну и, может быть, немного своих «умных мыслей».


Программирование микроконтроллеров AVR фирмы Atmel


Микроконтроллеры - первый шаг1. Микроконтроллеры — первый шаг

Эта статья, как и все последующие, — маленький шажок в мир микроконтроллеров. И таких «шажков» у нас будет много, пока не дойдем до того момента, когда сможем сказать: «Микроконтроллер — последний шаг». Но и это, скорее всего, из области фантастики — нельзя объять необъятное, — мир микроконтроллеров постоянно развивается и совершенствуется. Наша задача — сделать первый шаг, логическим итогом которого должна стать первая, самостоятельно разработанная и собранная конструкция на микроконтроллере.


Системы счисления2. Системы счисления: десятичная, двоичная и шестнадцатиричная

Как вы наверняка знаете, существует много разных систем счисления, одними пользуются и сейчас (наша, родная, десятичная система; римская система, известная нам как «римские цифры»), другие остались в глубоком прошлом (системы счисления инков и майя, древнеегипитская система, вавилонская).
Тут, я думаю, вопросов у нас нет, что такое системы счисления нам понятно — отображение чисел символами. А вот какая связь систем счисления с микроконтроллерами.


Логические выражения3. Логические операции, логические выражения, логические элементы

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


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


5. Прямой, обратный и дополнительный коды двоичного числа

Прямой, обратный и дополнительный коды двоичного числа — способы представления двоичных чисел с фиксированной запятой в компьютерной (микроконтроллерной) арифметике, предназначенные для записи отрицательных и неотрицательных чисел


Программатор USBASP AVR6. USBASP программатор для микроконтроллеров AVR — идеальное решение для начинающих, и не только

Сегодня мы рассмотрим как, без особых затрат и быстро, запрограммировать любой микроконтроллер AVR поддерживающий режим последовательного программирования (интерфейс ISP) через USB-порт компьютера. В качестве программатора мы будем использовать очень простой и популярный программатор USBASP, а в качестве программы — AVRdude_Prog V3.3, которая предназначена для программирования МК AVR.


Программа AVRdudeProg7. Программа AVRDUDE_PROG: программирование микроконтроллеров AVR ATmega и ATtiny

Популярнейшая программа AVRDUDE_PROG 3.3 предназначена для программирования микроконтроллеров AVR ATmega и ATtiny


Основы программирования микроконтроллеров8. Основы программирования микроконтроллеров AVR

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


Программа Atmel Studio9. Русификация программы Atmel Studio

В этой статье мы поговорим о проблемах русификации программы Atmel Studio, как перевести программу на русский (или другой) язык, и как сделать более удобной работу программы с программатором USBASP. После установки программы Atmel Studio весь интерфейс будет на английском языке. Кому-то, кто знаком с английским, или уже привык работать с программами с английским интерфейсом, это вполне устроит. Меня лично, такой подход создателей программы к великому и могучему не устраивает, мне более комфортно работать с русскими меню.


Почему С10. Введение в язык программирования С (Си) для микроконтроллеров

В этой статье будут рассмотрены основные сведение о языке С, структура программы на языке С, дано понятие о функциях, операторах и комментариях данного языка программирования.


Арифметические операции С11. Переменные и константы в языке С (Си) для микроконтроллеров AVR

В этой статье будут рассмотрены типы переменных в языке С (Си) для микроконтроллеров AVR, объявление переменных, способы задания констант, будет дан обзор арифметических операций языка С, присваивания, инкремента и декремента.


Зажигание светодиода12. Управление портами микроконтроллеров AVR на языке С (Си)

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



Структура цикла с предусловием13. Циклы в языке С (Си) для микроконтроллеров AVR

В данной статье будут рассмотрены циклы в языке программирования Си для микроконтроллеров AVR. Будут рассмотрены циклы типа «для» (for) и циклы типа «пока» (while), будет показано как осуществить принудительное прерывание цикла и организовать бесконечный цикл.



Что такое массив14. Массивы в программировании микроконтроллеров AVR

В данной статье мы рассмотрим основы использования массивов в языке С для микроконтроллеров AVR и рассмотрим их практическое применение в программе для изменения цифр на семисегментном индикаторе.



Что такое конечный автомат15. Конечные автоматы в микроконтроллерах AVR

В данной статье мы рассмотрим применительно к микроконтроллерам AVR такой интересный стиль программирования микроконтроллеров как автоматное программирование. Точнее это даже не стиль программирования а целая концепция, благодаря которой программист микроконтроллеров может существенно облегчить свою жизнь. Благодаря ей многие задачи, поставленные перед программистом, решаются гораздо легче и проще, избавляя программиста от многих сложностей. Автоматное программирование часто также называют Switch-технологией


(29 голосов, оценка: 4,76 из 5)
Загрузка…


Программирование микроконтроллеров AVR

Микроконтроллеры AVR: программирование и применение микроконтроллеров ATmega и ATtiny для начинающих

Published by: Мир микроконтроллеров

Date Published: 04/01/2015

Introduction: Programming PIC Microcontrollers

PIC microcontrollers are a very useful and versatile tool for use in many electronic projects. They are very inexpensive and easy to find. They are also very powerful and many are capable of speeds up to 64 MIPS using the internal oscillator block, about 16 times faster than most comparable AVR microcontrollers. PICs are also easy to program, however getting the project set up can some times be tricky. These instructions will walk through the process of setting up the software, creating a new project, and programming some very simple functions to test the configuration and ensure everything is working. They are designed to be very open ended; after the project is created and the basics are finished the reader is encouraged to explore all the features and extras not covered in these instructions. Also you will find that these instructions will start out walking through step by step, but as the instructions near the end the reader is encouraged to explore other ways of accomplishing the tasks and make the project their own.
What you will need To build a project with a PIC microcontroller only requires a few items.

  • PIC microcontroller
    • These instructions are for programming a PIC18F series MCU, although others are similar.
    • Obtained from Microchips website.
    • Microchip allows students with valid .edu email addresses sample PIC’s for free!
    • The PIC I am using to create these instructions is a PIC18F22K80
  • PICkit 3 In-Circuit Debugger
    • Available from Microchip.
    • Costs $45 for general public, and #34 with student discount if you have an .edu email address.
    • There are also other programmers which will work just as well; however, this is the best one for starting out.
  • Breadboard and breadboard wires
  • LEDs, buttons, potentiometers, or anything else you would like to connect to the PIC

Step 1: Build Hardware

Before doing any programming the first step is to build the hardware. Although the PIC18F portfolio is very large, many of the chips have several commonalities. For more detailed information see the «Guidelines for Getting Started with PIC18Fxxxx Microcontrollers» section in your devices datasheet. For detailed pin-outs of the PIC microcontroller see the «Pin Diagram» section in your devices datasheet.

Note: VDD = Positive Voltage and VSS = Ground.

  1. Connect the MCLR pin through a 1kΩ resistor to VDD.
  2. Connect a 0.1μF capacitor between every pair of adjoining VDD-VSS pairs or AVDD-AVSS pairs.
  3. Connect a 10μF capacitor between VCAP and Vss.
  4. Connect MCLR pin to pin 1 of the PICkit 3.
  5. Connect VDD to pin 2 of the PICkit 3.
  6. Connect VSS to pin 3 of the PICkit 3.
  7. Connect PGD pin to pin 4 of the PICkit 3.
  8. Connect PGC pin to pin 5 of the PICkit 3.
  9. Leave pin 6 of the PICkit 3 unconnected.
  10. Connect any analog inputs to pins with ANx functionality where x is a number.
  11. Connect any digital inputs or outputs to pins with Rxy functionality where x is a letter identifying the port, and y is a number identifying the bit.

For my example I have an LED connected between RA0 and ground, the wiper of a potentiometer connected to AN1, and a DPST switch connected to RA2. You may find it easier to program the PIC if you have sketched down a schematic of your circuit.

Step 2: Get Software

These instructions will use XC8 compiler and MPLAB X IDE by Microchip. This step will explain how to get these tools and ensure they have been installed correctly.

  1. To get the latest version of the software visit Microchips website at http://www.microchip.com/pagehandler/en-us/family/mplabx/
  2. Select the software for your OS and follow the standard installation instructions.

Note: If you are using Windows 8 you may need to run the installers in compatibility mode for Windows 7.

  1. Once the software is installed, start MPLAB X
  2. In the menu bar select Tools->Options
  3. In the Options dialog select the Embedded tab and ensure XC8 is listed in the Toolchain list.
  4. If it is listed select OK and move on the next step.
  5. If it is not listed ensure that instillation has completed, and click Scan for Build Tools button.
  6. If still not listed, look on Microchips forum for help with your specific problem.

Step 3: Create New Project

In this step we will create a new project based on a template from Microchip.

  1. On the menu bar select File->New Project…
  2. In the new file dialog box expand Samples and select Microchip Embedded
  3. In the project box select PIC18 C Template
  4. Select Next
  5. Give the project any name you like
  6. Choose a location to save the project to in the Project Location box
  7. Leave the Project Folder as default options
  8. Check «Set as Main Project» box
  9. Select Finish

The project will now show up in Project Explore on the left hand side of the screen.

Step 4: Build Parameters

Before we can get started programming we need to set the build parameters.
Create Configuration

  1. Right click on the project name in the projects tool bar.
  2. In the Project Properties dialog select Manage Configurations…
  3. In the Configurations dialog select New
  4. In the New Configuration Name dialog enter Default and click OK
  5. In the Configurations dialog make sure Default is selected and click Set Active
  6. Click OK in the Configurations dialog

Set Configuration Properties

  1. In the Project Properties dialog select «Conf: [Default]» in the Categories list
    1. In the Device box type the name of the device you are using. In my case PIC18F26K80
    2. In the Hardware Tools list select PICkit3
    3. In the Compiler Toolchain select XC8 (v…) Where … is the version you have installed.
    4. Select Apply
  2. Under Conf: [Default] select PICkit 3
    1. For Option categories select Power
    2. Check «Power target circuit from PICkit3
    3. Select Apply.
  3. Under Conf: [Default] select XC8 compiler
    1. For Option categories select Optimizations
    2. Set «Optimization Set» to «none»
    3. Select Apply
  4. Click OK to close the dialog box

Test the Configuration To test the configuration click the clean and build button (the one with the hammer and broom). Text will start scrolling in the output window at the bottom of the page. If everything is successful the this text will say BUILD SUCCESSFUL (total time: …). If you get an error, go back through this step making sure that you did not miss anything, and that everything was applied.

Step 5: Set Configuration Bits

The next step is setting the configuration bits. The configuration bits tell the MCU its initial conditions for when it turns on. They are used to set the clock source and speed, watchdog time configuration, and other similar features. Configuration bits are device dependent, so check the data sheet for the chip you are using for more information.

  1. In the project explorer expand Source Files and open configuration_bits.c
  2. Remove all the text below the #endif line
  3. Notice a new tab has opened at the bottom of the screen
  4. Set the bits as needed for your project. Since these are chip dependent, check the data sheet for more information about what each does. Some common settings follow:
    1. Extended Instruction Set — Should be set to OFF when using template
    2. Oscillator — Used to select the processor. Unless you are using an external crystal, leave set as Internal RC oscillator. See data sheet for other oscillator configurations. Note: CLKOUT will allow for easier debugging, and should be turned on if available.
    3. PLL Enable — Will allow for future use of the PLL. Note: this will not turn on the PLL, it will only enable it. It is recommended to enable it.
    4. Watchdog Timer — The watch dog timer is used to ensure the processor will not lock up. It however makes it much harder to debug. It is recommended to disable it while initially programming, and only enable it after the project is nearly done.
    5. Code/Table Write/Read protects — Used to disable writing or reading to certain ranges of memory. Leave all of these disabled.
    6. If unsure about a setting, it is usually safe to leave it default.
  5. After all configuration bits have been set, click the «Generate Source Code to Output» button at the bottom of the panel.
  6. The panel will now switch to the Output tab. Select all the text in this tab and copy it to the clip board
  7. Paste it at the bottom of the configuration_bits.c file and pres save.
  8. Clean and build the project again by clicking the broom and hammer icon.
  9. Ensure the build was successful. Also check to make sure there was no errors in the output

If everything has worked move on to the next step. If there are errors or warnings fix them before moving on.

Step 6: Configure Oscillator

The next step is to start programming; however, before we get to the application code we must program the system code. The system code are the low level functions such as configuring the oscillator and basic delay functions.

Determining Settings

Before we can program the settings, we must choose what speed we would like to run at. For this example I will use 16MHz as most PIC’s can run at this speed. For my configuration I will use the 4MHz postscaller from the HF-INTOSC, and the 4x PLL giving an output frequency of 4MHz*4x=16MHz

  1. In the datasheet find the section labeled Oscillator Configurations
  2. The first thing listed in this section is Oscillator Types. If you are using the internal oscillator then use the settings relating to INTIO1
  3. On the next page or two you will find a schematic drawing of the oscillator similar to the one shown. It is helpful to trace the signal on this drawing to ensure the correct speed is being selected.
  4. The next step is to program these settings to the MCU. This is done by setting registers. The first register to set is OSCCON.

    1. IDLEN — used to control the action of the sleep command. Can be left as default.
    2. IRCF — Oscillator selection. Since I am using HF-INTOSC/4 (4MHz) I will need to set this to a binary value of 101
    3. OSTS — Read only bit
    4. HFIOFS — Read only bit
    5. SCS — clock select bits. Since I am using the internal oscillator, I will set to 1x where x can be 0 or 1
  5. The next register is OSCCON2; however, this register is mostly read only and not important at this point
  6. The last oscillator configuration register is OSCTUNE. We will not tune the frequency for this project, however we must use this register to turn on the PLL using the PLLEN bit.

Applying Settings

  1. Return to MPLAB
  2. In the project explorer under Source Files open system.c
  3. At the bottom of this file is the function ConfigureOscillator. Remove the comments in that function.
  4. To set the bits of a register type in all caps the register name, followed by the lowercase word bits and then a period and the bit name.
  5. To set the bits follow that with an equal sign. To use binary type 0bXXXX where XXXX is the binary number. Lastly end the line with a semi-colon.
  6. Set all the bits as determined above for the OSCCON register. Example: OSCCONbits.IRCF = 0b101;
  7. Do the same for all other needed oscillator registers. See below for an example of a finished ConfigureOscillator function.
  8. When finished build and check for warnings/errors
/** * Configure the clock source and speed */void ConfigureOscillator(void){
    OSCCONbits.IRCF     =0b101;
    OSCCONbits.SCS      =0b00;
    OSCTUNEbits.PLLEN   =0b1;}

Step 7: Wait Milli-Second Function

One of the most useful functions is wait_ms. This however is not a function in the standard library, and will need to be programmed by you. For this implementation there will be a loop which will hold the processor until the given time has passed.

PIC18F microcontrollers need 4 clock cycles to execute one line of assembly code. Therefore with a clock of 16MHz, lines will be executed at 4 million lines per second = 4000 lines per milli-second. Since a for loop will take one instruction each time for the comparison, and two for the operation one for the body of the loop, it will work perfectly. We just need the for loop to loop 1000 time per milli-second.

  1. In system.c create a new function at the bottom of the file of type void wait_ms(uint16_t time)
  2. Below is the completed function
/**
 * Wait for a given number of milli-seconds using busy waiting scheme.
 * @param time - time in ms to wait.
 */
void wait_ms(uint16_t time)
{
    static long timel = 0;
    timel = time * 1000l;
    for( ; timel; timel--);// no initial condition, while time is >0, decrement time each loop
}
  1. Open system.h in the Header Files folder in the project browser
  2. At the end add the line void wait_ms(uint16_t); to prototype the function.
  3. Change line 8 from 8000000L to 16000000L
  4. Build and check for errors/warnings

Step 8: Blink an LED

The best way to test that everything is set up correctly is to blink an LED light. If the light blinks at the expected rate then everything has been configured correctly. In this example the LED is connected to PORT A, Pin 0 (RA0 on the datasheet). If you have your LED connected to a different pin, use the appropriate registers and bits.

  1. Open main.c in the project viewer under source files.

The function void main(void) is the main entry point of the program. When the MCU first powers on it will enter into this function. The first line calls the ConfigureOscillator function you filled in to set the clock source and speed. The next line calls InitApp, a function that we will fill in shortly, and finally it enters an infinite loop. Since there is no operating system for the function to return to, there is no return call at the end.
The finished function should look like this:

  1. Immediately above the while loop add the following code.
    1. Set the LED pin as output — TRISAbits.TRISA0 = 0; // setting a TRIS bit to 0 sets as output, setting to 1 sets as input
  2. Inside the while loop add the following code
    1. Set the LED to OFF — LATAbits.LATA0 = 0; // the LAT bits control the output of a pin. 0 = LOW, 1 = HIGH
    2. Wait for 1/2 second — wait_ms(500);
    3. Set the LED to ON — LATAbits.LATA0 = 1;
    4. Wait for 1/2 second — wait_ms(500);
void main(void)
{
    /* Configure the oscillator for the device */
    ConfigureOscillator();

    /* Initialize I/O and Peripherals for application */
    InitApp();
   
    TRISAbits.TRISA0 = 0; // set pin as output
    while(1)
    {
        LATAbits.LATA0 = 0; // set pin LOW
        wait_ms(500);       // wait 0.5 seconds
        LATAbits.LATA0 = 1; // set pin HIGH
        wait_ms(500);       // wait 0.5 seconds
    }
}
  1. Build the program and check for errors or warnings
  2. Ensure the PICkit is connected correctly to the PIC and the computer
  3. Click the make and program device button (the button to the right of the clean and build button)
  4. If prompted select PICkit 3 and click OK
  5. When the warning shows double check you have the correct PIC in the circuit and click OK
  6. If a warning shows about Target Device ID click OK to ignore it

Step 9: Reading an Analog Value

So far the program can blink an LED. Next lets give it some user input. We will use a potentiometer to create an analog signal which will change the speed of the LED. The ADC takes an analog voltage, and outputs a digital value.

  1. In the project browser open user.c under Source Files
  2. Above the InitApp function create a new function void init_adc(void)
  3. Enter the following code to initialize the ADC module
/** * Initialize the Analog to Digital Converter. */void init_adc(void){
    TRISAbits.TRISA1    =0b1;// set pin as input
    ANCON0bits.ANSEL1   =0b1;// set pin as analog
    ADCON1bits.VCFG     =0b00;// set v+ reference to Vdd
    ADCON1bits.VNCFG    =0b0;// set v- reference to GND
    ADCON1bits.CHSN     =0b000;// set negative input to GND
    ADCON2bits.ADFM     =0b1;// right justify the output
    ADCON2bits.ACQT     =0b110;// 16 TAD
    ADCON2bits.ADCS     =0b101;// use Fosc/16 for clock source
    ADCON0bits.ADON     =0b1;// turn on the ADC}
  1. Next create another function immediately after called uint16_t adc_convert(uint8_t channel)
/** * Preform an analog to digital conversion. * @param channel The ADC input channel to use. * @return The value of the conversion. */
uint16_t adc_convert(uint8_t channel){
    ADCON0bits.CHS      = channel;// select the given channel
    ADCON0bits.GO       =0b1;// start the conversionwhile(ADCON0bits.DONE);// wait for the conversion to finishreturn(ADRESH<<8)|ADRESL;// return the result}
  1. In the InitApp function add the line init_adc()
  2. In the file user.h add the prototype uint16_t adc_convert(uint8_t);
  3. Change main to match the following:
voidmain(void){
    uint16_t adc_value;// variable to hold ADC conversion result in/* Configure the oscillator for the device */
    ConfigureOscillator();/* Initialize I/O and Peripherals for application */
    InitApp();

    TRISAbits.TRISA0 =0;// set pin as outputwhile(1){
        LATAbits.LATA0 =0;// set pin LOW
        adc_value = adc_convert(1);// preform A/D conversion on channel 1
        wait_ms(adc_value>>2);// wait 0.5 seconds
        LATAbits.LATA0 =1;// set pin HIGH
        adc_value = adc_convert(1);// preform A/D conversion on channel 1
        wait_ms(adc_value>>2);// wait 0.5 seconds}}
  1. Build and download the code. As you turn the POT the speed the LED blinks should change

Step 10: Read a Digital Value

Next lets get digital input from the switch. When the switch is off we will have the program do what it has been doing all along, and when the switch is on the program will light up the LED solid until the switch is turned off again.

  1. To set a pin as an input, write a 1 to that pins TRIS register bit — TRISAbits.TRISA2 = 1;
  2. If a pin share analog features, it may be necessary to set it to digital by clearing the appropriate bit in ANCONx register
  3. When writing a value to a pin use the LAT register; however, when reading a value from a pin use the PORT register — value = PORTAbits.RA2;
  4. Change main to the following:
voidmain(void){
    uint16_t adc_value;// variable to hold ADC conversion result in/* Configure the oscillator for the device */
    ConfigureOscillator();/* Initialize I/O and Peripherals for application */
    InitApp();

    TRISAbits.TRISA0 =0;// set pin as output
    TRISAbits.TRISA2 =1;// set pin as input
    ANCON0bits.ANSEL2=0;// set pin as digitalwhile(1){if(PORTAbits.RA2)// if the pin is high{
            LATAbits.LATA0 =1;// set the pin as high}else// if the pin is low{// blink the LED
            LATAbits.LATA0 =0;// set pin LOW
            adc_value = adc_convert(1);// preform A/D conversion on channel 1
            wait_ms(adc_value>>2);// wait some time
            LATAbits.LATA0 =1;// set pin HIGH
            adc_value = adc_convert(1);// preform A/D conversion on channel 1
            wait_ms(adc_value>>2);// wait some time}}}

That is it! You now have the basic knowledge of how to set up a new project, read and write to digital pins, and how to read from analog pins. These three features will allow you to do 90% of the projects using PICs on the Internet. Also, as you continue your exploration into PIC microcontrollers you will find that most other features require very similar steps to configure peripherals, and read and right to registers.

Программирование микроконтроллеров на языке C. Часть 1

Приветствую всех жителей и гостей Датагор.ру!
Года полтора назад мы с Радиком Галимовым, более известным как камрад Galrad, обсуждали возможность совместной публикации о программировании микроконтроллеров на языке Си.

Содержание статьи / Table Of Contents

Далее закружились всякие важные и не очень события и стало как-то не до того.
А недавно меня настигла и сокрушила новость о том, что Радика с нами больше нет. Об этом сообщил в редакцию нашего журнала камрад Александр (mazr).
Отдавая дань уважения, я решил всё же написать статью и посвятить её памяти этого замечательного Человека.

Данная работа является логическим продолжение серии статей «Ассемблер для микроконтроллеров с нуля», в которой достаточно подробно освещены:
• Общие принципы устройства и работы микроконтроллера (МК).
• Система тактирования и прерывания.
• Назначение и функциональные возможности таких модулей МК, как порт ввода/вывода, АЦП, таймер.
• Механизм компиляции и сборки проекта средствами GCC, включая содержимое файлов Makefile и сценария компоновщика LinkerScript.
• Подключение к проекту сторонних объектных файлов и библиотек.
• Структура программы и её оптимизация посредством макроопределений/макросов, функций и хидер-файлов.
• Основные ошибки, допускаемые программистом, и методы их поиска и устранения.

Поскольку вся вышеуказанная информация пригодится нам и при изучении Си, я буду время от времени ссылаться на соответствующий раздел вышеуказанной статьи, для краткости именуя её «Ассемблер…» и лишь в особо важных случаях — дублировать фрагмент текста.

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

Для практических занятий нам понадобятся:

1. Микроконтроллер ATmega8

2. Макетная плата STM32F401

3. Макетная плата nRF52832

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

4. Программатор USBasp для ATmega8

и

Программатор st-link v2 для STM32F401 и nRF52832

.

5.

USB-UART адаптер CH340G

.

6.

Макетная плата

.

7.

Соединительные провода

.

8.

Потенциометры

.

9.

Светодиоды

.

Скачайте и установите компилятор, тулчейны и загрузчики согласно раздела 3.2 первой части «Ассемблер…». Кроме того, потребуются

SPL

(Standard Peripheral Library) для STM32F401 и

SDK

(Software Development Kit) для nRF52832, которые необходимо скачать и сохранить в папку GNU.

В случае, если вы используете STM32 с иным ядром, при скачивании SPL ориентируйтесь на первую цифру после буквы «F» в названии МК.

За последний год, дети «подсадили» меня на редактор

Visual Studio Code

, который имеет перед Notepad++ ряд преимуществ, приведу из которых пару:
а) Более продвинутый интерфейс, включая систему авто-подстановки.
б) Подключение соответствующего расширения даёт возможность писать в этом же редакторе приложения под Windows, Android, iOS (на Java, Python и др.) для обмена информацией с устройством на МК.

В ходе установки следует выставить галочки для подключения опции «Открыть с помощью VS Code».

Программирование микроконтроллеров на языке C. Часть 1

Рисунок 1. Подключение опции «Открыть с помощью VS Code»

Коротко об основных полях и вкладках редактора.

Рисунок 2. Основные вкладки и поля VS Code

Слева располагается панель инструментов, наиболее часто из вкладок которой используются «Проводник» (при кодировании) и «Расширения» (для подключения новых расширений).

В окне редактора мы будем писать наши программы. Здесь же отображаются функции расширения, предполагаемого к установке, а так же опции при настройке редактора через File/Preferences/Settings.

Окно консоли, открываемое комбинацией Control + Shift + тильда, будет использоваться для запуска программа make с целью компиляции кода и загрузки hex-файла в МК.

Поскольку в практических примерах предполагается передача данных в компьютер посредством UART, установим соответствующее расширение, для чего:
1. Пройдём во вкладку «Расширения» панели инструментов и в окне поиска наберём «serial».
2. Выберем из списка расширение «Serial monitor»
3. Нажмём кнопку «Install» в правой части редактора.

Рисунок 3. Установка расширения «Serial monitor»

После установки расширения в одном поле с консолью должна появиться вкладка «Serial Monitor», к настройкам и применению которой вернёмся позже.

Скачайте архив папки шаблонных файлов под ваш МК. Распакуйте папку, зайдите в неё и кликните по свободному месту правой клавишей мыши. Выберите в открывшемся контекстном меню пункт «Открыть с помощью Code / Open with Code».

Рисунок 4. Переход к редактору VS Code

Информацию о структуре и назначении шаблонных фалов можно почерпнуть из 2-й части и 7-й части «Ассемблер…».
В окне проводника редактора, последовательно выбирая нижеуказанные файлы, внесите следующие правки.

Для всех МК в файле c_cpp_properties.json из папки .vscode изменить на свой путь в 8-й строке.

Для AVR при использовании иного микроконтроллера, исправить на соответствующее название МК (например, attiny2313 или atmega328p) в 3-й строке файла variables.mk.

Для STM32F401
1. Изменить на свои пути в строках 8, 9 и 10 файла variables.mk.

2. При использовании МК с другим ядром изменить на соответствующие:
а) в файле variables.mk:
• тип ядра (например, cortex-m0 или cortex-m3) в 3-й строке,
• название файла startup.s в 14-й строке,
• название конфигурационного файла в 48-й строке.
б) в файле LinkerScript.ld:
• начальные адреса и размеры ОЗУ и флэш-памяти в 64-й и 65-й строках, соответственно, ориентируясь на данные из даташита.

Чтобы убедиться в исправности и работоспособности софта и «железа», подключим программатор к компьютеру с одной стороны, а к МК — с другой, соединив для Atmega8 одноимённые пины согласно Рисунка 5.

Рисунок 5. Распиновка а) MK ATmega8 и б) программатора USBasp

В случае с STM32F401 пины, используемые для прошивки, выведены в правую часть макетной платы, причём пин SWCLCK обозначен как SCK, а SWDIO – как DIO. Распиновка макетной платы nRF52832 обозначена на её оборотной стороне.

Рисунок 6. Распиновка макетной платы а) STM32F401 и б) nRF52832 и в) программатора st-link v2

Далее создадим папку нашего первого проекта с именем first, скопируем в неё шаблонные файлы для интересующего нас МК и откроем с помощью VS Code. Скомпилируем файл main.c из папки src, набрав в консоли «make» + Enter. В случае успешной компиляции должна быть автоматически создана папка exe с elf- и hex- файлами. Осталось прошить МК, набрав в консоли «make upload» + Enter. Если компилятор не выдал в консоль сообщения об ошибках, значит мы готовы перейти непосредственно к Си.

Но, об этом — в следующий раз.
Продолжение следует!

🍀

Микроконтроллер ATmega8

🍀

Макетная плата STM32F401

🍀

Макетная плата nRF52832

🍀

Программатор USBasp для ATmega8

🍀

Программатор st-link v2 для STM32F401 и nRF52832

🍀

USB-UART адаптер CH340G

🍀

Макетная плата

🍀

Соединительные провода

🍀

Потенциометры

🍀

Светодиоды

Архивы шаблонных файлов под ваш МК:

🎁atmega8-template.7z
 1.5 Kb ⇣ 25

🎁nrf52832-template.7z
 2.51 Kb ⇣ 13

🎁stm32f401-template.7z
 3.5 Kb ⇣ 15

Понравилась статья? Поделить с друзьями:

А вот и еще интересные новости по теме:

  • Zoncare экг аппарат инструкция по применению
  • Киа рио x line руководство по ремонту
  • Пульт ду harper kbwl 030 инструкция
  • Весы tefal premiss инструкция на русском напольные
  • Саранский механический завод руководство официальный сайт

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии