лабы. Laboratornye_raboty_1-5 Микропроцессорные системы. Методические указания к лабораторным работам 15 по дисциплине "Микропроцессорные системы" для студентов направления подготовкиспециальности
Скачать 1.97 Mb.
|
DDRx – регистр направления работы - вход или выход, х - означает букву А. В. С, D. Е... порта, по числу портов в конкретном МК. PINx – регистр содержит значения физических (т.е. реальных, тех, которые мы получим измерив вольтметром и преобразовав в 1 или 0) уровней сигнала на соответствующих ножках МК. PORTx – регистр в который записываются желаемые значения «1» или «0» и которые необходимо получить на соответствующих ножках МК при назначении их выходом. Т.е. если соответствующий бит в регистре DDRx установлен (значит равен «1»). Если бит в регистре DDRx равен «1», а в такой же бит PORTx записана «1» то «ножка» МК будет «входом с подтяжкой» т.е. к ней подключен резистор примерно 40 кОм от питания МК На вкладке «Ports» мы видим еще три вкладки поменьше (см. рис. 10). По одной вкладке для каждого порта. Как уже говорилось выше, порт РА в данной схеме мы не применяем. На вкладке мы видим два столбца с параметрами. Столбец «Data direction» (Направление передачи данных) позволяет настроить каждую линию порта либо на ввод, либо на вывод. По умолчанию каждый параметр имеет значение «In» (вход). Поменяем для каждого разряда это значение на «Out» (Выход). . Рис. 10 – Настройка портов PB и PD Для того, чтобы поменять значение разряда, достаточно щелкнуть по полю с надписью «In» один раз мышью, и параметр сменится на «Ош». Повторный щелчок заставит вернуться к «In». Каждое поде столбца «Data direction» определяет, какое значение будет присвоено соответствующему разряду регистра DDRB в нашей будущей программе. Второй столбец на той же вкладке называется «Pullup/Ontput Value» (Включение нагрузки/Выходное значение). Этот столбец определяет, какое значение будет присвоено каждому из разрядов регистра PORTB. В нашем случае порт РВ работает на вывод. Поэтому содержимое регистра PORTB определяет выходное значение всех разрядов порта. По умолчанию все они имеют значение «1». Но по условиям нашей задачи они должны быть равны единице (при старте программы светодиод должен быть отключен). Поэтому изменим все нули на единицы. Для этого также достаточно простого щелчка мыши. В результате всех операций вкладка «Port В» будет выглядеть так. как показано на рис. 10. Перейдем к настройке порта D. Для этого выберем вкладку «Potr D». На вкладке мы увидим такие же органы управления, как на вкладке «Port В» (см. рис. 10). По условиям задачи порт PD микроконтроллера должен работать на ввод. Поэтому состояние элементов первого столбца мы не меняем. Однако не забывайте, что нам нужно включить внутренние нагрузочные резисторы для каждого из входов. Для этого изменим значения элементов второго столбца. Так как порт PD работает в режиме ввода, элементы в столбце «Pullup / Output Value» принимают значение «Т» или «Р». «Т» (Terminate) означает отсутствие внутренней нагрузки, а «Р» (Pull-up) означает: нагрузка включена. Включим нагрузку для каждого разряда порта PD, изменив при помощи мыши значение поля с «Т» на «Р». В результате элементы управления будут выглядеть так. как показано на рис. 10. Для данной простейшей программы настройки можно считать оконченными. Остальные системы микроконтроллера нам пока не нужны. Оставим их настройки без изменений. Рис. 11 – Вкладка информации о проекте Воспользуемся еще одним полезным свойством мастера программ. Откроем вкладку «Project Information» (см. рис. 11). В поле «Project Name» вы можете занести название вашего проекта. Поле «Version» предназначено для номера версии. В поле «Date» помещают дату разработки программы. В полях «Author» и «Company» помещается, соответственно, имя автора и название компании. В поле «Comments:» можно поместить любые необходимые комментарии. Вся эта информация будет автоматически помещена в заголовок будущей программы. Рис. 12 – Запуск процесса генерации программы После того, как все параметры выставлены, приступаем непосредственно к процессу генерации программы. Для этого выбираем в меню «File» нашего мастера пункт «Generate, Save and Exit», как это показано на рис. 12. Процесс генерации начнется с запроса имени файла будущей программы. Для этого откроется стандартный диалог сохранения файла, в котором вы сначала должны выбрать каталог, а затем указать имя файла программы. Что касается каталога, то вам нужно самостоятельно выбрать каталог, где будет размещен весь ваш проект. Рекомендуется для каждого проекта создавать свой отдельный каталог. В нашем случае самое простое – назвать каталог именем «Prog1». А вернее, выбрать что-то вроде «C:\AVR\C\Prog1\». Если каталог ещё не создан, то вы можете создать его прямо в диалоге создания файла. Файлу рекомендую присвоить то же самое имя: «Prog1». Однако вы можете выбрать имя по своему усмотрению. Для завершения процесса создания файла нажмите кнопку «Сохранить». В результате на ваш жесткий диск запишется файл «Prog1.с», в который будет помешен созданный построителем текст заготовки вашей программы. Расширение «.с» набирать не нужно. Оно присваивается автоматически. Это стандартное расширение для программ на языке C++. Однако процесс генерации проекта на этом не заканчивается. Сразу после того, как файл программы будет записан, откроется новый диалог, который запросит имя для файла проекта. Файл проекта предназначен для хранения параметров конкретного проекта. Кроме типа используемой микросхемы и частоты задающего генератора, файл проекта используется для хранения вспомогательной информации, такой как наличие и расположение точек останова, закладок и т. д. Подробнее о закладках и точках останова мы узнаем, когда будем изучать работу отладчика. В качестве имени файла проекта удобнее всего использовать то же самое имя. что и для текста программы. То есть «Prog1». Файлу проекта автоматически присваивается расширение «.prj». Когда файл проекта будет записан, диалог записи файла откроется в третий раз. Теперь нам предложат выбрать имя для файла данных построителя. В этот файл будут записаны текущие значения всех параметров, мастера. То есть значения всех управляющих элементов со всех его вкладок. И те. которые мы изменили в процессе настройки, и те. которые остались без изменений (по умолчанию). Эти данные могут понадобиться, если потребуется заново пересоздать проект. Используя файл данных построителя, вы можете в любой момент восстановить значения всех его элементов. немного подкорректировать их и создать новый проект. Файлу данных построителя присвоим то же самое имя. что обоим предыдущим («Prog1»). Новый файл получит расширение «.cwp» (Code Wizard Project). После того, как и этот файл будет записан, процесс генерации проекта завершается. На экране появляются два новых окна. В одном окне открывается содержимое файла «Prog1.с». Второе окно – это файл комментариев. Сюда вы можете записать, а затем сохранить на диске любые замечания по вашей программе. В дальнейшем они всегда будут у вас перед глазами. Посмотрим теперь, что же сформировал наш построитель. Текст программы, полученной описанным выше образом, дополненный русскоязычными комментариями, приведен в листинге 1. Листинг 1 #include // Declare your global variables here void main (void) { // declare your local variables here CLKPR=0x80; CLKPR=0x00; PORTA=0x00; DDRA=0x00; PORTB=0xFF; DDRB=0xFF; PORTD=0x7F; DDRD=0x00; TCCR0A=0x00; TCCR0B=0x00; TCNT0=0x00; OCR0A=0x00; OCR0B=0x00; TCCR1A=0x00; TCCR1B=0x00; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; GIMSK=0x00; MCUCR=0x00; TIMSK=0x00; ACSR=0x80; while (1) { // Place your code here PORTB=PIND; }; } ЛАБОРАТОРНАЯ РАБОТА №2 Микропроцессорное устройство «Бегущие огни» с использованием функции прерываний по таймеру Цель. Разработать алгоритм работы устройства, написать программу для МК предложенного устройства на C++ в программной среде CodeVisionAVR и получить файл .hex («прошивку») готовый для загрузки в МК. Проверить работу программы на эмуляторе Proteus 7.5. Задача. Устройство должно обеспечивать «движение» огня в двух разных направлениях с использованием прерываний по таймеру. Переключение направления «движения» должно осуществляться при помощи переключателя. Постановка задачи Техническое задание для предлагаемой задачи выглядит следующим образом: Разработать устройство на микроконтроллере ATmega8 которое будет отображать, в двоичном виде, НЕ горящими светодиодами 8-ми битное число начиная с 0 и с постоянным увеличением на 1. Устройство должно питаться постоянным стабилизированным напряжением от 4 до 5.5 вольт. Тактирование МК осуществляется от кварцевого резонатора с частотой 4 МГц. Всего должно быть подключено 8 светодиодов от ножек порта А через токоограничительные резисторы к питанию МК. Переключение светодиодов должно производится с паузами в 200 мс. Выполнение работы В настоящей работе мы используем таймер для вызова прерывания. На практике чаще всего в подобных случаях применяют прерывания по таймеру. Это позволяет более точно формировать интервалы времени, но главное – позволяет разгрузить центральный процессор. Пока таймер формирует задержку, программа может выполнять любые другие действия. В результате программу бегущих огней можно легко совместить, например, с программой генерации звуков. Составим схему (Рис. 1), которая физически может выполнить то, что написано в тех. задании: Кварц на 4 МГц подключаем к ножкам МК XTAL1 и XTAL2 и эти ножки заземляем конденсаторами по 22 пФ на ножку GND. Делаем цепь сброса МК - RESET. Для этого ножку 1 заземляем конденсатором 0.1 мкФ на ножку GND номер 10. От ножки 1 ставим диод 4148 (или любой маломощный маленький кремниевый, например кд522) черточкой к питанию МК - ножка 20 VCC. Параллельно диоду ставим резистор 10 кОм. Питание МК подается так: 0 на ножку 10 и +5 вольт на ножку 20. Поставим блокировочный конденсатор 0.1 мкФ между ножками 10 и 20. 8 светодиодов подключим черточками к ножкам МК с 12 до 19. К другим выводам светодиодов подсоединим резисторы от 470 до 750 Ом – их тоже будет 8 – вторые выводы резисторов подсоединяются к питанию МК – ножка 10. Рис. 1 – Схема «Бегущие огни» Разработка алгоритма Поставленная выше задача потребует полной переделки всей программы листинга 1. В данном конкретном случае удобнее всего использовать режим совпадения. Точнее, его подрежим «сброс при совпадении». В этом режиме таймер сам периодически вырабатывает запросы на прерывание с заранее заданным периодом. Все функции управления «движением огней» выполняет процедура обработки прерывания. При каждом вызове прерывания процедура производит сдвиг «огней» на один шаг в нужном направлении. Для того, чтобы обеспечить нужную скорость движения «огней» мы должны рас-читать коэффициенты деления. Для начала необходимо включить предварительный делитель и выбрать для него коэффициент деления 1/1024. Второй коэффициент деления (780) мы помещаем в специальный системный регистр – регистр совпадения. Сравнение содержимого счетного регистра с содержимым регистра совпадения будет происходить на аппаратном уровне. В режиме «сброс при совпадении» таймер работает следующим образом. Сразу после запуска значение счетного регистра начнет увеличиваться. Когда это значение окажется равным значению регистра совпадения, таймер автоматически сбросится и продолжит работу с нуля. В момент сброса таймера формируется запрос на прерывание. Для имитации бегущих огней мы будем использовать операции сдвига. При этом нам также понадобится специальный рабочий регистр. То есть один из регистров общего назначения, в котором будет храниться текущее состояние наших «огней». В начале программы в рабочий регистр необходимо записать исходное значение. То есть число, один из разрядов которого равен единице, а остальные – нулю. В результате операций сдвига эта единица будет перемешаться вправо или влево, создавая эффект бегущего огня. Проверка состояния кнопки и сдвиг на один шаг будет производиться при каждом вызове процедуры обработки прерывания. Исходя из вышесказанного, алгоритм работы программы состоит из двух независимых алгоритмов. Во-первых, это алгоритм основной программы, а во-вторых, алгоритм процедуры обработки прерывания. Рассмотрим их по порядку. Алгоритм основной программы: старт программы; делать ножки МК, к которым подключены светодиоды, выходами; настроить таймер и систему прерываний (запустить таймер МК со скоростью счета обеспечивающей его переполнение каждые 200 мс); записать в рабочий регистр исходное значение; разрешить работу таймера и разрешить прерывания; ждать переполнения таймера; очистить признак переполнения таймера; перейти к пункту 4. Так как все операции, связанные с движением огней, выполняет процедура обработки прерываний, в основном цикле программы нам ничего делать не нужно. Для простоты оставим основной цикл пустым. Алгоритм процедуры обработки прерывания: 1. Проверить состояние переключателя режимов. 2. Если контакты переключателя разомкнуты, произвести сдвиг всех разрядов рабочего регистра на один разряд вправо. Если в результате этого сдвига единичный бит выйдет за пределы байта, создать новый единичный бит в крайней левой позиции. 3. Если контакты переключателя замкнуты, произвести сдвиг всех разрядов рабочего регистра на один разряд влево. Если в результате этого сдвига единичный бит выйдет за пределы байта, создать новый единичный бит в крайней правой позиции. 4. Вывести содержимое рабочего регистра в порт РВ. предварительно проинвертировав его. 5. Закончить процедуру обработки прерывания. Программа на языке C++ Для нашей новой задачи потребуются довольно значительные изменения программы. При разработке программы средствами системы CodeVisionAVR в подобной ситуации целесообразнее воспользоваться мастером, при помощи которого удобно создать новую заготовку программы. Д ля создания новой заготовки программы удобно восстановить настройки из созданного ранее примера, подкорректировать их в соответствии с новыми требованиями и записать под новым именем. Для этого зайдем в программу CodeVisionAVR и запустим мастер. Для запуска мастера достаточно нажать на панели инструментов кнопку После запуска мастера все его управляющие элементы будут находиться в исходном состоянии. То есть иметь значения по умолчанию. Теперь нам нужно восстановить настройки из первого примера. Для этого в меню «File» мастера выберем пункт «Open». Появится стандартное окно открытия файла. Найдите на вашем диске файл Prog1.cwp и откройте его. После того, как вы его откроете, все органы управления во всех вкладках мастера примут те значения, какие они имели при создании программы Prog1. Теперь нужно сохранить этот пример с другим именем. Для этого при помощи пункта меню «File/Save As» сделайте копию только что загруженного файла. Копию поместите в новую директорию с именем Prog2. В этой директории будет храниться наш новый проект. Теперь можно приступать к изменениям настроек под новые требования. Исходя из технического задания, нам придется изменить настройки таймера. Для этого сначала откройте вкладку «Timers». На этой вкладке вы увидите еще три вкладки поменьше (см. Рис. 2). Эти вкладки предназначены для настройки двух системных таймеров (Timer0 и Timer1), а также охранного таймера (Watchdog). Открываем вкладку «Timer1», как показано на Рис. 3. При помощи расположенных там элементов управления выставляем следующие настройки: Поле «Clock Source» (Источник Тактового Сигнала) оставляем в положении «System Сlock» (Тактовый сигнал от системного генератора). В поле «Сlоck Value» (Значение тактовой частоты) выбираем значение 3.906 кГц. На самом деле мы выбираем коэффициент деления предварительного делителя. Но для удобства программиста показаны получаемые при этом частоты сигнала. Значения этих частот вычисляются исходя из выбранной частоты тактового генератора (см. вкладку «Chip»). Как вы помните, тактовая частота в нашем случае равна 4 МГц. В поле «Mode» выбираем режим работы таймера. В нашем случае мы должны выбрать режим «СТС top=OCR1A» (режим сброса при совпадении с регистром OCR1A). Два поля «Out. А» и «Out. В» оставляем без изменений. При помощи этих полей можно включить и настроить параметры вывода сигнала совпадения на внешние контакты микроконтроллера. В данном случае нам это не нужно. Поле «Input Capt.» (Вход Захвата) используется при работе в режиме захвата. Мы не используем режим захвата, поэтому и это поле тоже оставим без изменения. Поле «Interrupt On» (Прерывание От) нам нужно изменить. Это поле предназначено для разрешения или запрета различных видов прерываний от таймера. В правой части поля имеются две маленькие кнопочки, при помощи которых вы можете листать его содержимое. В процессе перелистывания в окошечке появляются названия видов прерываний. Слева от названия каждого вида прерывания имеется поле выбора («Check Box»), при помощи которого вы можете включить либо выключить данное прерывание. Путем перелистывания найдите прерывание, которое называется «Compare А Mach» (при совпадении с А). Поставьте «птичку» в соответствующем поле «Check Box». Теперь нужное прерывание будет включено. поля «Value» и «Inp. Capture» оставим без изменений. Эти поля предназначены для задания начальных значений счетного регистра и содержимого регистра захвата. два поля под общим названием «Comp.» позволяют выставить значения, записываемые в регистры совпадения А и В. Мы будем использовать регистр А. Запишем в поле «А:» значение нужного нам коэффициента деления (30C). В данном случае допускается только шестнадцатеричный формат. Рис. 2 – Настройка таймера В результате всех этих манипуляций окно настройки таймера должно выглядеть так, как показано на Рис. 2. Сохраните новое значение параметров при помощи меню «File/Save» мастера. Далее необходимо сформировать новый проект. После того, как проект сформирован, приступаем к созданию новой программы. Возможный вариант такой программы приведен в листинге 2. В новой программе в основном использованы уже знакомые нам операторы. Из новых операторов появился лишь один: #asm(). Это специальная системная функция, позволяющая в программе на C++ выполнять команды Ассемблера. Параметр функции – это строковая переменная или строковая константа, значение которой представляет собой текст команды на Ассемблере. Подобная функция добавляет программе значительную гибкость. В строке 41 программы (Листинг 1) при помощи функции #asm () выполняется ассемблерная команда разрешения прерывания sei. Команды такого уровня не имеют аналогов в традиционном синтаксисе языка C++. Да и нецелесообразно выдумывать новые команды, когда удобнее просто выполнить команду Ассемблера. |