Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Микропроцессорные системы. Применение микроконтроллеров семейства AVR для управления внешними устройствами
.pdf
51
Конструктор класса CycloBuf() создает класс, который не имеет
привязки к массиву байт.
Метод void CycloBuf::init (uint8_t* buffer, uint8_t size) осуществ-
ляет привязку экземпляра класса к массиву байт. Параметр buffer – указатель на массив байт; параметр size задает размер массива байт и цик-
лического буфера.
Метод void CycloBuf::clear(); очищает циклический буфер.
Метод bool CycloBuf::isEmpty(); проверяет, пуст ли циклический
буфер. Если буфер пуст, то возвращает значение true, если не пуст –
возвращает значение false.
Метод bool CycloBuf::putByte(uint8_t c); помещает байт c в цик-
лический буфер. Если буфер не полон, то байт помещается в него и метод возвращает значение true. Если байт нельзя поместить в буфер,
то метод возвращает значение false.
Метод bool CycloBuf::getByte(uint8_t& c); извлекает значение из
циклического буфера и помещает его в байт c. Если буфер не пуст,
то байт с извлекается из него и метод возвращает значение true. Если бу-
фер пуст, то метод возвращает значение false, а значение c не изменяется.
8.3. Универсальный асинхронный приемопередатчик UART
Универсальный асинхронный приемопередатчик используется для
обмена данными между микропроцессорными устройствами. Логически, протокол обмена UART полностью совпадает с протоколом интерфейса RS232. В модуле AVR Butterfly имеется преобразователь уровней,
позволяющий подключать UART к интерфейсу RS232, например, персо-
нального компьютера.
Термин «асинхронный» означает, что данные могут приниматься и
независимо друг от друга без отдельных сигналов синхронизации.
При программировании интерфейсов передачи данных, подобных
UART, возникает проблема взаимодействия драйвера и остальных программных модулей. Суть проблемы состоит в следующем: поскольку
UART – устройство относительно медленное, то передача массива информации побайтно с ожиданием ведет к непроизводительным потерям
времени на ожидание передачи байта. Например, при скорости обмена
UART 115200, за время передачи одного байта, процессор AVR на ча-
стоте 8 МГц успевает выполнить около 690 операций.
Выход из ситуации – использование буферов для приема и переда-
чи информации, совмещенное с генерацией прерываний от UART при
приеме или передаче каждого байта.

52
Наиболее удобно, в данном случае, использовать циклические буфера. Поскольку данный вид буферов может использоваться по-разному,
то реализация вынесена в отдельный модуль.
8.3.1. Аппаратные средства UART
С точки зрения программиста, UART микроконтроллера AVR
представляет собой несколько регистров управления – UCSRA, UCSRB,
UCSRC, PORTE, DDRE, UBRR и регистр данных UDR. Назначения
этих регистров были рассмотрены ранее.
8.3.2. Драйвер UART
Драйвер UART приведен в прил. Г (файлы cUSART.h и
cUSART.cpp ).
Все обращения к драйверу USART идут через метод
cUSART::instance().
Метод cUSART::instance().start() инициализирует аппаратную
часть UART и разрешает обработку прерываний от UART.
Метод cUSART::instance().setBaud ( uint16_t baud ) задает ско-
рость передачи данных в бит/сек. Стандартные скорости передачи дан-
ных по RS232 – 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200.
Метод uint8_t cUSART::instance().get(char* s, uint8_t size) полу-
чает не более size байт из приемного буфера и помещает их в буфер,
на который указывает s. Метод возвращает реально полученное число
байт. Если метод вернул 0, то приемный буфер пуст и данных нет.
Метод uint8_t cUSART::instance().putc(char c) помещает один
байт в буфер передачи и запускает передачу по UART, если она еще не
запущена. Метод возвращает 1, если символ помещен в буфер передачи,
или 0, если символ не передан (например, в буфере передачи нет места).
Метод uint8_t cUSART::instance().puts(const char* s) помещает
строку, размещенную по адресу s в памяти данных, в буфер передачи.
Метод возвращает помещенное в буфер передачи число байт.
Метод uint8_t cUSART::instance().putsF(const char* s) помещает
строку, размещенную по адресу s в памяти программ, в буфер переда-
чи. Метод возвращает помещенное в буфер передачи число байт.
Метод uint8_t cUSART::instance().put(const char* s, uint8_t size)
помещает массив size байт, размещенный по адресу s в памяти данных,
в буфер передачи. Метод возвращает помещенное в буфер передачи
число байт.

53
8.4. Дисплей
Микроконтроллер ATMega169 имеет встроенный контроллер
управления ЖКИ-дисплеем. В состав модуля AVR Butterfly входит
ЖКИ-дисплей, способный отображать шесть символов (рис. 20).
Рис. 20. Дисплей модуля AVR Butterfly
Каждый из символов дисплея состоит из четырнадцати сегментов.
Это позволяет отображать все символы латинского и кириллическо-
го алфавитов, цифры и спецсимволы. Кроме того, имеются два символа
«двоеточие», которые можно отображать между вторым и третьим,
а также между четвертым и пятым символами (нумерация символов –
слева направо, рис. 21).
Рис. 21. Структура символа ЖКИ-дисплея
Драйвер дисплея
Драйвер ЖКИ-дисплея приведен в прил. Д (файлы LCD_driver.h и
LCD_driver.cpp).
Драйвер имеет следующие функции:
установка уровня контраста изображения на дисплее;
вывод строки символов из памяти данных на дисплей;
вывод строки символов из памяти программ на дисплей;
функция прокрутки (скроллинга) строки на дисплее, если ее раз-
мер более 6 символов;
установка режима вывода разделительных символов «двоеточие».
Все обращения к драйверу USART идут через метод
cLCD::instance().

54
Метод void cLCD::instance().puts(const char *Data) осуществляет
вывод строки символов, размещенной в памяти данных по адресу s,
на дисплей. Максимальный размер строки задается константой
cLCD::Constant::TextBufferSize. Если строка длиннее, чем
cLCD::Constant::TextBufferSize, то лишние символы не выводятся.
Метод void cLCD::instance().putsF(const char *FlashData) осу-
ществляет вывод строки символов, размещенной в памяти программ
по адресу s, на дисплей. Максимальный размер строки задается константой cLCD::Constant::TextBufferSize. Если строка длиннее, чем
cLCD::Constant::TextBufferSize, то лишние символы не выводятся.
Метод void cLCD::instance().showColons(const bool ColonsOn)
определяет вывод символов «двоеточие» на дисплей. Если
ColonsOn=true, то символы «двоеточие» выводятся на дисплей. Если
ColonsOn=false, то символы «двоеточие» не выводятся на дисплей.
Метод void cLCD::instance().setContrast(uint8_t level) устанавли-
вает уровень контраста изображения на дисплее. Значение level может
принимать значение от 0 (низкий контраст) до 15 (высокий контраст).
8.5. Джойстик
Как было указано ранее, джойстик служит для ввода информации
пользователем и представляет собой с точки зрения схемотехники пять
переключателей типа «сухой контакт», подключенных к 5 линиям ввода
микроконтроллера ATMega169. Соответствие положения джойстика и
линий ввода микроконтроллера приведено в табл. 1.
Драйвер джойстика
Драйвер джойстика приведен в прил. Е (файлы JOY_driver.h и
JOY_driver.cpp).
Драйвер имеет следующие функции:
считывание линий джойстика и определение того, какая из линий
активна (т. е. в каком положении находится джойстик и его центральная кнопка);
запоминание последнего активного положения джойстика;
задержка для устранения дребезга контактов, для организации ко-
торой используется программный таймер.
Все обращения к драйверу джойстика идут через метод
cJOYSTICK::instance().
Метод cJOYSTICK::instance().start() инициализирует аппарат-
ную часть микроконтроллера AVR (линии портов, прерывания), создает

55
программный таймер для устранения дребезга контактов и разрешает
опрос джойстика.
Метод uint8_t cJOYSTICK::instance().getLastKey() позволяет за-
просить последнее состояние джойстика.
Состояния джойстика определены константами:
cJOYSTICK::JoyKeys::None – джойстик неподвижен, централь-
ная кнопка не нажата;
cJOYSTICK::JoyKeys::Enter – нажата центральная кнопка;
cJOYSTICK::JoyKeys::Up – джойстик в положении «вверх»;
cJOYSTICK::JoyKeys::Dn – джойстик в положении «вниз»;
cJOYSTICK::JoyKeys::Left – джойстик в положении «влево»;
cJOYSTICK::JoyKeys::Right – джойстик в положении «вправо».

56
Список литературы
1. Голубцов М.С. Микроконтроллеры AVR : от простого к сложно-
му / М.С. Голубцов. – Москва : СОЛОН-Пресс, 2003. – 288 с. (Се-
рия «Библиотека инженера»).
2. Гребнев В.В. Микроконтроллеры семейства AVR фирмы Atmel /
В.В. Гребнев. – Москва : ИП. РадиоСофт, 2002. – 176 с.
3. Евстифеев А.В. Микроконтроллеры AVR семейства CLASSIC
фирмы ATMEL / А.В. Евстифеев. – Москва : Издательский дом
«Додэка-XXI», 2002. – 288 с.
4. Гриффитс А. GCC. Настольная книга пользователей, программи-
стов и системных администраторов / А. Гриффитс. – Москва :
ООО ТИД «ДС», 2004. – 624 с.
5. Знакомство с компилятором GCC [Электронный ресурс]. – Режим
доступа : http://www.linuxcenter.ru/lib/books/linuxdev/linuxdev1.
phtml, свободный. – Загл. с экрана.
6. Компилятор G++ [Электронный ресурс]. – Режим доступа :
http://www.linuxcenter.ru/lib/books/linuxdev/linuxdev4.phtml, сво-
бодный. – Загл. с экрана.
7. Managing Projects with GNU Make [Электронный ресурс] // O'Reil-
ly Media, Inc., 2004. – Режим доступа : http://shop.oreilly.com/
product/9780596006105.do, свободный. – Загл. с экрана.
8. Корнеев В.В. Современные микропроцессоры / В.В. Корнеев,
А.В. Кисилев. – Москва : Нолидж, 2000. – 316 с.
9. Гончаровский О.В. Встроенные микропроцессорные системы :
учебное пособие / О.В. Гончаровский, Н.Н. Матушкин, А.А. Южа-
ков. – Пермь : Изд-во Перм. нац. исслед. политехн. ун-та, 2012. –
198 с.

57
Приложение A. Исходные тексты программного модуля
калибровки (os_calibrate.cpp, os_calibrate.h)
// os_calibrate.h
#ifndef OS_CALIBRATE_H
#define OS_CALIBRATE_H
#define F_CPU 8000000
void OSCCAL_calibration(void);
#endif /* OS_CALIBRATE_H */
// os_calibrate.cpp
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
#include "os_calibrate.h"
void OSCCAL_calibration(void){
unsigned char calibrate = false;
int temp;
unsigned char tempL;
cli();
CLKPR = (1<<CLKPCE);
// set prescaler = 8, Inter RC 8Mhz / 8 = 1Mhz
CLKPR = (1<<CLKPS1) | (1<<CLKPS0);
TIMSK2 = 0;
ASSR = (1<<AS2);
OCR2A = 200;
TIMSK0 = 0;
TCCR1B = (1<<CS10);
TCCR2A = (1<<CS20);
while((ASSR & 0x01) | (ASSR & 0x04));
_delay_ms(1000);
while(!calibrate){
cli();
TIFR1 = 0xFF;
TIFR2 = 0xFF;
TCNT1H = 0; // clear timer1 counter
TCNT1L = 0;
TCNT2 = 0; // clear timer2 counter

58
while ( !(TIFR2 & (1<<OCF2A)) );
TCCR1B = 0; // stop timer1
if ( (TIFR1 & (1<<TOV1)) ){
temp = 0xFFFF;
}
else{
tempL = TCNT1L;
temp = TCNT1H;
temp = (temp << 8);
temp += tempL;
}
if (temp > 6250){
OSCCAL--;
}
else if (temp < 6120){
OSCCAL++;
}
else
calibrate = true;
TCCR1B = (1<<CS10);
}
EIMSK=0;
EIFR=0xFF;
// 1mhz
#if F_CPU == 1000000UL
CLKPR = (1<<CLKPCE);
CLKPR = (1<<CLKPS1) | (1<<CLKPS0);
// 2mhz
#elif F_CPU == 2000000
CLKPR = (1<<CLKPCE);
CLKPR = (1<<CLKPS1) | (0<<CLKPS0);
// 8mhz
#elif F_CPU == 8000000
CLKPR = (1<<CLKPCE);
CLKPR = (0<<CLKPS1) | (0<<CLKPS0);
#endif
}

59
Приложение Б. Исходные тексты программного драйвера пула
программных таймеров (cSoftTimers.cpp, cSoftTimers.h)
// Файл cSoftTimers.h
#ifndef CSOFTTIMERS_H
#define CSOFTTIMERS_H
#include "stdint.h"
/**
* @brief Программные таймеры
*/
class cSoftTimers {
public:
enum Constants{
/// Максимальное число таймеров
maxTimers=0x08
};
/**
* @brief Идентификатор таймера
*/
typedef int8_t idT;
/**
* @brief Процедура, Вызывается по таймеру
*/
typedef void(*timerProc)();
/**
* @brief Описатель таймера
*/
typedef struct {
// Период таймера (1мс – 60000 мс)
uint16_t period;
// Счетчик
uint16_t counter;
// Процедура обработки таймера
timerProc proc;
} dscTimer;
/**

60
* @brief Конструктор
*/
cSoftTimers();
/**
* @brief Добавить таймер
*
* @param period – Период таймера (1мс – 60000 мс)
* @param handler – Процедура обработки таймера
* @return cSoftTimers::idT – Идентификатор таймера или -1, если
некуда добавить таймер
*/
idT addTimer( uint16_t period, timerProc handler );
/**
* @brief Удалить таймер
*
* @param id – Идентификатор таймера
* @return void
*/
void delTimer(idT id);
/**
* @brief Перезапуск таймера
*
* @param id – Идентификатор таймера
* @return void
*/
void rstTimer(idT id);
/**
* @brief Запуск таймеров
*
* @return void
*/
void start();
/**
* @brief Остановка таймеров
*
* @return void
*/
void stop();
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
