У меня такая проблема. Есть 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);
}
}
#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.
Объясните, пожалуйста, что я делаю не так?