Вывод символа на дисплей робота

May 26, 2014 by admin Комментировать »

Начнём создание своей программы поддержки для ЖКИ с простой задачи – вывести один символ на индикатор Я использую вначале программу ISIS для проверки результата, затем использую дисплей робота

Вспомним, как включается дисплей:

Рис 505 Включение ЖКИ робота ROBOPICA

Для написания кода программы и её отладки используем MPLABX, создав новый проект, который я назову lcd_hold, следуя всем тем инструкциям, с которыми мы определились в предыдущей главе Позже я приведу ту программу, которую использую в качестве основы для работы, а сейчас начну с тех функций, что создадут основу файла поддержки: lcd_dat(unsigned char x), lcd_com(unsigned char x), lcd_init(void) Как было написано выше, нам потребуются команды передачи данных (символов и команд), понадобится инициализация дисплея – это и определяет выбор функций

void lcd_com (unsigned char lcd)

{

unsigned char temp

temp=(lcd&amp~(1<<RS))|(1<<E) //При RS=0 записывается команда

PORTD = temp  //Выводим в порт D старшую тетраду команды, сигналы RS, E

  asm      //Небольшая задержка nop

nop nop nop nop

  endasm

PORTD = temp&amp~(1<<E)      //Запись команды

temp = ((lcd*16)&amp~(1<<RS))|(1<<E)     //При RS=0 выводится команда

PORTD = temp  //Выводим в порт D младшую тетраду команды, сигналы RS, E

  asm      //Небольшая задержка nop

nop nop nop nop

  endasm

PORTD = temp&amp~(1<<E) //Запись команды

pause (10*TIME)     //Пауза для выполнения команды

}

Напомню, не я автор этой программы И перейдём к исправлениям Из явных проблем, которые возникнут, отсутствие функции pause() Но она есть в тексте программы, добавим её:

void pause (unsigned int a)

{

unsigned int i

for (i=ai>0i–)

}

Кроме того, не определены RS, E и TIME, определение которых автор добавляет в программу:

#define RS 2       //RS = RD2 – сигнал управления ЖКИ

#define E 3        //E = RD3 – сигнал управления ЖКИ

#define TIME 50      //Константа временной задержки для ЖКИ 20 МГц

И теперь функция вывода символа:

void lcd_dat (unsigned char lcd)

{

unsigned char temp

temp=(lcd|(1<<RS))|(1<<E) //При RS=1 выводятся данные

PORTD = temp  //Выводим в порт D старшую тетраду данных, сигналы RS, E

  asm      //Небольшая задержка nop

nop nop nop nop

  endasm

PORTD = temp&amp~(1<<E) //Сигнал записи данных

temp = ((lcd*16)|(1<<RS))|(1<<E) //При RS=1 выводятся данные

PORTD = temp  //Выводим в порт D младшую тетраду данных, сигналы RS, E

  asm //Небольшая задержка nop

nop nop nop nop

  endasm

PORTD = temp&amp~(1<<E) //Сигнал записи данных pause(10*TIME) //Пауза для вывода данных

}

Последнее, что нам нужно, это функция инициализации ЖКИ:

void lcd_init (void)

{

lcd_com(0x28)  //4-проводный интерфейс, 5×8 размер символа pause(100*TIME)

lcd_com(0x0С)  //Показать изображение, курсор не показывать pause(100*TIME)

lcd_com(0x01)  //Очистить DDRAM и установить курсор на 0x00 pause (100*TIME)

}

Времена я привёл к тактовой частоте 20 МГц, в оригинале использована частота 4 МГц Первая проверочная программа (ниже без функций) выглядит следующим образом:

#include <pic16f887h>

typedef unsigned int word

word at 0x2007 CONFIG1 = 0x2FF2

void main(void) {

TRISD = 0x03 PORTD $= 0x03

pause(5000) lcd_init() lcd_dat(A) while(1)

}

Я не привожу программу полностью по причине того, что на экране дисплея в ISIS ничего не отображается Аналогичный результат и при проверке программы в «железе» Вроде бы всё правильно, но…

Проверив   и  перепроверив   разные   варианты,   вызывающие   сомнения,   я,   в   конце   концов,

«подсмотрел» то, как сделана инициализация в программе Flowcode Кстати, вышла пятая версия программы, ограничение демоверсии которой, в первую очередь, касается размера памяти, ограниченного до 2 Кбайт

Сейчас функция инициализации выглядит так:

void lcd_init (void)

{

lcd_com(0x33) pause(100*TIME) lcd_com(0x33) pause(100*TIME) lcd_com(0x32) pause(100*TIME)

lcd_com(0x28)   //4-проводный интерфейс, 5×8 размер символа pause(100*TIME)

lcd_com(0x0С)   //Показать изображение, курсор не показывать pause(100*TIME)

lcd_com(0x06) pause (100*TIME)

lcd_com(0x0C) pause(100*TIME)

}

И теперь при проверке в программе ISIS я вижу отображение символа:

Рис 506 Проверка программы после исправления функций

Прежде, чем собрать все функции в файл lcdh, что я намерен сделать, хотелось бы разобраться, какие команды выполняют добавленные строки:

lcd_com(0x33) lcd_com(0x32) lcd_com(0x06)

Первая команда в двоичном виде: 110011, – как я понимаю, относится к формату данных (Function Set в таблице инструкций), как и следующая Я, ориентируясь на четыре линии данных, написал бы эту команду иначе, но, попробуйте – изменение этих строк приводит к тому, что программа не работает

Возможно, позже, возможно, вы сами разберётесь, в чём дело Я не исключаю, что контроллер ЖКИ другой На плате используется бескорпусной контроллер И, если работает, то пусть работает

Создадим файл lcdh:

#define RS 2

#define E 3

#define TIME 50

void pause (unsigned int a)

{

unsigned int i

for (i=ai>0i–)

}

void lcd_com (unsigned char lcd)

{

unsigned char temp

temp=(lcd&amp~(1<<RS))|(1<<E) PORTD = temp

_asm

nop

nop nop nop nop

_endasm

PORTD = temp&amp~(1<<E)

temp = ((lcd*16)&amp~(1<<RS))|(1<<E) PORTD = temp

_asm

nop nop nop nop nop nop

_endasm

PORTD = temp&amp~(1<<E) pause (10*TIME)

}

void lcd_dat (unsigned char lcd)

{

unsigned char temp

temp = (lcd|(1<<RS))|(1<<E) PORTD = temp

  asm

nop nop nop nop nop

  endasm

PORTD = temp&amp~(1<<E)

temp = ((lcd*16)|(1<<RS))|(1<<E) PORTD = temp

  asm

nop

  endasm

nop nop nop nop

PORTD = temp&amp~(1<<E) pause(10*TIME)

}

void lcd_init (void)

{

lcd_com(0x33)

pause(100*TIME) lcd_com(0x32) pause(100*TIME) lcd_com(0x28) pause(100*TIME) lcd_com(0x0C) pause(100*TIME) lcd_com(0x06) pause (100*TIME) lcd_com(0x0C) pause(100*TIME)

}

Созданный файл добавим в папку программы, саму программу оформим так:

#include <pic16f887h>

#include &quotlcdh&quot

typedef unsigned int word

word at 0x2007 CONFIG1 = 0x2FF2

void main(void) { TRISD = 0x03 PORTD &amp= 0x03

pause(5000) lcd_init() lcd_dat(I)

lcd_dat(\’)

lcd_dat(m)

lcd_dat( )

lcd_dat(R)

lcd_dat(O)

lcd_dat(B)

lcd_dat(O)

lcd_dat(P)

lcd_dat(I)

lcd_dat(C)

lcd_dat(A) while(1)

}

Конечно,   выводить   сообщения   с   помощью   символов,   это   не   самое   правильное   Следует использовать строку текста Но сейчас важно проверить, правильно ли работает программа

Проверим это с помощью ISIS (Proteus):

Рис 507 Проверка программы вывода сообщения на ЖКИ И завершим проверку, загрузив программу в ROBOPICA

Рис 508 Загруженная программа в ROBOPICA

В программе есть строки, которые мне хотелось бы пояснить Пояснить, используя не ссылку на учебник, а программу MPLABX с компилятором SDCC Конечно, нужно обязательно читать учебник, спору нет, но, читая учебник, полезно проделать операции в среде разработки Итак:

temp = ((lcd*16)&amp~(1<<RS))|(1<<E)

Разберём эту строку «по кирпичикам» Напишем такую программу:

#include <pic16f887h>

typedef unsigned int word

word at 0x2007 CONFIG1 = 0x2FF2

#define RS 2

unsigned char temp = 0

void main()

{

temp = 1<<RS

}

Создадим в MPLABX новый проект, новый исходный файл для SDCC, скомпилируем программу и запустим отладку На инструментальной панели нажмём паузу (панель отладки), а затем сброс (кнопка Reset) на инструментальной панели В окне редактора отображается текст программы на ассемблере   Для   наблюдения   за   переменными   используйте   окно   наблюдения:   Window-

>Debugging->Watches Чтобы добавить наблюдение за переменной temp, достаточно щёлкнуть в окне редактора правой клавишей мышки и выбрать пункт New Watch…

Рис 509 Окно ввода переменной для наблюдения

Переменную я ввожу в том виде, в котором она представлена на ассемблере, и она выделена цветом, если есть в программе После того, как нажата кнопка ОК, переменная появляется в окне наблюдения Нажав на инструментальной панели (панель отладки) кнопку сброса после запуска отладки, можно начать пошаговое прохождение программы Изначально переменная в окне наблюдение равна нулю:

Рис 5010 Начальное значение переменной в окне наблюдения

После пошагового прохождения программы переменная изменит своё значение:

Рис 5011 Новое значение переменной

Запишем это значение в двоичном виде: 00000100

Теперь изменим программу, записав единственную её строку так: temp = 1<<E

Откомпилируем программу заново (Run->Build Project), запустим, остановим отладчик, сбросим программу и пройдём её по шагам, чтобы получить новое значение переменной в окне наблюдения:

Рис 5012 Ещё одно значение переменной после изменения программы И это значение тоже запишем в двоичном виде: 00001000

Обратим внимание на определение, которое задаёт E:

#define E 3

То есть, в программе E – это число 3

Операция << осуществляет побитовый сдвиг влево Сдвигается число, стоящее слева от знака на количество позиций, которое записано справа В первом случае можно было бы записать так 1<<2 Что означало бы, число 0000001 сдвигается на два разряда влево: 00000100 Во втором случае, записывая его 1<<3, мы получаем сдвиг на три разряда: 00001000

Теперь посмотрим, как влияет на результат значок, который добавлен к первому сдвигу влево:

~(1<<RS)

Внеся изменения в программу, я использую компиляцию командой Run->Clean and Build Project И дальше запуская отладку, прервав её и сделав сброс кнопкой инструментальной панели Reset, я пошагово выполняю программу:

Рис 5013 Результат операции инверсии

Запишем  результат  сдвига  и  полученное  значение  в  двоичном  виде:  00000100  и  11111011 Операция инверсии или отрицания меняет единицы на нули и наоборот

Следующее,  что  я  хочу  показать,  это  результат  умножения:  lcd*16  Добавляя  в  программу переменную lcd = 0x0F, (двоичное число 00001111) я умножу её на 16 (десятичное):

Рис 5014 Результат умножения числа на 16

В двоичном виде это число выглядит следующим образом: 11110000  Умножение  двоичного числа на 2 похоже на умножение десятичного числа на 10, то есть, прибавляем ноль справа Количество этих нулей определяется количеством десяток в десятичной системе счисления и количеством двоек в двоичной

Когда мы выводим значение на жидкокристаллический индикатор, используя четырёх-битовую шину данных, мы выводим старшую тетраду байта Чтобы подготовить младшую тетраду, мы и умножаем число на 16

Как и в арифметике, в любом языке программирования порядок выполнения операций строго определён, а повлиять на это можно с помощью выделения операций скобками Рассмотрим, как выглядит результат операции:

temp = ((lcd*16)&amp~(1<<RS))

Все операции, кроме операции &amp, мы уже разобрали Эта операция – побитовое логическое И Значение lcd то же, что и в предыдущем примере

Рис 5015 Результат выполнения логического И

Первое число в скобках – 11110000, второе – 00000100 Второе число после операции НЕ – 11111011 И результат получается таким, как если бы мы «побитово умножили» одно число на другое

Наконец, выполним всю последовательность операций Из них осталась операция |, с которой мы ещё не знакомы Это операция побитового ИЛИ двух операндов Операция, которая напоминает арифметическое «побитовое сложение»

Рис 5016 Результат выполнения всех исследованных операций

Мы разобрали одну строку программы Очень полезно, используя предложенный мною механизм исследования, или ориентируясь на учебники, разобрать все операции языка Си, чтобы ясно понимать, что вы получите в результате операции

Программе приходится манипулировать с тетрадами байта данных и управлять сигналами RS и E, первый переключает шину данных с приёма команд на приём символов, второй разрешает передачу этих данных в регистры контроллера ЖКИ

Программу можно было бы написать и иначе, но я предпочёл оставить авторское изложение, поскольку вы часто встретите именно такой подход

Использование среды разработки MPLABX, как вы видите, благодаря встроенному механизму отладки не только помогает отлаживать написанный вами текст программы, но и помогает глубже изучить язык Си

Ценой отказа от ограничения на размер программы и становится необходимость глубже изучать язык программирования Но это открывает для вас и новые горизонты, новые возможности

Модуль аналого-цифрового преобразователя может быть встроен в микроконтроллер, а может отсутствовать Модуль АЦП может быть многоканальным

Очень удобно применять АЦП микроконтроллера в паре с датчиками, которые плавно меняют своё значение Например, если в качестве датчика температуры использовать терморезистор, то напряжение, меняющееся при изменении температуры, можно считывать программно

В MicroC и для этих целей есть библиотечный файл, обслуживающий работу с АЦП (ADC) Как и в предыдущих главах, для компилятора SDCC нам потребуется создать такой  вспомогательный файл, имеющий все необходимые функции

Источник: Гололобов ВН,- Самоучитель игры на паяльнике (Об электронике для школьников и не только), – Москва 2012

Оставить комментарий

микросхемы мощности Устройство импульсов питания пример приемника провода витков генератора выходе напряжение напряжения нагрузки радоэлектроника работы сигнал сигнала сигналов управления сопротивление усилитель усилителя усиления устройства схема теория транзистора транзисторов частоты