реклама на сайте
подробности

 
 
> LCD дисплей KS0076, не могу инициализировать
Freeze Anti
сообщение Dec 10 2007, 05:52
Сообщение #1


Частый гость
**

Группа: Новичок
Сообщений: 153
Регистрация: 29-03-07
Из: Саратов
Пользователь №: 26 613



Здравствуйте.

У меня такая проблема. Есть LCD дисплей с контроллером KS0076, подключенный к микроконтроллеру ATmega32.

Я пытаюсь его инициализировать и вместо нужной мне строки символов получаю какие-то иероглифы вперемежку с черными прямоугольничками...

Вот текст программы, написанной в среде WinAVR...

Код
#include <avr/io.h>
#include <util/delay.h>

#define RD_1 PORTB |= 64 //PORTB = PORTB | 0b1000000 - RD = 1
#define RS_1 PORTB |= 16 //PORTB = PORTB | 0b0010000 - RS = 1
#define E_1 PORTB |= 32 //PORTB = PORTB | 0b0100000 - E = 1
#define RD_0 PORTB &= 63 //PORTB = PORTB & 0b0111111 - RD = 0
#define RS_0 PORTB &= 111 //PORTB = PORTB & 0b1101111 - RS = 0
#define E_0 PORTB &= 95 //PORTB = PORTB & 0b1011111 - E = 0

//Объявляем массив с адресами во внутренней памяти ЖК-модуля,
//соответствующими первой позиции в каждой из 4-х строк дисплея
const unsigned char addLUT[2] = {0x80, 0xC0};
unsigned char LCD_Address, LCD_Line; //Переменные для хранения
                                       //адреса позиции и номера строки ЖК-дисплея
char Buffer[15]; //Буфер для хранения строки, выводимой на дисплей

//Функция записи в ЖК-модуль полубайта
void WriteNibble(unsigned char data)
{
    RD_0; //Режим записи
    E_1; //Активируем передачу
    PORTB = (data & 0x0F); //Передаем данные
    E_0; //Завершаем передачу
    RD_1; //Режим чтения
    _delay_loop_2(5000); //Задержка 5 мс, чтобы ЖК-модуль имел
                          //достаточно времени на обработку данных
}

//Функция записи в ЖК-модуль байта
void WriteByte(unsigned char data)
{
    RD_0; //Режим записи
    E_1; //Активизируем передачу
    PORTB = (data >> 4); //Передаем старший полубайт
    E_0; //Завершаем передачу
    E_1; //Активизируем передачу
    PORTB = (data & 0xF); //Передаем младший полубайт
    E_0; //Завершаем передачу
    RD_1; //Режим чтения
    _delay_loop_2(3000); //Задержка 3мс, чтобы ЖК-модуль имел
                          //достаточно времени на обработку данных
}

//Функция перехода к первой позиции строки с номером LineNum
void GoToLine(char LineNum)
{
    RS_0; //Передача команды
    LCD_Address = addLUT[LineNum - 1]; //Определяем адрес строки
    WriteByte(LCD_Address); //и передаем его в ЖК-модуль
    RS_1; //Конец передачи команд
    LCD_Address = 0; //Обнуляем адрес
    LCD_Line = LineNum; //Устанавливаем текущую строку
}

//Функция очистки дисплея
void ClearLCD(void)
{
    RS_0; //Передача команды
    WriteByte(0x01); //Команда очистки, курсор перемещается
                      //в исходную позицию
    _delay_loop_2(10000); //Задержка 10мс, чтобы ЖК-модуль имел
                           //достаточно времени на обработку команды
    RS_1; //Конец передачи команд
    GoToLine(1); //Переходим к строке 1
}

//Функция установки текущей позиции col в строке row дисплея
void SetLCDPosition(char row, char col)
{
    RS_0; //Передача команды
    LCD_Address = addLUT[row - 1] + col; //Определяем позицию дисплея
    WriteByte(LCD_Address); //Записываем в ЖК-модуль адрес
    RS_1; //Конец передачи команды
    LCD_Line = row; //Устанавливаем текущую строку
}

//Функция отображения в текущей позиции на дисплее символа
void ShowChar(unsigned char c)
{
    RS_1; //Передача данных
    WriteByte(c); //Записываем символ
    LCD_Address++; //Увеличиваем адрес на 1
    switch(LCD_Address) //Определяем, произошел ли
                         //переход на новую строку дисплея
    {
        case 20:
            GoToLine(2);
            break;
        case 40:
            GoToLine(1);
            break;
    }
}

//Функция вывода на дисплей строки
void ShowStr(unsigned char *s)
{
    while(*s != 0)
        ShowChar(*s++);
}

//Функция инициализации ЖК-модуля
void InitLCD(void)
{
    RD_1; //предустановка управляющих сигналов
    E_0;
    RS_0;
    _delay_loop_2(50000); //Задержка на 50мс, чтобы ЖК-модуль
                           //имел достаточно времени на инициализацию
    WriteByte(0x33);
    _delay_loop_2(1100);
    WriteByte(0x33);
    WriteByte(0x33);
    WriteByte(0x38); //Определение параметров развертки и ширины шины данных сейчас 0x38 если не получится - попробовать 0x28
    WriteByte(0x01);
    WriteByte(0x10); //Устанавливаем режим смещения курсора
    WriteByte(0x06); //вправо, без сдвига содержимого дисплея
    WriteByte(0x0C); //Включаем дисплей, прячем курсор
    for(char i = 0x40; i < 0x5F; i++) //Инициализируем память
                                         //знакогенератора
    {
        _delay_loop_2(10000);
        RS_0;
        WriteByte(i);
        _delay_loop_2(10000);
        ShowChar(0);
    }
    RS_1; //Переходим в режим передачи данных
    SetLCDPosition(1, 4); //Переходим в первую строку дисплея
}

void main(void)
{
    DDRB = 0xFF; //Выводы 0 - 6 порта B - выходы (передача данных и управляющие сигналы)
    InitLCD(); //Инициализируем ЖК-дисплей
    while(1)
    {
        char Test[] = {0x53, 0x65, 0x63, 0xBF, 0x6F, 0xB3, 0x61, 0xC7, 0x00};
        char String[] = {0x63, 0xBF, 0x70, 0x6F, 0xBA, 0x61, 0x00};
        ClearLCD();
        ShowStr(Test);
        SetLCDPosition(2, 1);
        ShowStr(String);
        _delay_loop_2(10000);
    }
}


Данные передаются по четырем линиям, подключенным к PORTB, к этому же порту подключены и выводы, отвечающие за управляющие сигналы R/W, RS и ES.

Объясните, пожалуйста, что я делаю не так?


--------------------
!!! All you need is LOVE !!!
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Freeze Anti
сообщение Dec 12 2007, 05:32
Сообщение #2


Частый гость
**

Группа: Новичок
Сообщений: 153
Регистрация: 29-03-07
Из: Саратов
Пользователь №: 26 613



Мои изменения в программе таковы:

В функции WriteNibble я убрал задержку на 5 мс

Функцию InitLCD я переписал следующим образом
Код
//Функция инициализации ЖК-модуля
void InitLCD(void)
{
    RD_1; //предустановка управляющих сигналов
    E_0;
    RS_0;
    _delay_loop_2(50000); //Задержка на 50мс, чтобы ЖК-модуль
                           //имел достаточно времени на инициализацию
    WriteNibble(0x30);
    _delay_loop_2(4100);
    WritrNibble(0x30);
    _delay_loop_2(100);
    WriteNibble(0x30);
    WriteNibble(0x28); //Определение параметров развертки и ширины шины данных сейчас 0x38 если не получится - попробовать 0x28
    _delay_loop_2(5000);
    WriteByte(0x01);
    WriteByte(0x10); //Устанавливаем режим смещения курсора
    WriteByte(0x06); //вправо, без сдвига содержимого дисплея
    WriteByte(0x0C); //Включаем дисплей, прячем курсор
    for(char i = 0x40; i < 0x5F; i++) //Инициализируем память
                                         //знакогенератора
    {
        _delay_loop_2(10000);
        RS_0;
        WriteByte(i);
        _delay_loop_2(10000);
        ShowChar(0);
    }
    RS_1; //Переходим в режим передачи данных
    SetLCDPosition(1, 4); //Переходим в первую строку дисплея
}


Вот... и все равно не работает... симптомы все те же... я не понимаю, что я делаю не так...


--------------------
!!! All you need is LOVE !!!
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 12 2007, 10:00
Сообщение #3


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(Freeze Anti @ Dec 12 2007, 07:32) *
что я делаю не так...
1) PORTB = (data & 0xF); - тем самым вы не только выставляете данные, но и сбрасываете управляющие сигналы. Нужно бы PORTB = (data & 0x0F) | (PORTB & 0xF0);
2) аргументом _delay_loop2 является не время в микросекундах. Не зная частоты вашего кварца трудно сказать, какую реально задержку вы получаете. Используйте _delay_ms и _delay_mks.
3) Вы не используете чтение из дисплея. Поэтому выкиньте дерганье ногой RD.
4) Все команды, кроме очистки дисплея, исполняются за 40 мкс, очистка дисплея - за 1.6мс. Т.е. задержку в WriteByte можно уменьшить, а после посылки 0x01 в функциях InitLCD() и ClearLCD() добавить по дополнительной задержке 1.6мс.
5) Команда 0x01 в ClearLCD уже устанавливает курсор на начало, после этого не нужно GoToLine(1);
6) В порядке пожелания:
Код
#define E_1 PORTB |= (1 << 5) //PORTB = PORTB | 0b0100000 - E = 1
#define E_0 PORTB &= ~(1 << 5) //PORTB = PORTB & 0b11011111 - E = 0
Так вы не запутаетесь в битах.
7) В SetLCDPosition() вы первым делом ставите RS в 0. Зачем же в InitLCD вы перед вызовом SetLCDPosition() ставите его в 1? Ваша программа сильно упростится и станет более читабельной, если вы добавите функцию
Код
void WriteCommand(uint8_t byte)
{
     RS_0;   // command mode
     WriteByte(byte);
     RS_1;   // data mode
}
Т.е. дисплей после этой функции готов принимать команды и не нужно делать RS_1 перед каждым выводом информации.
8) Команды лучше задать в символьном виде, тоже повысит читаемость:
Код
#define   LCD_CLEAR    0x01
#define   LCD_SET_CURSOR   0x80
#define   LCD_SET_CG_PTR    0x40

9) Вы не используете знакогенератор, поэтому зачем его чистить? Когда будете использовать, грузить его можно как строку:
Код
//Функция вывода на дисплей строки из флеш
void ShowStr_P(prog_char *s)
{

    char C = pgm_read_byte(s++);
    while(C != 0)
    {
        ShowChar(C);
        C = pgm_read_byte(s++);
    }
}
prog_char const CharGen[][8] =
{
   0x01, 0x03, 0x07, 0x0F, 0x07, 0x03, 0x01, 0x00, // symbol 0 image, 8 bytes per symbol
   0x10, 0x18, 0x1C, 0x17, 0x1C, 0x18, 0x10, 0x00, // symbol 1 image, 8 bytes per symbol
   .........
};

void InitLCD(void)
{
.............
    WriteCommand(LCD_SET_CG_PTR | 0);   // write to CG RAM, starting at position 0
    ShowStr_P(CharGen);
..............
    WriteCommand(LCD_SET_CURSOR | 0);  //Переходим в первую строку дисплея
}

10)Непонятен комментарий "//Определение параметров развертки и ширины шины данных сейчас 0x38 если не получится - попробовать 0x28" У вас дисплей, судя по коду, подключен в 4-битном режиме, вам обязательно надо посылать 0x28 после 0x30, 0x30, 0x30.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 31st July 2025 - 00:21
Рейтинг@Mail.ru


Страница сгенерированна за 0.01403 секунд с 7
ELECTRONIX ©2004-2016