ВНИМАНИЕ
|
217
|
11011001
|
АДРЕС
|
57
|
00111001
|
ГОТОВ
|
237
|
11101101
|
ЗАНЯТ
|
253
|
11111101
|
КОНЕЦ_ПЕРЕДАЧИ
|
114
|
01110000
|
КОНЕЦ_ПРИЕМА
|
174
|
10101110
|
ПОВТОРИТЬ_ПЕРЕДАЧУ
|
154
|
10100100
|
Схема микроконтроллера.
Для программирования необходимой логики работы мы будем
использовать 3 из 8 выводов порта А и все 8 выводов порта B
Описание
работы порта А
На вывод 0 поступает сигнал синхронизации С1
На вывод 1 поступает сигнал синхронизации С2
Вывод 2 используется для посылки и приёма Арбитру управляющих
сигналов ("Внимание", "Готов" ит.д.), а также для приёма
информационного сообщения.
Выводы 3-7 не используются и поэтому не показаны на схеме
Описание
работы порта B
8 выводов порта B используются для параллельной передачи и приёма
Абоненту управляющих сигналов ("Ошибка передачи", "Конец
работы" ит.д.), а также для пересылки информационного сообщения, которое
идёт от Арбитра
порт линия связь схема
В качестве программируемого микроконтроллера возьмём ATmega169. Выбор обусловлен тем, что данное устройство поддерживает
необходимые для выполнения курсового проекта характеристики, хотя и является
избыточным.
Работу программы будем проверять в эмуляторе AVR Studio 4.13.528
Компилировать программу будем в WinAVR 20071221
AVR Studio - интегрированная среда проектирования программ для микроконтроллеров,
которую можно свободно скачать с сайта производителя www.atmel.com
<http://www.atmel.com>
WinAVR - программный пакет, содержащий в себе интересующий нас
компилятор GNU GCC для C. WinAVR можно свободно скачать с сайта
разработчиков <http://sourceforge.net/projects/winavr/>
Для разбора задания установите сначала WinAVR, а потом AVR Studio. Порядок установки важен для того, чтобы AVR Studio
установил в настройках проекта в качестве компилятора компилятор GNU GCC, входящий в состав WinAVR. Обе программы
установите с параметрами по умолчанию.
Создание
проекта в AVR Studio
Для создания проекта в AVR Studio необходимо зайти в меню Project - > Project Wizard - > New Project
В окне Project type выбираем AVR GCC потому что будем писать
программу на языке C
В окне Project name вписываем произвольно
название проекта, допустим mk
В окне Initial file вписываем main. c. Это будет главный файл
проекта, где будет находиться функция main.
Жмём Next
В окне Debug
platform выбираем AVR Simulator. В
окне Device выбираем ATmega169
Жмём Finish
После создания проекта в AVR Studio необходимо зайти в меню Project - >
Configuration Options - > General и выставить значение Optimization
= - O0. Это отключит оптимизацию кода, которая нам не нужна при отладке
программы.
Окно main. c содержит исходный текст
программы (предварительно скопируйте код в это окно).
В окне I/O View можно наблюдать, а также
изменять состояние портов А и B.
Например сигнал С1 эмулируется в данной работе установкой в
единицу PINA bit 0., а сигнал С2 эмулируется установкой в единицу PINA bit 1.
Значение PINA bit 2 эмулирует значения, которые нам приходят по
информационной линии
В окне Watch можно следить за значениями переменных.
Список
использованной литературы
1. Голубцов
М.С., Кириченкова А.В. Микроконтроллеры AVR: от простого к сложному. - М.:
"Солон-Пресс", 2004.
2. Шпак
Ю.А. Программирование на языке C для AVR и PIC микроконтроллеров. - М.:
"МК-Пресс", 2006.
. Фрунзе
А.В. Микроконтроллеры? Это же просто! - K.: "Додэка XXI", 2007.
. Белов
А.В. Самоучитель разработчика устройств на микроконтроллерах AVR. - М.:
"Наука и техника", 2008.
. Хартов
В.Я. Микроконтроллеры AVR. Практикум для начинающих. - М.: МГТУ им. Н.Э.
Баумана, 2007.
. Джон
Мортон Микроконтроллеры AVR. Вводный курс AVR: An Introductory Course. - К.: "Додэка XXI", 2006.
. Евстифеев
А.В. Микроконтроллеры AVR семейства Tiny. Руководство пользователя. - К.:
Додэка XXI, 2007
Приложение
/*
Подключение заголовочного файла io. h, который в свою очередь
подключит iom169. h. h - заголовочный файл, который ставит в соответствие
константам PORTA и PORTB реальные адреса выводов конкретного контроллера (в
нашем случае ATmega169)
*/
#include <avr/io. h>
// Подключение заголовочного файла, который позволяет
объявлять булевские переменные
#include <stdbool. h>
// Определение пользовательского типа данных byteunsigned
char byte;
// Константы, определённые для обращения к выводам порта А
#define C1 (PINA & 0x01) /* 0-вой вывод порта А, на
который приходит сигнал С1 */
#define C2 (PINA & 0x02) /* 1-вой вывод порта А, на
который приходит сигнал С2 */
#define DATAIN ( (PINA & 0x04) >> 2) /* 2-вой вывод
порта А, на который приходит информация. Чтение информации из порта */
#define DATAOUT (x) PORTA = (PORTA & ~ (0x04)) | (x
<< 2) /* 2-вой вывод порта А, на который приходит информация. Ввод
информации в порт */
// Символы сигналов связи варианта задания на курсовой проект
#4
#define ATTENTION 217 // Внимание
#define ADDRESS 57 // Адрес
#define READY 237 // Готов
#define BUSY 253 // Занят
#define END_OF_TRANSFER_SEQUENCE 114 // Конец передачи
#define END_OF_RECEIVE 174 // Конец приёма
#define REPEAT_TRANSFER 154 // Повторить передачу
// Символы сигналов связи от Абонента
#define END_OF_WORK 1 // Конец работы
#define TRANSFER_ERROR 2 // Ошибка передачи
// Глобальные переменные
byte frameFromArbiter = 0;abonentStateReceived =
false;frameCameFromArbiter = false;AddressCameFromArbiter =
false;frameToAbonentWasSent = false;requestToAbonentWasSent = false;stateOfAbonentWasSentToArbiter
= false;DataMessageRefered = false;
int abonentState = 0;
// Получаем побитово байт от Арбитра
void ReceiveFrameFromArbiter ()
{int C2Count = 0;bool C1Came = false;bool C2Out =
true;
if (C1) // Если пришёл сигнал С1,{Came = true; // запоминаем
что сигнал С1 приходил
}(C1Came) // Если сигнал С1 приходил
{(C2 && C2Out) // Если сигнал С2 пришёл,
{= (frameFromArbiter & ~ (1 << C2Count)) | (DATAIN
<< C2Count); // считываем очередной бит с информационной линии
/*
(1 << C2Count) даст нам байт с единицой, установленной
на том бите, который мы должны установить
~ (1 << C2Count) инвертирование даст нам байт с нулём,
установленным на том бите, который мы должны установить
(frameFromArbiter & ~ (1 << C2Count)) даст нам
исходный frameFromArbiter с нулём, установленным на том бите, который мы должны
установить<< C2Count) даст нам бит со значением пришедшим по
информационной линии, который установлен в байте на том бите, который мы должны
установить
Итоговое поразрядное ИЛИ даст нам исходный frameFromArbiter
со значением пришедшим по информационной линии, которое установится в
frameFromArbiter на номере бита, равном номеру сигнала С2
*/Count++; // Считаем номер пришёдшего сигнала С2Out = false;
// Запоминаем, что С2 пришёл, но ещё не уходил
}(C2Count == 8) // Если пришло 8 сигналов С2, значит мы
приняли целиком байт
{Count = 0; // Обнуляем количество сигналов С2Came = false;
// Запоминаем что пришёдший после С1 байт уже обработан, ждём следующий С1
C2Out = true;= true; // Запоминаем что байт пришёл
}(! C2) { // Если сигнал С2 ушёлOut = true; // Запоминаем,
что сигнал С2 ушёл
}
}
}
// Ждём поступления от Арбитра адреса
микроконтроллераWaitAddressFromArbiter ()
{= 0x00; // Указываем микроконтроллеру настроить все выводы
на приём информации
bool attentionCame = false;(); // Получить байт от Арбитра(frameCameFromArbiter)
// Если байт от Арбитра пришёл
{(attentionCame) // Если сигнал Внимание уже приходил
{(frameFromArbiter == ADDRESS) // И пришедший байт равен
адресу микроконтроллера
{= true; // Запоминаем, что адрес пришёл
}= false;
}(frameFromArbiter == ATTENTION) // Если пришёл байт равный
сигналу Внимание
{= true; // Запоминаем, что приходил сигнал Внимание
}= false; // Записываем, что мы уже обработали пришедший байт
}
}
// Посылаем параллельно байт АбонентуSendFrameToAbonent (byte
sendFrame)
{bool C1Came = false;(C1) // Если пришёл сигнал С1,{Came = true; //
запоминаем что сигнал С1 приходил
}(C1Came) // Если сигнал С1 приходил
{= sendFrame; // Выдаём на выводы порта B байт
}(! C1 && C1Came) // Если сигнал С1 ушёл и приходил
{= true; // Запоминаем что байт был отосланCame = false;
}
}
// Посылаем Абоненту запрос о его
состоянииSendToAbonentRequestAboutAbonentState ()
{= 0xFF; // Указываем микроконтроллеру настроить все выводы
порта B на вывод информации(READY); // Посылаем байт ГОТОВ
Абоненту(frameToAbonentWasSent) // Если байт был послан
{= true; // Запоминаем, что запрос Абоненту был послан
}
}
// Получаем от Абонента его
состояниеReceiveFromAbonentAbonentState ()
static bool C1Came = false;(C1) // Если пришёл сигнал С1,{Came = true; //
запоминаем что сигнал С1 приходил
}(C1Came) // Если сигнал С1 приходил
{= PINA; // Выдаём на выводы порта B байт
}(! C1 && C1Came) // Если сигнал С1 ушёл и приходил
{= true; // Запоминаем что получили состояние АбонентаCame =
false;
}
}
// Посылаем Арбитру состояние Абонента
void SendToArbiterAbonentState (byte frame)
{= 0x04;int C2Count = 0;bool C1Came = false;bool
C2Out = true;(C1) // Если пришёл сигнал С1,{Came = true; //
запоминаем что сигнал С1 приходил
}(C1Came) // Если сигнал С1 приходил
{(C2 && C2Out) // Если сигнал С2 пришёл,
{( (frame & (1 << C2Count)) >> C2Count); //
Записываем очередной бит на информационную линиюCount++; // Считаем номер
пришёдшего сигнала С2Out = false; // Запоминаем, что С2 пришёл, но ещё не
уходил
}(C2Count == 8)
{Count = 0; // Обнуляем количество сигналов С2Came = false;
// Запоминаем что пришёдший после С1 байт уже обработан, ждём следующий С1Out =
true;= true; // Запоминаем, что состояние Абонента было отослано Арбитру
}(! C2) { // Если сигнал С2 ушёлOut = true; // Запоминаем,
что сигнал С2 ушёл
}
}
}
// Получаем информационное сообщение от Арбитра и пересылаем
АбонентуReceiveDataMessageFromArbiterAndReferToAbonent ()
{= 0x00; // Указываем микроконтроллеру настроить все выводы
на приём информации(); // Получить байт от Арбитра(frameCameFromArbiter) //
Если байт от АРбитра пришёл
{(frameFromArbiter); // Посылаем байт Абоненту= false; //
Запоминаем, что мы обработали байт, пришедший от Арбитра(frameFromArbiter ==
END_OF_TRANSFER_SEQUENCE) // Если пришёдший байт совпадает с символом КОНЕЦ
ПЕРЕДАЧИ
{= true; // Запоминаем что информационное сообщение переслали
}
}
}main (void)
{(1) // Запускаем бесконечный цикл
{(! AddressCameFromArbiter) // Если адрес МК ещё не пришёл от
Арбитра,
{(); // ждём
}(AddressCameFromArbiter) // Если от Арбитра пришёл адрес МК
{(); // посылаем Абоненту запрос о его
состоянии(requestToAbonentWasSent) // Если запрос о состоянии Абонента был
послан
{(); // получаем ответ
}(abonentStateReceived) // Если получили состояние Абонента,
{(abonentState == END_OF_WORK) // и состояние равно КОНЕЦ
РАБОТЫ,
{(READY); // посылаем Арбитру сигнал
ГОТОВ(stateOfAbonentWasSentToArbiter) // Если состояние Абонента отослалось
Арбитру
{(); // Начинаем принимать информационное сообщение от
Арбитра и пересылать его Абоненту(DataMessageRefered) // Если информационное
сообщение было отослано
{(); // Посылаем Абоненту запрос о его
состоянии(requestToAbonentWasSent) // Если запрос о состоянии Абонента был
послан,
{(); // ждём ответ
}(abonentStateReceived) // Если получили состояние Абонента,
{(abonentState == TRANSFER_ERROR) // Если состояние Абонента
равно ОШИБКА ПЕРЕДАЧИ
{SendToArbiterAbonentState (REPEAT_TRANSFER); // Посылаем
Арбитру сигнал ПОВТОРИТЬ ПЕРЕДАЧУ
}// Если ошибки не произошло
{
SendToArbiterAbonentState (END_OF_RECEIVE); // Посылаем Арбитру сигнал КОНЕЦ ПРИЁМА
}
}
}
}
}// Если состояние не равно КОНЕЦ РАБОТЫ
{(BUSY); // Посылаем Арбитру, что Абонент ЗАНЯТ
}
}
}
}
}