Введение
Некоторое время назад я написал макросы для реализации виртуальных портов. С помощью этих макросов можно переделать практически любую библиотеку для работы с произвольными выводами микроконтроллера. Первая библиотека, которая попала под это изменение, стала библиотека для символьного LCD. В этом посте я расскажу, как ее применить в своем проекте.
Особенности
- работает с компиляторами IAR AVR, CodeVision AVR, GNU GCC,
- поддерживает lcd контроллеры HD44780 и KS0066,
- поддерживает подключение lcd к произвольным выводом микроконтроллера,
- поддерживает 4-х и 8-ми разрядный интерфейс,
- имеет функции вывода строк из ОЗУ и флэш,
- имеет функции добавление пользовательских символов.
Состав библиотеки
compilers_4.h - файл для поддержки трех компиляторов
port_macros.h - макросы виртуальных портов
lcd_lib_2.h - заголовочный файл LCD библиотеки с прототипами функций и настройками
lcd_lib_2.c - файл реализации функций LCD библиотеки
Подключение к проекту
1. Переписываем все файлы библиотеки в папку проекта.
2. Подключаем lcd_lib_2.c к проекту внутри среды разработки.
3. Инклюдим заголовочный файл lcd_lib_2.h к сишному файлу, в котором будут использоваться lcd функции.
4. Настраиваем конфигурацию lcd библиотеки в заголовочном файле lcd_lib_2.h
5. Прописываем в код вызов функций lcd библиотеки.
Настройка конфигурации
Настройка конфигурации в файле lcd_lib_2.h включает в себя следующие шаги.
1. Настройка виртуального или реального порта, к которому подключается LCD
Синтаксис объявления виртуального порта подробно описан в файле port_macros.h и в статье посвященной виртуальным портам. В заголовочном файле lcd_lib_2.h уже объявлен порт, в этих объявления нужно менять только буквы порта (A, B, C..), номера выводов (0, 1, 2, 3 ...), тип порта (_REAL, _VIRT), активный уровень (_HI, _NONE). Все остальное (имя порта и имена выводов) трогать не надо.
Пример объявление виртуального порта для 8-ми битной шины и реального порта для 4-х битной шины.
Рамками выделены те части кода, которые нужно настраивать под свой проект.
2. Глобальные настройки драйвера
LCD_CHECK_FL_BF - проверять флаг BF или использовать программную задержку. 0 - задержка, 1 - проверка флага.
LCD_BUS_4_8_BIT - используемая шина данных. 0 - 4 разрядная шина, 1 - 8-ми разрядная
3. Настройка инициализации дисплея
Эти настройки определяют состояние дисплей после вызова функции LCD_Init().
LCD_ONE_TWO_LINE - количество отображаемых строк. 0 - 1 строка; 1 - 2 строки.
LCD_FONT58_FONT511 - тип шрифта. 0 - 5х8 точек; 1 - 5х11 точек.
LCD_DEC_INC_DDRAM - изменения адреса ОЗУ при выводе на дисплей. 0 - курсор движется влево, адрес уменьшается на 1 (текст получается задом наперед) ; 1 - курсор движется вправо, адрес увеличивается на 1.
LCD_SHIFT_RIGHT_LEFT - сдвиг всего дисплея. 0 - при чтении ОЗУ сдвиг не выполняется, 1 - при записи в ОЗУ сдвиг дисплея выполняется согласно установке LCD_DEC_INC_DDRAM (0 - сдвиг вправо, 1 - сдвиг влево)
LCD_DISPLAY_OFF_ON - включение / выключение дисплея. 0 - дисплей выключен, но данные в ОЗУ остаются; 1 - дисплей включен.
LCD_CURSOR_OFF_ON - отображение подчеркивающего курсора. 0 - курсор не отображается, 1 - курсор отображается.
LCD_CURSOR_BLINK_OFF_ON - отображение мигающего курсора. 0 - мигающий курсор не отображается; 1 - мигающий курсор отображается.
LCD_CURSOR_DISPLAY_SHIFT - команда сдвига вправо/влево курсора или дисплея без записи на дисплей. В библиотеке не используется и ни на что не влияет. Затесалась сюда случайно )
Пользовательские макросы и функции
LCD_Clear() - очистка дисплея.
LCD_ReturnHome() - возврат курсора в начальное положение.
LCD_Goto(x, y) - позиционирование курсора. x - номер знакоместа, y - номер строки.
void LCD_Init(void) - инициализация дисплея.
void LCD_WriteCom(uint8_t data) - запись команды
void LCD_WriteData(char data) - вывод одного символа
void LCD_SendStr(char *str) - вывод строки из ОЗУ.
void LCD_SendStrFl(char __flash *str) - вывод строки из флэш памяти.
void LCD_SetUserChar(uint8_t __flash *sym, uint8_t adr) - загрузка пользовательского символа в ОЗУ дисплея.
Пример использования:
char textCompiler[] = "xz ";
__flash uint8_t quarterNote[] = {4,4,4,4,4,4,28,28};
int main( void )
{
//инициализируем дисплей
LCD_Init();
//загружаем пользовательский символ в нулевую ячейку ОЗУ дисплея
LCD_SetUserChar(quarterNote, 0);
//устанавливаем курсор в 8-мое знакоместо
LCD_Goto(8,0);
//выводим строку на дисплей
LCD_SendStr(textCompiler);
while(1);
return 1;
}
Файлы
LCD_VP_iar.rar - тестовый проект для IAR AVR
LCD_VP_as6.rar - тестовый проект для AtmelStudio
LCD_VP_cv.rar - тестовый проект для CodeVision AVR
LCD_VP_winavr.rar - тестовый проект для WinAvr
LCD_VP_proteus.rar - тестовый проект для Proteus
lcd_lib_2.rar - lcd библиотека с произвольным подключением выводов
Comments
У меня вопрос по назначению реального порта!? Пины должны нумероваться с 0 по 7 и никак по другому?(Наприм ер у порта С в меге 88 пользоваться пинами можно с 0 по 5) Выход - виртуальный порт?
Еще допилил вашу библиотеку для работы с произвольным X Y дисплея. (20x4 мне нужен был) Куда изменения выложить?
Нумерация с 0 по 7. Если выводы реального порта не используются, то добавляется атрибут _NONE.
Напиши мне через форму обратной связи, я тебе отвечу по почте и ты мне скинешь свой проект. Я его выложу на форум или присоединю к материалу.
#define LCD_PORT LCD_DATA, C, _REAL
#define LCD_DATA_0 C, 0, _NONE
#define LCD_DATA_1 C, 1, _NONE
#define LCD_DATA_2 C, 6, _NONE
#define LCD_DATA_3 C, 7, _NONE
#define LCD_DATA_4 C, 2, _HI
#define LCD_DATA_5 C, 3, _HI
#define LCD_DATA_6 C, 4, _HI
#define LCD_DATA_7 C, 5, _HI
Не работает. Если погонять в протосе, видно как 0x30 пишется в порт 0x30 а не 0x0C
Code:
#define LCD_DATA_0 C, 0, _NONE
#define LCD_DATA_1 C, 1, _NONE
#define LCD_DATA_2 C, 2, _HI
#define LCD_DATA_3 C, 3, _HI
#define LCD_DATA_4 C, 4, _HI
#define LCD_DATA_5 C, 5, _HI
#define LCD_DATA_6 C, 6, _NONE
#define LCD_DATA_7 C, 7, _NONE
А что это изменит?
Как я понимаю для корректной работы драйвера LCD требуется соответствие
Code:
#define LCD_DATA_4 C, 2, _HI
#define LCD_DATA_5 C, 3, _HI
#define LCD_DATA_6 C, 4, _HI
#define LCD_DATA_7 C, 5, _HI
Попробовал, ничего не изменилось.
З.Ы. Проект готов к отправке.
Code:
#define LCD_Goto(x,y) LCD_WriteCom(((((y)&1)*0x40)+((((y)&3)>>1)*0x10)+(x))|128)
А вот так для дисплея 20 х 4 :
#define LCD_Goto(x,y) LCD_WriteCom((( ((y)&1)*0x40)+( (((y)&3)>>1)*0x 14)+(x))|128)
Компилятор WINAVR, МК- ATmega8A
Распиновка следующая
#define VIRT_PORT
#ifdef VIRT_PORT
//здесь я определил виртуальный порт
//шина данных LCD
#define LCD_PORT LCD_DATA, F, _VIRT
#define LCD_DATA_0 D, 0, _HI
#define LCD_DATA_1 D, 1, _HI
#define LCD_DATA_2 D, 2, _HI
#define LCD_DATA_3 C, 5, _HI
#define LCD_DATA_4 C, 4, _HI
#define LCD_DATA_5 C, 3, _HI
#define LCD_DATA_6 B, 0, _HI
#define LCD_DATA_7 B, 1, _HI
//управляющие выводы LCD
#define LCD_RS C, 0, _HI
#define LCD_RW C, 1, _HI
#define LCD_EN C, 2, _HI
//глобальные настройки драйвера
#define LCD_CHECK_FL_BF 1
#define LCD_BUS_4_8_BIT 1
//настройки инициализации дисплея
#define LCD_ONE_TWO_LIN E 1
#define LCD_FONT58_FONT 511 0
#define LCD_DEC_INC_DDR AM 1
#define LCD_SHIFT_RIGHT _LEFT 0
#define LCD_DISPLAY_OFF _ON 1
#define LCD_CURSOR_OFF_ ON 1
#define LCD_CURSOR_BLIN K_OFF_ON 1
#define LCD_CURSOR_DISP LAY_SHIFT 0
остальные
вывод 1 - земля
вывод 2 - +5
вывод 3 - +5
Вы не могли бы мне подсказать что я не так сделал ? Или я мог бы выслать проект с моими настройками на указанный Вами адрес.
Спасибо
http://chipenable.ru/index.php/forum/materialy-sajta-chipenable/3245-vetka-dlya-vremennogo-khraneniya-proektov.html?start=50
ЗЫ Так же имеется дисплей 20х4 и тоже не хочет работать. Ув mmavka, можете поделиться допилинной библиотекой для сего дисплея?
../lcd_lib_2.c:78: warning: 'data' may be used uninitialized in this function
было
Code:
uint8_t data, tmp;
LCD_DirPort(LCD_PORT, 0x00);
стало
Code:
uint8_t data, tmp;
data = 0;
LCD_DirPort(LCD_PORT, 0x00);
Компилятору не нравится, что эта переменная не инициализирован а. Но я сделал это специально и как самый последний жлоб сэкономил два байта памяти) Инициализация этой переменной выполняется дальше с помощью макроса LCD_ReadPort(LC D_PORT, data);
и, кстати, отдельное спасибо за хорошие библиотеки - как начинающему это очень помогает
Например, когда нужно изменить значение - для удобства его хорошо бы выделять, курсором выделяется 1 цифра, а если их несколько в числе, красивее чтоб все число мигало
посмотри например "Учебный курс. 16 разрядный таймер/счетчик Т1." там вывод переменной на LCD, и файлы есть.
и пишешь например:
BCD_5IntLcd(АЦП переменная); //это на LCD
Code:
void LCD_ProgressBar(uint8_t state, uint8_t size)
{
uint8_t i, bLine, wLine;
bLine = (size * state)/100;
wLine = size - bLine;
for(i = 0; i < bLine; i++){
LCD_WriteData(0xff);
}
for(i = 0; i < wLine; i++){
LCD_WriteData(' ');
}
}
size - это размер прогресс бара (количество элементов). state - состояние прогресс бара в процентах.
Code:
LCD_Goto(0,0);
//прогресс бар из 10-и элементов
//3 элемента будут черные
LCD_ProgressBar(30, 10);
Если убрать расчет процентов, а задавать количество черных элементов, код будет компактнее.
#define LCD_DATA_0 D, 0, _NONE
#define LCD_DATA_1 D, 1, _NONE
#define LCD_DATA_2 D, 2, _NONE
#define LCD_DATA_3 D, 3, _NONE
#define LCD_DATA_4 D, 4, _HI
#define LCD_DATA_5 D, 3, _HI
#define LCD_DATA_6 D, 2, _HI
#define LCD_DATA_7 D, 1, _HI
//управляющие выводы LCD
#define LCD_RS D, 7, _HI
#define LCD_RW D, 6, _HI
#define LCD_EN D, 5, _HI
дисплей показывает мерцаюцие квадратики. Печаль-беда :cry:
Спасибо за прекрасные библиотеки ;-)
void LCD_SetUserChar (uint8_t __flash *sym, uint8_t adr)
Как я понимаю , надо создать массив Code:
sym [] ={0b11111,0b10001,0b10000,0b11110,0b10001,0b10001,0b11110,0b00000,};
(это русская буква Б)во флеш памяти с символами , в самой функции прописывать начало адреса символа в флеш памяти ? У меня еще сильный напряг с синтаксисом Си , так что если не сложно можно пример , хотя бы с тойже буквой Б ?
Огромное спасибо вам за материалы, примеры и библиотеки. Только начал изучать микроконтроллеры.
Подскажите, у меня дисплей 20х4, выше Dim писал что надо изменить дефайн на такой Code:
#define LCD_Goto(x,y) LCD_WriteCom((( ((y)&1)*0x40)+( (((y)&3)>>1)*0x 14)+(x))|128)
После этого у меня не компилируется, ругается на F_CPU, return type of main is not int, отсутвующие скобки и неверный суффикс Х в LCD_Goto.
В синтаксисе еще плохо разбираюсь. Почему так?
Заранее спасибо!
Code:
char data;
while (*str){
data = pgm_read_byte(str);
str++;
LCD_WriteData(data);
}
а нужно (можно) такой:
Code:
char data;
while (data = pgm_read_byte(str)){
str++;
LCD_WriteData(data);
}
Иначе нулевой конец ищется в оперативке.
в уже готовой железке в этой цепи стоит транзистор, делающий этот сигнал инверсивным, сам незнаю зачем, плата заводская, ставя в .h файле _LOW программа он все равно работает с высоким уровнем.
подскажите как поступить?
RSS feed for comments to this post