Re: Работа с ЖКИ на контроллере HD44780 и его аналогах
Добавлено: Сб янв 31, 2015 04:15:39
Потребление значительно меньше. Одна лапа MSP430 справляется:)
Здесь можно немножко помяукать :)
https://radiokot.ru/forum/
Есть сделанная плата с этим индикатором. Сделана так, что колодка выводов снизу, жестко впаяна в плату. Соответственно, при запуске индикатора оказалось что все символы вверх ногамиGudd-Head писал(а):как вы себе это представляете?
Вот я про это и спрашивал, что вы хотите там найти? Если только рисовать свои "перевёрнутые" символы.eess9 писал(а):Теперь сижу курю даташит.
Код: Выделить всё
#include "LCD.h"
#include <compiler_defs.h>
#include <SI_C8051F320_Register_Enums.h> // SFR declarations
#define DATABUS P1
#define DATABUS_CF P1MDOUT
sbit EN = P1^1;
sbit RW = P1^2;
sbit DC = P1^3;
/*
* ВСЕ МЕТОДЫ ДОЛЖНЫ БЫТЬ УВЕРЕНЫ, ЧТО РАБОТАЮТ В 8-БИТ РЕЖИМЕ
* ДРОБЕНИЕ НА ПОЛУБАЙТЫ ПРОИЗВОДИТЬ НЕПОСРЕДСТВЕННО В
* МЕТОДАХ GET DATA И SET DATA!!!
*/
//*************************************************************
void LCD_delay (void)//Маленькая задержка
{
TH1 = 0xFF;//Задержка ~60мкс
TL1 = 0xC0;//
TCON_TR1=1;//Запуск таймер 1
while(TCON_TF1==0);//Ожидание поднятия флага переполнения таймера 1
TCON_TR1=0;//Стоп таймер 1
TCON_TF1=0;//Сбросить флаг переполнения
}
unsigned char Get_Data (void)//Берем данные с дисплея.
{
unsigned char CH=0;
DATABUS_CF &= 0x0F; // Режим с открытым истоком регистр обнулить (кроме P1^0-P1^3, они не наши) 0000 1111
DATABUS |= 0xF0; // Данные на ввод, DB4-7 должны быть "1"
CH=DATABUS;
EN=1;
LCD_delay();//По идее задержка не нужна
EN=0;
return CH; // Взять данные
}
//*************************************************************
void Set_Data (unsigned char CH)//Отрпавить биты в порт
{
unsigned char temp=0x00;
temp = CH;
DATABUS_CF |= 0xF0;//Режим push pull Для левой части, то есть работаем на ВЫВОД
CH = CH | 0x0F;//Левая часть - первый полубайт. Правую ставим в "1", что бы не сбить EW, RW и DC
DATABUS &= CH; //Сперва отправим левую часть CH, так как она старше в DB7:DB4
EN=0;//
LCD_delay();//По идее задержка тут не нужна
EN=1;//Отправили первый полуйбайт
temp=temp<<4;//Сдвинем на 4 бита влево
temp = temp | 0x0F;//Левая часть - второй полубайт. Правую ставим в "1", что бы не сбить EW, RW и DC
DATABUS &= temp;
}
//*************************************************************
///////////////////////
xdata unsigned char IF_LCD;
//**********************************************************************
code const unsigned char LCDCODE[132] = {0xdb,0xd1,0xdc,0xd9,0x41,0xA0,0x42,0xa1,
0xe0,0x45,0xA3,0xA4,0xa5,0xa6,0x4b,0xa7,
0x4d,0x48,0x4f,0xa8,0x50,0x43,0x54,0xa9,
0xaa,0x58,0xe1,0xab,0xac,0xe2,0xad,0xae,
0x62,0xaf,0xb0,0xb1,0x61,0xb2,0xb3,0xb4,
0xe3,0x65,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,
0xbc,0xbd,0x6f,0xbe,0x70,0x63,0xbf,0x79,
0xe4,0x78,0xe5,0xc0,0xc1,0xe6,0xc2,0xc3,
0xc4,0xc5,0xc6,0xc7};
//**********************************************************************
void LCD_Init (void)
{
unsigned char i=0;
EN=0;
DC=0;//Работаем с командой
RW=0;
delay(1);//Стартовое ожидание не менее 20 мс, используем внешний делей на 100мс
//Тут мы еще в 8 бит режиме, передавать надо все сразу!!!
for (i=0;i<3;i++)
{
EN=1;
//DATABUS_CF &= 0x0F; // Режим с открытым истоком почему так? вроде же push pull надо?
DATABUS_CF |= 0xF0;//Режим push pull Для левой части
DATABUS |= 0x30;//0011 смотри даташит
EN=0;
LCD_delay();
}
EN=1;
//DATABUS_CF &= 0x0F; // Режим с открытым истоком почему так? вроде же push pull надо?
DATABUS_CF |= 0xF0;//Режим push pull Для левой части
DATABUS |= 0x20;//0010 смотри даташит, ставим разрядность
EN=0;
LCD_delay();
//Далее - уже 4 битный режим, можно проверять флаг занятости (см. даташит)
LCD_SetCom(0x28);//0010 100(P)0 Разрядность 4-бит, страница знакогенератора "0"(P)
LCD_SetCom(0x08);//0000 1000 Включение модуля, курсора нет, ничего не мигает
LCD_SetCom(0x01);//0000 0001 Очищает модуль и помещает курсор в самую левую позицию. Ждать не мене 1,5 мс
LCD_SetCom(0x06);//0000 0110 Курсор сдвигаеться вправо, сдвиг дисплея запрещен
//?????
//PROFIT!
}
//**********************************************************************
void LCD_Put (unsigned char DB)//Подготовить дисплей к приему команды. Без опроса BUSY но с задержкой, удобно для инициализации
{
DC=0;//Работаем с командой
RW=0;
EN=1;
Set_Data(DB);//Помещаем даныые в порт
LCD_delay();//Зачем ты тут?
EN=0;
}
//**********************************************************************
/*пример из lcd.h
* #define LCD_Reset() LCD_SetCom (0x38);LCD_SetCom (0x0E);LCD_SetCom (0x06);
*
*/
void LCD_SetCom (unsigned char DB)//Отправить команду на дисплей и убедиться в выполнении
{
EN=1;
DC=0;//Работаем с командой
RW=0;//Пишем внутрь
LCD_Put(DB);
LCD_Wait();
}
//**********************************************************************
void LCD_Wait (void)//Задержка и проверка BUSY
{
unsigned char CH;
volatile unsigned int TIMEOUT=15000;
DC=0;//Работаем с командой
EN=1;
RW=1;//Берем ИЗ дисплея
while (TIMEOUT--)
{
CH=Get_Data();
CH&=0x80;
if(CH==0) break;
}
EN=0;//Почему это тут??????
LCD_delay();//Зачем?
RW=0;//Хватит брать из дисплея
}
//**********************************************************************
void LCD_AddrStr (unsigned char X, unsigned char Y) // Set String Address поставить адрес строки
{
code unsigned char Offset[4] = {0x00,0x40,0x14,0x54};
LCD_SetCom (0x80|Offset[Y]|(X & 0x3F));
}
//**********************************************************************
unsigned char LCD_ReCode (unsigned char CH)//ПОлучает код символа из массива
{
if ((CH<0x20)&(CH!=0x0d)) return 0x20;
else if (CH==0x0d) return 0x7e;
else if ((CH<0xA7)&(CH< 0x7b)) return CH;
else if (CH>=0xc0) return LCDCODE[CH-0xc0+4];
}
//**********************************************************************
void LCD_WriteData (unsigned char DAT)//Записывает 1 символ
{
EN=1;
RW=0;//Отправляем в дисплей
DC=1;//Работаем с данными
Set_Data(LCD_ReCode(DAT));//Помещаем даные в порт
EN=0;
LCD_Wait();
DC=0;
}
//**********************************************************************
void LCD_String (char *s)//Записывает строку
{
register int i;
for (i=0; i<strlen(s); i++)
{
LCD_WriteData (s[i]);//Запись символа
LCD_delay();//И нахрена?
}
}
//**********************************************************************
void LCD_XYString (unsigned char STR, unsigned char NUM, char *s)//Записывает строку по адресу
{
LCD_AddrStr (NUM,STR);
LCD_String (s);
}
А никак - заземлил Uо и все. В ДШ проде бы написано, что это даст заводские настройки контрастности.А контраст вы как регулируете?
Не очень понял эту часть. Вроде же бы он один из этапов инициализации - полная очистка дисплея?Правильно инициализированный покажет вам две строки
В целом алгоритм работы устройства я изучил. Все более-менее понятно (за исключением, нужно ли делать задержку между пересылкой двух полубайт в 4-бит режиме.)ЕN - это строб импульс
Код: Выделить всё
LCD_Init();Код: Выделить всё
LCD_Put(0xBB);Код: Выделить всё
/*
* newLCD.c
*
* Created on: 21.02.2015
* Author: Богдан
*/
#include <compiler_defs.h>
#include <SI_C8051F320_Register_Enums.h> // SFR declarations
#define DATABUS P1
extern void delay(int);
void NLCD_delay(void);
void NLCD_init(void);
void NLCD_SetPort(unsigned char);
void NLCD_SetData(unsigned char);
void NLCD_SetCommand(unsigned char);
sbit EN = P1^1;
sbit RW = P1^2;
sbit DC = P1^3;
void NLCD_delay (void)
{
TH1 = 0xFF;//Задержка ~60мкс
TL1 = 0xC0;//
TCON_TR1=1;//Запуск таймер 1
while(TCON_TF1==0);//Ожидание поднятия флага переполнения таймера 1
TCON_TR1=0;//Стоп таймер 1
TCON_TF1=0;//Сбросить флаг переполнения
}
void NLCD_SetPort (unsigned char dat)
{
volatile int i=0;//Не оптимизируется компилятором
unsigned char temp=0x00;//Для манипуляций с данными
temp = dat;
dat = dat & 0xF0;//dat=XXXX0000 (где x - отправляемый полубайт)
DATABUS = DATABUS & 0x0F;//P1= 0000XXXX(где х - значения DC, RW, EN и P0.0)
DATABUS = DATABUS | dat; //Отправлена старшая часть байта
EN=1;//Строб вверх!
for (i=0;i<4;i++);//Маленькая задержка для 100% отправки данных
EN=0;//Строб опущен, дисплей принимает данные
temp=temp<<4;//Сдвинем на 4 бита влево проверь это
temp = temp & 0xF0;//dat=XXXX0000 (где x - отправляемый полубайт)
DATABUS = DATABUS & 0x0F;//P1= 0000XXXX(где х - значения DC, RW, EN и P0.0)
DATABUS = DATABUS | temp;//Отправлена младшая часть байта
EN=1;//Строб вверх!
for (i=0;i<4;i++);//Маленькая задержка для 100% отправки данных
EN=0;//Строб опущен, дисплей принимает данные
}
void NLCD_init()
{
//RW всегда держать 0;//Пока что мы будем писать только ВНУТРЬ
volatile int i=0,k=0;//Не оптимизируются компилятором
DATABUS=0x00;
delay(1);//Задержка 100 мс
//Далее - 8 бит режим
DATABUS = DATABUS | 0x30;//0011 смотри даташит
for (k=0;k<3;k++)
{
EN=1;//Строб вверх
for (i=0;i<4;i++);//Маленькая задержка для 100% отправки данных
EN=0;//Строб опущенн, дисплей принимает данные
NLCD_delay();
}
DATABUS = DATABUS & 0x0F;//P1= 0000XXXX(где х - значения DC, RW, EN и P0.0)
DATABUS = DATABUS | 0x20;//0010 смотри даташит, ставим разрядность
EN=1;//Строб вверх
for (i=0;i<4;i++);//Маленькая задержка для 100% отправки данных
EN=0;//Строб опущенн, дисплей принимает данные
NLCD_delay();
//Далее - уже 4 битный режим, можно проверять флаг занятости (см. даташит)
NLCD_SetCommand(0x28);//0010 100(P)0 Разрядность 4-бит, страница знакогенератора "0"(P)
NLCD_SetCommand(0x08);//0000 1000 Включение модуля, курсора нет, ничего не мигает
NLCD_SetCommand(0x01);//0000 0001 Очищает модуль и помещает курсор в самую левую позицию. Ждать не мене 1,5 мс
delay(1);
NLCD_SetCommand(0x06);//0000 0110 Курсор сдвигаеться вправо, сдвиг дисплея запрещен
}
void NLCD_SetData (unsigned char dat)
{
DC=1;//Работаем с данными
NLCD_SetPort (dat);
NLCD_delay();
}
void NLCD_SetCommand (unsigned char command)
{
DC=0;//Работаем с командой
NLCD_SetPort (command);
NLCD_delay();
}
На стр. 82 в посте от Пт янв 09, 2015 15:03:43 я давал ссылку на документацию на Русском языке. Делайте так, как сказано в pdf-е и проблем не будет.4elovek37 писал(а):Порядок настолько важен?
А ведь действительно, ни в родном ДШ на мой индикатор, ни в ДШ по ссылке из сообщения такой инфы нет!единственное, у них не написано про то, что после INIT-а надо дать команду "включить индикатор"