Если Вы хотите обучаться программированию микроконтроллеров, но попали, сюда не прочитав предыдущих уроков, то советую начать изучение материала с самого начала.
На прошлом занятии мы с вами подключили к микроконтроллеру трехсекционный семисегментный индикатор, а также написали программу-обработчик для отображения цифр и небольших сообщений. Работа обработчика базировалась на статическом массиве находящимся во флешь памяти. На этот раз мы подключим светодиодный кубик, который сделали на одиннадцатом уроке и поиграем в него, используя для этого массив, в котором данные будут меняться в процессе выполнения программы. |
---|
Если вы не смогли сделать домашнее задание к 13-тому уроку, то мою версию таймера можно посмотреть и разобрать в прилагаемых файлах, находящихся в папке «leson_13_1».
И так начнем работу с кубиком. Сперва нам надо подключить его к микроконтроллеру. Ничего сложного в этом нет. Всё как на прошлом занятии за исключением того, что для подключения потребуется не 8, а 9 сигнальных линий.
Обратите внимание на то, что эта схема имеет ряд отличий от той, которую вы собирали на прошлом занятии. Их необходимо учесть. Во-первых, питание не 3.3, а 5 вольт. Во-вторых, управляющие транзисторы не кт814, а кт815. Они другой проводимости (npn), а значит их эмиттеры нужно подключать на общую шину питания. Ну и как было сказано выше для отображения девятого сегмента нам потребуется дополнительная линия РВ0 порта «В». У меня получилось вот так.
После того как схема собрана необходимо убедится в ее правильной работе. Для этого можно заполнить единицами порт «D», подать единицу на выход PB0 и поочередно подать питание на управление транзисторами (выходы МК РВ6, РВ7 и РВ1). При этом должны загораться все светодиоды выбранной секции. Но также можно проявить толику творчества и написать маленькую программку, которая будет по очереди зажигать нам все светодиоды.
Вот слегка упрощенная блок-схема этой программы, которую я предлагаю вам написать самостоятельно.
Для работы программы потребуются три переменные, а также настроить порты «D» и «B» как выходные. При входе в основной цикл происходит проверка нуля счетчика паузы (pausa), который будет осуществлять общую задержку и регулировать скорость переключения светодиодов. После счетчика паузы, в начале каждой итерации переключения, проверяется обнуление счетчика светодиодов (c_led). Если все светодиоды были поочередно включены и счетчик обнулен, то происходит переключение рабочей секции (c_plate), задается номер следующей и происходит проверка по превышению номера секции, после чего выставляется максимальное значение счетчика светодиодов, которое указывает на девятый светодиод. Если же счетчик светодиодов не обнулен, то включается следующий светодиод, а счетчик светодиодов декремируется. После всех изменений выставляется максимальная пауза и цикл повторяется.
В этой блок схеме пропущены некоторые нюансы, с которыми вы встретитесь при написании программы. Конечно в файлах, приложенных к уроку все уже есть, но я бы настоятельно рекомендовал ими не пользоваться, а написать и отладить свою программу. Ведь в программировании, как и в изучении иностранного языка. Чем больше ты на нём говоришь (пишешь программы) тем лучше им владеешь.
Вот что у вас должно получиться в итоге.
Согласитесь, уже красиво. Но эта только проверочная программа, наглядно показывающая нам то, что все светодиоды рабочие, смонтированы и подключены правильно в определенной последовательности.
Помедитировав на «бегающий» светодиод и получив свою долю удовольствия будем двигаться дальше.
Если особо не заморачиваться с ШИМ, то работу светодиода в пределе можно представить, как «горит» - 1 «не горит» - 0. Посему очевидно то, что нам нужен массив данных равный количеству светодиодов в ячейки которого мы будем заносить эти самые нули и единицы. Т.к. у нас три плоскости по 9 светодиодов в каждой то логичным будет использовать массив 3х9.
Но перед тем как мы начнем писать программу необходимо вспомнить о том, что, во-первых, массивы могут хранить несколько элементов, но все они должны быть одного типа. Во-вторых, нумерация элементов массива начинается с нуля «0», а не с единицы. В-третьих, при объявлении массива с заданным количеством элементов указывается количество его ячеек, а не номер последней ячейки.
Синтаксис объявления массива будет таким:
Тип_данных имя_массива [количество_элементов];
Например,
unsigned char m_cub [3] [9]; //массив данных для кубика
Чтобы передать массив в подпрограмму необходимо проследить чтобы реципиент имел одинаковую структуру с донором.
//Объявление подпрограмм void show (unsigned char m_show [3][9]); //подпрограмма отображения
А синтаксис передачи всего массива в подпрограмму очень прост.
show (m_cub);
Ну вот теперь можно заняться написанием простой программы для вывода информации на наше кубическое индикаторное поле. Вот блок схема моей подпрограммы, которая отображает информацию из массива.
При входе в подпрограмму мы объявляем необходимые переменные, затем выключаем все светодиоды и закрываем транзисторы обнулив оба порта. После чего подпрограмма переходит в блок ротации отображаемых плоскостей. Приращение номера отображаемой плоскости, проверка номера на максимальное значение и выставление нулевого значения в случае выхода за пределы. Затем программа переходит к блоку выведения информации из массива для отображения. Запускается цикл для пересчета всех ячеек выбранной плоскости (от 0 до 8) и т.к. у нас девятый светодиод подключен к другому порту, нежели первые 8, то нам необходимо контролировать счетчик светодиодов и обработать девятый светодиод отдельно. Проверка заключается в том, что если в проверяемой ячейки массива не ноль, то в нужный разряд порта мы записываем единицу, а если в ячейки ноль, то переходим к следующей итерации.
if (m_show_3_9[c_plane][c_leds]){ if (c_leds < (MAX_LED-1)) PORTD |= (ON<<c_leds); else PORTB |= (ON<<LAST_LED); };
Девятый светодиод проверяется так же с той лишь разницей, что результат проверки записывается в нулевой разряд другого порта. После этого происходит включение выбранной плоскости для отображения. Вот и вся подпрограмма. Для ее проверки в основной цикл нужно записать строку, в которой какой-нибудь ячейки массива присваивается единица и массив передается для отображения.
Например:
m_cub [2][5] = 1; show (m_cub);
После прошивки, если все подключения были сделаны правильно, у вас должен загореться только один светодиод на одной из плоскостей.
Если я криво объяснил или у вас почему-то не получается, программу можно посмотреть в прилагаемых файлах. Но я всё-таки надеюсь на то, что вы всё сделаете сами как надо и получили кайф от проделанной работы.
После того как мы написали подпрограмму вывода информации на «объемный индикатор», нам необходимо научиться «жонглировать» единицами в массиве, чтобы получать интересные эффекты. Для этого мы должны в основном цикле написать программу, которая в процессе работы будет менять данные нашего массива.
На мой взгляд простейшим световым эффектом можно считать синхронно бегающие по кругу огоньки.
Программа действительно не сложная и, на мой взгляд, проста в понимании. Вот блок схема программы.
Все как обычно. Объявляем переменные, инициализируем порты «D» «B» как выходные. Затем войдя в основной цикл проверяем задержку и если она обнулена, то создаем вложенный цикл и полностью очищаем массив. После чего увеличиваем переменную положения светодиода на единицу и проверяем на максимальное значение. Т.к. для «бега по кругу» мы не задействуем девятый светодиод, то крайним будет светодиод под номером восемь, данные которого лежат в седьмой ячейке. После чего записываем единицы в новые ячейки. Конечно для записи можно организовать цикл, но я решил не париться и просто записал три почти одинаковых строчки. После того как новые данные записаны в массив выставляется максимальная задержка и весь массив передается подпрограмме индикации show (m_cub);. Затем цикл повторяется.
Вот вроде ничего сложного. Я надеюсь, что все программы вы напишите сами.
В качестве домашнего задания к этому уроку прошу модифицировать программу, которая позволяла бы светодиодам каждого уровня двигаться не зависимо друг от друга. Хотя бы вот так.
Или сделать мерцающие звезды. Вот так.
Или капающие с «потолка» капли.
Или сделать программу для вывода еще каких-нибудь причудливых узоров. Да. Необходимо сказать о том, что для программы «мерцающие звезды» и «капли» я использовал процедуру генератора «случайных» чисел, которая имеется в стандартной библиотеке. Для этого необходимо подключить файл stdlib.h. А чтобы это сделать необходимо вспомнить шестой урок и почитать: М.Б. Лебедева «CodeVisionAVR пособие для начинающих» 2008г. Страницы 266…268.
Для правильной организации работы генератора случайных чисел надо будет поискать публикации по этому поводу в интернете. Там они есть.
Ну а если после прочтения книги что-то будет не понятно, то к следящему уроку я прикреплю файлы со всеми программками, работу которых я продемонстрировал.
Ну вот. Мы закончили с изучением основ языка «Си» для МК. В последующих уроках я собираюсь рассмотреть имеющиеся на борту микроконтроллера разные периферийные устройства, а также работу с прерываниями.
На сон, грядущий необходимо почитать о тактировании МК, режимах работы и возможностях сброса контроллера в разных ситуациях: Евставфьев А.В. «Микроконтроллеры AVR семейства Tiny и Mega фирмы Atmel» 2008г. Страницы 200…229. Ю.А. Шпак «Программирование на языке С для AVR и PIC микроконтроллеров» 2006. Страницы 35…37.
Т.к. у Евстифеева описывается все семейство «Mega», то вам для изучения необходимо выбирать из текста только описание, относящееся к микроконтроллеру «Mega-8».
На следующем занятии мы просто изменим тактовую частоту нашего МК с 1 МГц на 8 МГц и проконтролируем наше изменение по морганию светодиода. Для этого понадобится один светодиод и резистор на 300 Ом.
А на сегодня всё. Удачи.
03.01.19
Если вдруг найдете в статье неточности или заблуждения. Напишите мне об этом. Я подправлю.
Приложение: Схема и проект CV_AVR.