Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Микроконтроллеры с ядром Cortex-M3 в системах управления и автоматики. Учебное пособие

.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать
☆
Поле DMA_DestBaseAddr содержит адрес регистра, в который будут помещаться данные для преобразования ЦАП. В поле DMA_SourceBaseAddr помещается адрес начала буфера с данными для преобразования. В поле DMA_CycleSize записываем количество
циклов считывания данных из буфера. Поскольку запись данных производится в один
регистр, в поле DMA_DestIncSize помещаем признак запрета автоувеличения адреса приемника данных. В поле DMA_SourceIncSize записываем признак автоматического смещения адреса буфера данных на два байта (DMA_SourceIncHalfword). В поле DMA_MemoryDataSize обозначаем размер порции данных, передаваемых из буфера для преобразования (DMA_MemoryDataSize_HalfWord = 2 байта). Поле DMA_NumContinuous
содержит количество повторений полных циклов передачи информации (это значение
должно быть равно 2
k
, где k изменяется от 0 до 10). С помощью полей DMA_SourceProtCtrl и DMA_DestProtCtrl можно управлять режимом защиты источника и приемника данных. В приведенном тексте оба режима включены. В поле DMA_Mode выбираем режим работы DMA. В данном случае выбран базовый режим.
Следующим шагом заполняем структуру для настройки канала DMA:
DMACIStruct.DMA_PriCtrlData = &DMA_InitStructure; DMACIStruct.DMA_SelectDataStructure = DMA_CTRL_DATA_PRIMARY; DMACIStruct.DMA_Priority = DMA_Priority_Default; DMACIStruct.DMA_UseBurst = DMA_BurstClear.
В поле DMA_PriCtrlData записываем адрес заполненной структуры настроек DMA, а с помощью поля DMA_SelectDataStructure определяем ее как используемую. С помощью поля DMA_Priority задаем приоритет канала DMA (выбраны настройки по умолчанию). С помощью поля DMA_UseBurst отменяем запрет на одиночные запросы к DMA.
После задания настроек каналу DMA необходимо инициализировать канал DMA для
работы совместно с таймером, снять запрет на запросы таймера к DMA, разрешить работу
DMA с таймером и разрешить работу DMA с каналом таймера TIM1. Также нужно определить приоритет аппаратных прерываний от DMA как 1:
DMA_Init(DMA_Channel_TIM1, &DMACIStruct);
MDR_DMA->CHNL_REQ_MASK_CLR = 1 << DMA_Channel_TIM1;
MDR_DMA->CHNL_USEBURST_CLR = 1 << DMA_Channel_TIM1;
DMA_Cmd(DMA_Channel_TIM1, ENABLE);
NVIC_SetPriority(DMA_IRQn, 1).
После выполненных настроек для работы с DMA необходимо произвести настройки
таймера. Это требуется для определения временного интервала, через который DMA будет
передавать данные в ЦАП. Для настроек таймера необходимо использовать структуру типа
TIMER_CntInitTypeDef;
TIMER_CntInitTypeDef TCInit.
41
Далее нужно сбросить настройки таймера и включить его тактирование. Используем
для примера таймер TIM1. Для настройки частоты тактирования выберем делитель частоты
импульсов 1. Значения делителя задаются выражением 2
k
, где k изменяется от 0 до 7:
TIMER_DeInit(MDR_TIMER1);
RST_CLK_PCLKcmd(RST_CLK_PCLK_TIMER1, ENABLE);
TIMER_BRGInit(MDR_TIMER1, TIMER_HCLKdiv1);
TCInit.TIMER_Prescaler = 0;
TCInit.TIMER_Period = 3200;
TCInit.TIMER_CounterDirection = TIMER_CntDir_Up;
TCInit.TIMER_CounterMode = TIMER_CntMode_ClkFixedDir;
TCInit.TIMER_EventSource = TIMER_EvSrc_None;
TCInit.TIMER_FilterSampling = TIMER_FDTS_TIMER_CLK_div_1;
TCInit.TIMER_ARR_UpdateMode = TIMER_ARR_Update_Immediately;
TCInit.TIMER_ETR_FilterConf = TIMER_Filter_1FF_at_TIMER_CLK;
TCInit.TIMER_ETR_Prescaler = TIMER_ETR_Prescaler_None;
TCInit.TIMER_ETR_Polarity = TIMER_ETRPolarity_NonInverted;
TCInit.TIMER_BRK_Polarity = TIMER_BRKPolarity_NonInverted.
Поле TIMER_Prescaler позволяет задать значение предделителя импульсов. Период
таймера устанавливается значением поля TIMER_Period. Это значение вычисляется по формуле P = 80000000/(F*S) - 1, где F — частота сигнала, S — размер буфера. В поле TIMER_CounterDirection задается направление отсчетов (увеличение или уменьшение), а в поле TIMER_CounterMode это направление фиксируется.
Далее таймер инициализируется заданной структурой и разрешается работа DMA совместно с таймером:
TIMER_CntInit(MDR_TIMER1, &TCInit);
TIMER_DMACmd(MDR_TIMER1, TIMER_STATUS_CNT_ARR, ENABLE).
В процессе преобразований запрос к DMA будет возникать при достижении таймером
значения TIMER_STATUS_CNT_ARR. После этого разрешаем работу таймера TIMER1 и аппаратные прерывания DMA:
TIMER_Cmd(MDR_TIMER1, ENABLE);
NVIC_EnableIRQ(DMA_IRQn).
После этого ЦАП начнет генерировать сигнал.
Следует напомнить, что для корректной работы необходимо настроить обработчик
прерываний от DMA. В нем рекомендуется переопределить объем передаваемых данных и инициализировать канал DMA.
42
2.4. Организация вывода информации на графический дисплей
Chip2
Управляющий
контроллер
К145ВГ10
(KS0108)
Chip1
DB7-DB0
R/W
E
RES
A0
E1 E2
UCC
U
0
GND
Led+
Led-
Драйвер
питания
Драйвер
сегментов
KS0107
ЖК
матрица
Подсветка
Для вывода информации в микропроцессорных и микроконтроллерных системах
применяются графические дисплеи (GLCD). В частности, в отладочных платах
микроконтроллеров серии 1986ВЕ9х применяется жидкокристаллический дисплей МТ-12864J-2YLG-3V0 под управлением контроллера К145ВГ10 [10, 12, 14, 15].
В дисплеях GLCD, совместимых с системой команд контроллера KS0108 (фирма Samsung), чипсет, как правило, обозначается через дробь KS0107/KS0108. Название KS0107 относится к драйверу сегментов, а KS0108 — к управляющему контроллеру. Иногда
в документации указывают только тип контроллера KS0108, подразумевая, наличие
микросхемы драйвера KS0107. На рис. 2.5 показана структурная схема GLCD-дисплея стандарта KS0107/KS0108 с раскладкой 128 × 64 пикселя. Основой служит матрица ЖК-элементов, скомпонованная по ширине в 128 столбцов и по высоте в 64 строки. Чтобы включить каждый из 8 192 пикселей экрана, необходимо 192 транзисторных ключа, размещаемых в драйверах KS0107 и паре контроллеров KS0108. Емкость внутреннего ОЗУ каждого контроллера — 4 Кбит. В контроллере есть схемы управления и сопряжения с внешней шиной. Драйвер KS0107 формирует сетку синхросигналов для всей системы. Графические ЖК-дисплеи в большинстве случаев имеют встроенную светодиодную подсветку экрана. Цвет подсветки определяет фон картинки.
Рис. 2.5. Структурная схема контроллера дисплея
Назначение сигналов шины и номера выводов показаны в табл. 2.2. Дисплей имеет два контроллера Chip1 и Chip2. Для выбора контроллера используют выводы Е1 и Е2. Для того, чтобы «включить» пиксель на GLCD-дисплее, необходимо записать 1 в соответствующий бит ОЗУ. В начале работы с GLCD-дисплеем нужно подать 0 (сигнал RES) с длительностью около 1 мкс, после чего необходима пауза около 10 мкс.
43
Таблица 2.2
Номер
вывода
Обозначение
Назначение вывода
4…11
DB0 ÷ DB7
Шина данных DB0 ÷ DB7
12
E1
Выбор кристалла 1
13
E2
Выбор кристалла 2
14
RES
Сброс
15
R/W
Чтение/Запись
16
A0
Команды/Данные
17 E Стробирование данных
Обозначение выводов микроконтроллера К145ВГ10
Для удобства программирования ОЗУ микроконтроллера разделено на 8 страниц
каждая размером 64 × 8 бит, фактически представляющие собой матрицы для описания образа выводимого знака. Передача информации в модуль осуществляется побайтно
с предварительным заданием номера страницы ОЗУ и адреса внутри страницы. Для этого
используются команды «Set Page» и «Set Address». Параллельно с записью байта нужно
подать 1 на соответствующий вывод Е1 или Е2. После записи байта счетчик адресов
автоматически увеличивается на 1. При этом счетчик адресов обслуживает только одну
страницу памяти. После достижения счетчиком значения 63 на следующем шаге его
значение сбрасывается. Помимо этого графический модуль позволяет читать содержимое ОЗУ. Для выбора режима Чтение/Запись используется линия R/W. Для переключения режима
Команда/Данные задействуется линия А0 (0 — команда, 1 — данные).
Контроллер управления графического дисплея К145ВГ10 (производство ОАО «Ангстрем», г. Зеленоград) аналогичен контроллеру KS0108 фирмы SAMSUNG. Полная техническая информация на модуль графического дисплея MT-12864J содержится в спецификации [10, 12, 14, 15].
Разработчик программного обеспечения самостоятельно формирует базу букв, цифр,
символов, знаков. При программировании каждая страница представлена в виде матрицы 64 × 8 бита. Запись информации в модуль осуществляется по страницам (64 байта данных) (рис. 2.6). Для записи байта данных по произвольному адресу необходимо предварительно
установить страницу ОЗУ и установить адрес внутри страницы ОЗУ. Это осуществляется
командами Set Page и Set Address соответственно. После этого можно записать байт данных.
Модуль поддерживает непрерывную последовательность операций записи: после записи
одного байта счетчик адреса автоматически увеличивается на 1, и модуль готов к новой операции записи по следующему адресу без предварительной установки страницы ОЗУ и адреса. Счетчик адреса считает только внутри одной страницы. При достижении адреса
44
63 следующим значением счетчика будет 0 и т. д. Между любыми двумя передачами данных
Для левой половины отображаемого
поля точек (1-й кристалл, Е1 = 1)
Для правой половины отображаемого
поля точек (2-й кристалл, Е2 = 1)
или команд необходимо выдержать паузу не менее 8 мкс или ожидать сброса флага BUSY в регистре состояния того кристалла, к которому будет обращение. Возможна скорость потока данных до 100–130 тыс. байт/с.
Рис. 2.6. Соответствие адресов ОЗУ отображаемыми точками на ЖК-дисплее [10]
45
Рутинные процедуры для работы с графическим модулем дисплея собраны
в библиотеку, которая представлена в виде отдельного файла lcd_mlt.lib. Для организации
взаимодействия с графическим ЖК-модулем библиотеку следует подключить к проекту посредством команд Project/Manage/Components, Environment, Books.../Project items/Files/Add Files. Прототипы всех библиотечных функций собраны в отдельный файл lcd_mlt.h, который необходимо включить в программу посредством оператора #include.
Функции для работы с графическим модулем собраны в библиотеке lod_mlt.lib с заголовочным файлом lod_mlt.h. Ниже приведен фрагмент текста программы, позволяющей вывести символ на дисплей:
MltPinCfg();
LcdInit();
LcdClearChip(1);
LcdClearChip(2);
LcdPutImage(Logotip, 0, 0, 7, 15).
Для вывода символа необходимо подключить HSE-генератор и установить частоту тактирования 8 МГц. Функция MltPinCfg конфигурирует линии микроконтроллера с графическим модулем. Функция LcdInit инициализирует ЖК-дисплей. Функция
LcdClearChip используется для очистки ОЗУ графического модуля. Функция LcdPutImage(uint8_t *, int Y0, int X0, int Y1, int X1) выводит графический образ на экран
дисплея. В выводимом массиве должны быть представлены 8 групп из 128 байтов. Еще
четыре аргумента этой функции задают координаты левой верхней (Y0, X0) и правой нижней (Y1, X1) точек региона отображения на дисплее. Координата X меняется в диапазоне от 0 до 15, координата Y — от 0 до 7.
Вывод одиночных символов в произвольную часть отображаемой области точек производится путем вызова библиотечной функции LcdPutChar(): LcdPutChar (uint8_t* array, int Xpos, int Ypos). Это библиотечная функция для вывода графического образа символа.
Первый аргумент представляет собой указатель на массив точек, соответствующих образу
символа. Графические образы символов подготовлены в файле font.h. Каждому символу (8 × 8 точек) соответствует группа из 8 байтов в виде массива uint8_t symbol [10, 12, 14, 15].
Второй и третий аргументы функции задают местоположение выводимого символа.
Численные значения этих аргументов могут изменяться от 0 до 7 (Ypos) и от 0 до 15 (Xpos):
#include <MDR32F9Qx_config.h> // Device Startup
#include <MDR32Fx.h> // Device Header
#include <.\mlt\lcd_mlt.h> // LCD module functions
#include <.\mlt\font.h> // Fonts
void frq_init(void);
int main (void)
46
{
frq_init();
MltPinCfg();
LcdInit();
LcdClearChip(1);
LcdClearChip(2);
LcdPutChar (cyr_F, 5, 3);
LcdPutChar (cyr_I, 6, 3);
LcdPutChar (cyr_Z, 7, 3);
LcdPutChar (cyr_T, 8, 3);
LcdPutChar (cyr_E, 9, 3);
LcdPutChar (cyr_KH, 10, 3);
while(1) ;
}
//Pins configuration for LCD //LCD module init //Clear chip 1 //Clear chip 2
Вывод строки символов осуществляется при помощи функции LcdPutString (uint8_t** array, int Ypos). Первый аргумент представляет собой указатель на строку символов. Второй
аргумент задает местоположение строки по вертикали. Подпрограмма-функция будет
пытаться вывести ровно 16 символов, чтобы заполнить одну страницу ОЗУ графического
модуля. Строка символов задана в формате файла font.h. Пример программы:
#include <MDR32F9Qx_config.h> // Device Startup
#include <MDR32Fx.h> // Device Header
#include <.\mlt\lcd_mlt.h> // LCD module functions
#include <.\mlt\font.h> // Fonts
void frq_init(void);
int main (void)
{
uint8_t *array[16] = {sym_sp,sym_sp,sym_sp,sym_sp,sym_sp,\
cyr_T,cyr_S,cyr_T,cyr_U,cyr_.,cyr_RU,
sym_sp,sym_sp,sym_sp,sym_sp,sym_sp};
frq_init();
MltPinCfg(); //Pins configuration for LCD
LcdInit(); //LCD module init
LcdClearChip(1); //Clear chip 1
LcdClearChip(2); //Clear chip 2
LcdPutString (array, 2);
while(1) ;
}
47
Вывод строки символов в ASCII кодировке [10, 12, 14, 15]. Эта программа читает системную переменную SystemCoreClock, осуществляет форматированный вывод информации о текущей тактовой частоте микроконтроллера в строку ch_str (ASCII кодировка). При помощи подпрограммы-функции ascii() сопоставляет ASCII-символ строки с графическим образом этого символа в файле font.h. Функция LcdPutString() выводит графический образ строки на экран. Секция include содержит дополнительный файл stdio.h, в котором размещены прототипы стандартных функций ввода-вывода. Секция прототипов
функций дополнена декларацией функции ascii(). Длина строки для вывода задана
константой STR_LENGTH.
В секции main объявляются два массива одинаковой длины. Массив ch_str служит для
размещения строки вывода, символы которой представлены в кодировке ASCII. Этот массив
заполняется при помощи стандартной функции sprintf(). Массив array служит для
размещения указателей на графические образы этих символов в файле font.h. Каждый элемент этого массива заполняется при помощи функции ascii() в цикле по индексу «i».
Функция ascii() выполняет роль знакогенератора. Она принимает ASCII-символ в качестве входного аргумента и возвращает указатель на графический образ этого символа
в файле font.h. Основу функции ascii() составляет оператор switch, осуществляющий
многовариантный выбор. Для минимизации объема программы он содержит только
символы, используемые в данной программе:
#include <MDR32F9Qx_config.h> // Device Startup
#include <MDR32Fx.h> // Device Header
#include <.\mlt\lcd_mlt.h> // LCD module functions
#include <.\mlt\font.h> // Fonts
#include <stdio.h>
#define STR_LENGTH 16 //Length of the string in bytes
void frq_init_pll(void);
uint8_t * ascii(char symbol);
int main (void)
{
char ch_str[STR_LENGTH];
uint8_t *array[STR_LENGTH], i;
frq_init_pll();
MltPinCfg(); //Pins configuration for LCD
LcdInit(); //LCD module init
LcdClearChip(1); LcdClearChip(2); //Clear chip 1 & 2
sprintf(ch_str," %u %c%c%c",SystemCoreClock/1000,\
'k','H','z');
for(i = 0;i < STR_LENGTH;i++) {array[i] = ascii(ch_str[i]);}
LcdPutString(array, 3);
48
while(1) ;
}
uint8_t* ascii(char symbol)
{
uint8_t* ch_ptr;
switch (symbol){
case '0': ch_ptr=dig_0; break;
case '1': ch_ptr=dig_1; break;
case '2': ch_ptr=dig_2; break;
case '3': ch_ptr=dig_3; break;
case '4': ch_ptr=dig_4; break;
case '5': ch_ptr=dig_5; break;
case '6': ch_ptr=dig_6; break;
case '7': ch_ptr=dig_7; break;
case '8': ch_ptr=dig_8; break;
case '9': ch_ptr=dig_9; break;
case 'H': ch_ptr=lat_H; break;
case 'V': ch_ptr=lat_V; break;
case 'k': ch_ptr=lat_k; break;
case 'z': ch_ptr=lat_z; break;
case '.': ch_ptr=sym_pt;break;
default: ch_ptr=sym_sp;break;
}
return(ch_ptr);
}
Вывод графического символа (128×64 точки) на ЖК-дисплей организован в виде программы [10, 12, 14, 15] с применением библиотеки lcd_mlt.lib, подключенной к проекту с помощью команд [Project/Manage...]:
#include <MDR32F9Qx_config.h> // Device Startup
#include <MDR32Fx.h> // Device Header
#include <.\mlt\lcd_mlt.h> // LCD module functions
#include <.\mlt\logo_mlt.h> // Picture for output
void frq_init(void);
int main (void)
{
frq_init();
MltPinCfg(); //Pins configuration for LCD
LcdInit(); //LCD module init
49
LcdClearChip(1); //Clear chip 1
LcdClearChip(2); //Clear chip 2
LcdPutImage(*LogoMlt[0],0,0,7,15); //Draw picture for LCD while(1) ;
}
Контрольные вопросы и задания к главе 2
1. Сколько портов ввода-вывода имеет микроконтроллер 1986ВЕ92У?
2. Нарисуйте схему организации разряда порта ввода-вывода.
3. Поясните назначение инструкции PORT_InitTypeDef.
4. Поясните назначение инструкции POTR_StructInit.
5. Нарисуйте структурную схему контроллера АЦП.
6. Какой порт ввода-вывода функционирует в режиме АЦП?
7. Поясните назначение инструкции ADC_InitTypeDef.
8. Поясните назначение инструкции PtIStruct.PORT_Pin.
9. Поясните назначение инструкции ADCInit.
10. Поясните назначение инструкции DMA_StructInit.
11. Поясните назначение инструкции DMA_Init.
12. Нарисуйте структурную схему контроллера ЦАП.
13. Какой порт ввода-вывода функционирует в режиме ЦАП?
14. Поясните назначение инструкции DAC_DeInit.
15. Поясните назначение инструкции DAC2_Cmd.
16. Поясните назначение инструкции TIMER_DeInit
17. Объясните функциональное назначение контроллера KS0108.
18. Объясните функциональное назначение контроллера KS0107.
19. Объясните функциональное назначение контроллера К145ВГ10.
20. Нарисуйте структурную схему контроллера GLCD-дисплея.
21. Сколько разрядов имеет внешняя шина данных контроллера GLCD-дисплея
MT-12864J?
22. Поясните страничную организацию отображаемого поля точек GLCD-дисплея
MT-12864J.
23. Поясните назначение инструкции LcdInit.
24. Поясните назначение инструкции LcdClear.
25. Поясните назначение инструкции LcdPutChar.
50
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]