Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: LCD + ATmega8
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
Melandr
Доброго дня Всем! Думаю эта тема уже конкретно проработана на форуме, но нужного мне ответа не нашел. Пытаюсь подключить ЖКИ к контроллеру. Сначала пробовал использовать готовые библиотеки. Но ничего не получилось. Везде используется другая частота тактирования процессора, и я подозреваю, что я не попадаю в нужные временные задержки дл работы с ЖКИ. Прогу писал в GCC. Также запускал в Протеусе для проверки. Прога не заводилсь. Потом нашел исходничек маленький в CodeVision. Вот он:
CODE
/*****************************************************
This program was produced by the
CodeWizardAVR V2.05.0 Professional
Automatic Program Generator
© Copyright 1998-2010 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date : 28.04.2011
Author : NeVaDa
Company :
Comments:


Chip type : ATmega8
Program type : Application
AVR Core Clock frequency: 14,745600 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 256
*****************************************************/

#include <mega8.h>
//Библиотека для расчета задержки по времени
#include <delay.h>
// Alphanumeric LCD Module functions
#include <alcd.h>

// Declare your global variables here

void main(void)
{
// Declare your local variables here

// Input/Output Ports initialization
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTB=0x00;
DDRB=0x00;

// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0xFF;
DDRC=0xFF;

// Port D initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTD=0x00;
DDRD=0xFF;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
TCCR0=0x00;
TCNT0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer1 Stopped
// Mode: Normal top=0xFFFF
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer2 Stopped
// Mode: Normal top=0xFF
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
MCUCR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00;

// USART initialization
// USART disabled
UCSRB=0x00;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;

// ADC initialization
// ADC disabled
ADCSRA=0x00;

// SPI initialization
// SPI disabled
SPCR=0x00;

// TWI initialization
// TWI disabled
TWCR=0x00;

// Alphanumeric LCD initialization
// Connections specified in the
// Project|Configure|C Compiler|Libraries|Alphanumeric LCD menu:
// RS - PORTD Bit 2
// RD - PORTD Bit 1
// EN - PORTD Bit 3
// D4 - PORTD Bit 4
// D5 - PORTD Bit 5
// D6 - PORTD Bit 6
// D7 - PORTD Bit 7
// Characters/line: 16
delay_us(500);
lcd_init(16);

#asm("sei")
lcd_gotoxy (2,0);
lcd_putsf("HELLO,WORLD!");

while (1)
{
PORTC=0xFE;
delay_ms(1000);//задержка 1 секунда
PORTC=0xFF;
delay_ms(1000);//задержка 1 секунда
}
}

Светодиод поцепил, чтобы было видно что программа работает. В протеусе эта программа запустилась, но в железе изображения на ЖКИ нет. Регулирую контрастность на ЖКИ, все нормально, сначала темнее верхний ряд, потом нижний. Подскажите в чем может быть проблема? Заранее благодарен за ответ.
ЗЫ:Вылаживаю архив с исходником и проектом Протеус
Нажмите для просмотра прикрепленного файла
ЗЫ2:Хотелось бы написать программу в GCC, так в КодеВижене ничего не видно, что и как работает, а интересно разобраться в работе с ЖКИ. Если у кого то есть исходничек для работы с ЖКИ 44780 и ATmega8 с кварцем 14,745600 МГц, большая просьба выложить или дать нормальную ссылочку.
bav
видел где-то здесь

еще здесь
Сергей Борщ
QUOTE (Melandr @ Apr 29 2011, 01:30) *
ЗЫ2:Хотелось бы написать программу в GCC
Так давайте, пишите. Выкладывайте исходники, схему (только в читаемом виде - картинку, не у всех есть честно купленный протеус). Вместе посмотрим - что не получается и разберемся почему.
Melandr
Цитата(Сергей Борщ @ Apr 29 2011, 13:40) *
Так давайте, пишите. Выкладывайте исходники, схему (только в читаемом виде - картинку, не у всех есть честно купленный протеус). Вместе посмотрим - что не получается и разберемся почему.

Спасибо за отзывчивость, вылаживаю все исходные данные.
Вот код:
CODE

#include <avr/io.h> //библиотека ввода/вывода

#define RS 2 //RS=PD2 - сигнал управления ЖКИ
#define E 3 //E=PD3 - сигнал управления ЖКИ

#define TIME 10 //Константа временной задержки для ЖКИ
//Частота тактирование МК - 4Мгц

//Программа формирования задержки
void pause (long int a)
{ unsigned int i;

for (i=a;i>0;i--);
}

//Программа передачи команд в ЖКИ
void lcd_com (unsigned char lcd)
{ unsigned char temp;

temp=(lcd&~(1<<RS))|(1<<E); //RS=0 – это команда
PORTD=temp; //Выводим на portD старшую тетраду команды, сигналы RS, E
asm("nop"); //Небольшая задержка в 1 такт МК, для стабилизации
PORTD=temp&~(1<<E); //Сигнал записи команды

temp=((lcd*16)&~(1<<RS))|(1<<E); //RS=0 – это команда
PORTD=temp; //Выводим на portD младшую тетраду команды, сигналы RS, E
asm("nop"); //Небольшая задержка в 1 такт МК, для стабилизации
PORTD=temp&~(1<<E); //Сигнал записи команды

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

//Программа записи данных в ЖКИ
void lcd_dat (unsigned char lcd)
{ unsigned char temp;

temp=(lcd|(1<<RS))|(1<<E); //RS=1 – это данные
PORTD=temp; //Выводим на portD старшую тетраду данных, сигналы RS, E
asm("nop"); //Небольшая задержка в 1 такт МК, для стабилизации
PORTD=temp&~(1<<E); //Сигнал записи данных

temp=((lcd*16)|(1<<RS))|(1<<E); //RS=1 – это данные
PORTD=temp; //Выводим на portD младшую тетраду данных, сигналы RS, E
asm("nop"); //Небольшая задержка в 1 такт МК, для стабилизации
PORTD=temp&~(1<<E); //Сигнал записи данных

pause(TIME); //Пауза для вывода данных
}

//Программа иниализации ЖКИ
void lcd_init (void)
{
lcd_com(0x2c); //4-проводный интерфейс, 5x8 размер символа
pause(100*TIME);
lcd_com(0x0c); //Показать изображение, курсор не показывать
pause(100*TIME);
lcd_com(0x01); //Очистить DDRAM и установить курсор на 0x00
pause (100*TIME);
}

//Основная программа
int main(void)
{
DDRD=0xfc; //Инициализация portD
PORTD=0x00;

DDRC=0xFF;
PORTC=0xFF; //Инициализация portС

pause(1000); //Задержка, чтобы ЖКИ успел включиться
lcd_init(); //Инициализация ЖКИ


lcd_dat('w'); //Вывод "www.avrlab.com"
lcd_dat('w');
lcd_dat('w');
lcd_dat('.');
lcd_dat('a');
lcd_dat('v');
lcd_dat('r');
lcd_dat('l');
lcd_dat('a');
lcd_dat('b');
lcd_dat('.');
lcd_dat('c');
lcd_dat('o');
lcd_dat('m');

lcd_com(0xc0); //Ставим курсор на начало 2-й строки ЖКИ

lcd_dat('I'); //Записываем "It's so easy"
lcd_dat('t');
lcd_dat('"');
lcd_dat('s');
lcd_dat(' ');
lcd_dat('s');
lcd_dat('o');
lcd_dat(' ');
lcd_dat('e');
lcd_dat('a');
lcd_dat('s');
lcd_dat('y');


while (1)
{
PORTC=0xFE; //мигаем светодиодом для проверки работоспособности программы
pause(15000000);//задержка 0,5 секунда
PORTC=0xFF;
pause(15000000);//задержка 0,5 секунда
}

return 1;
}



Задержки конечно сделано уххх.. sm.gif, но не хочется заморачиваться с таймером, главное запустить ЖКИ. Значит эта программа мигает светодиодом что в железе, что в Протеус. Есть подозрения, что из-за смены частоты тактирования процессора (в исходном примере кварц был на 4 МГц, а у меня 14,745600МГц), изменились временные интервалы при работе с ЖКИ. Необходимо изменить переменную TEMP, но только на сколько и в какую сторону непонятно.

Выкладываю схему подключения
Нажмите для просмотра прикрепленного файла
Сергей Борщ
QUOTE (Melandr @ Apr 29 2011, 15:48) *
Задержки конечно сделано уххх.. sm.gif
При включении оптимизации от этой задержки останется пшик. Ибо она не делает ничего полезного с точки зрения компилятора - просто тупо делает хорошую быструю программу медленнее. используйте функции из <avr/delay.h>, для них можно указывать задержку в единицах времени и они не зависят от оптимизации (ну разве что совсем без оптимизации дают гораздо большую задержку).

QUOTE (Melandr @ Apr 29 2011, 15:48) *
Есть подозрения, что из-за смены частоты тактирования процессора (в исходном примере кварц был на 4 МГц, а у меня 14,745600МГц), изменились временные интервалы при работе с ЖКИ.
Вот от таких трудностей и защищена <avr/delay.h>. Изменился кварц - меняете строку #define F_CPU 4000000UL на #define F_CPU 14745600UL (или соответствующий параметр в makefile) а все остальное посчитает компилятор.

Чуть позже допишу по остальному коду, там есть мелкие недочеты и главное - неправильная последовательность инициализации. Гляньте вот эту ссылку пока: http://electronix.ru/forum/index.php?s=&am...st&p=143374
Melandr
Цитата(Сергей Борщ @ Apr 29 2011, 16:47) *
При включении оптимизации от этой задержки останется пшик. Ибо она не делает ничего полезного с точки зрения компилятора - просто тупо делает хорошую быструю программу медленнее. используйте функции из <avr/delay.h>, для них можно указывать задержку в единицах времени и они не зависят от оптимизации (ну разве что совсем без оптимизации дают гораздо большую задержку).

Оптимизацию я отключил, чтобы циклы компилятор не убрал. По поводу функции delay, функция хорошая, но там есть ограничение по задержке, вроде бы 768мкс/частоту кварца в МГц, соответственно задержка получается маленькой.

Мне непонятно не слишком ли маленькие задержки в одну оперцию asm "nop"?
defunct
Цитата(Melandr @ Apr 29 2011, 18:58) *
По поводу функции delay, функция хорошая, но там есть ограничение по задержке, вроде бы 768мкс/частоту кварца в МГц, соответственно задержка получается маленькой.

Это не функция, а модуль и там всяких разных функций "мульён".
delay_ms, delay_us, delay_cycles.
можно делать и большие и маленькие задержки.
Melandr
Почитал http://electronix.ru/forum/index.php?s=&am...st&p=143374, и решил линию управления RW переключить с GND на линию PD1. Поэтому если будут исходники с чтением состояния ЖКИ, очень хотелось бы ознакомиться.
=GM=
Начальную установку дисплея вы делаете неправильно. Основная проблема здесь в том, что по умолчанию при подаче питания дисплей устанавливается в 8-битный интерфейс, а если питание нехорошее, то он может вообще встать в неопределенное состояние. Поэтому на дисплей прежде всего надо подать команду 0х30 установки в режим 8-битного интерфейса. Рекомендуется подавать команду 3 раза. Тут надо учесть, что команду вы подаёте тетрадами, т.е. подавая команду 0х30, вы на самом деле подаёте две команды 0х3х и 0х0х, так что лучше подавать команду 0х33 два-три раза, без разницы. Затем можете подавать команду 0х20 для перехода в 4-битный интерфейс. Состояние дисплея читать пмсм без надобности.
Melandr
Вопрос по поводу питания. Если у меня напряжение питания 4,6 В, запустится ли ЖКИ? Также по поводу задержек, попробовать просимулировать, определить какие задержки, и скорректировать согласно даташиту?, или можно использовать те, что уже прописаны в программе?
Melandr
Как проверить флаг занятости, какая должна быть последовательность кода? Какие задержки?
Melandr
переписал немного программу, изменил процедуру инициализации ЖКИ, согласно рекомендациям на форуме. Вот код:
CODE

#include <avr/io.h> //библиотека ввода/вывода
#include <util/delay.h> //библиотека задержек

#define RW 1 //RW=PD1 - сигнал управления ЖКИ
#define RS 2 //RS=PD2 - сигнал управления ЖКИ
#define E 3 //E=PD3 - сигнал управления ЖКИ

//Программа передачи команд в ЖКИ
void lcd_com (unsigned char lcd)
{ unsigned char temp;

temp=(lcd&~(1<<RS))|(1<<E); //RS=0 – это команда
PORTD=temp; //Выводим на portD старшую тетраду команды, сигналы RS, E
_delay_us(2); //Небольшая задержка в 2 мкс, для стабилизации
PORTD=temp&~(1<<E); //Сигнал записи команды

temp=((lcd*16)&~(1<<RS))|(1<<E); //RS=0 – это команда
PORTD=temp; //Выводим на portD младшую тетраду команды, сигналы RS, E
_delay_us(2); //Небольшая задержка в 2 мкс, для стабилизации
PORTD=temp&~(1<<E); //Сигнал записи команды

_delay_us(100); //Пауза для выполнения команды
}

//Программа записи данных в ЖКИ
void lcd_dat (unsigned char lcd)
{ unsigned char temp;

temp=(lcd|(1<<RS))|(1<<E); //RS=1 – это данные
PORTD=temp; //Выводим на portD старшую тетраду данных, сигналы RS, E
_delay_us(2); //Небольшая задержка в 2 мкс, для стабилизации
PORTD=temp&~(1<<E); //Сигнал записи данных

temp=((lcd*16)|(1<<RS))|(1<<E); //RS=1 – это данные
PORTD=temp; //Выводим на portD младшую тетраду данных, сигналы RS, E
_delay_us(2); //Небольшая задержка в 2 мкс, для стабилизации
PORTD=temp&~(1<<E); //Сигнал записи данных

_delay_us(100); //Пауза для вывода данных
}

//Программа иниализации ЖКИ
void lcd_init (void)
{
_delay_ms(15);
lcd_com(0x33); //8-проводный интерфейс,
_delay_ms(4.1);
lcd_com(0x33); //8-проводный интерфейс,
_delay_us(100);
lcd_com(0x33); //8-проводный интерфейс,
_delay_us(100);
lcd_com(0x20); //4-проводный интерфейс,
lcd_com(0x08); // полное выключение дисплея
lcd_com(0x01); // очистка дисплея
_delay_us(100);
lcd_com(0x06); // сдвиг курсора вправо
lcd_com(0x0D); // включение дисплея дисплея, мигающий курсор
}

//Основная программа
int main(void)
{
DDRD=0xFE; //Инициализация portD
PORTD=0x00;

DDRC=0xFF;
PORTC=0xFF; //Инициализация portС

lcd_init(); //Инициализация ЖКИ


lcd_dat('w'); //Вывод "www.avrlab.com"
lcd_dat('w');
lcd_dat('w');
lcd_dat('.');
lcd_dat('a');
lcd_dat('v');
lcd_dat('r');
lcd_dat('l');
lcd_dat('a');
lcd_dat('b');
lcd_dat('.');
lcd_dat('c');
lcd_dat('o');
lcd_dat('m');

lcd_com(0xc0); //Ставим курсор на начало 2-й строки ЖКИ

lcd_dat('I'); //Записываем "It's so easy"
lcd_dat('t');
lcd_dat('"');
lcd_dat('s');
lcd_dat(' ');
lcd_dat('s');
lcd_dat('o');
lcd_dat(' ');
lcd_dat('e');
lcd_dat('a');
lcd_dat('s');
lcd_dat('y');


while (1)
{
PORTC=0xFE; //мигаем светодиодом для проверки работоспособности программы
_delay_ms(1000);//задержка 1 секунда
PORTC=0xFF;
_delay_ms(1000);//задержка 1 секунда
}

return 1;
}


Попробовал запустить в железе, светодиод мигает, а на экран ЖКИ информация не выводится. В протеусе тоже самое, на экране ничего нет. Ваши Комментарии ожидаю, в чем может быть проблема?
В протеусе выдало такие предупреждения
Нажмите для просмотра прикрепленного файла

Подключил сигнал управления RW к порту PD1, но почему-то вместо того чтобы быть в "0", в симуляторе PD1 находится в высоком состоянии. Что неправильно?
Melandr
Изменил код, получается линия RW при записи байта устанавливалась в "1", теперь код такой:
CODE

#include <avr/io.h> //библиотека ввода/вывода
#include <util/delay.h> //библиотека задержек

#define RW 1 //RW=PD1 - сигнал управления ЖКИ
#define RS 2 //RS=PD2 - сигнал управления ЖКИ
#define E 3 //E=PD3 - сигнал управления ЖКИ

//Программа передачи команд в ЖКИ
void lcd_com (unsigned char lcd)
{ unsigned char temp;

temp=((lcd&~(1<<RS))&~(1<<RW))|(1<<E); //RS=0 – это команда
PORTD=temp; //Выводим на portD старшую тетраду команды, сигналы RS, E
_delay_us(2); //Небольшая задержка в 2 мкс, для стабилизации
PORTD=temp&~(1<<E); //Сигнал записи команды

temp=((lcd*16)&~(1<<RS))|(1<<E); //RS=0 – это команда
PORTD=temp; //Выводим на portD младшую тетраду команды, сигналы RS, E
_delay_us(2); //Небольшая задержка в 2 мкс, для стабилизации
PORTD=temp&~(1<<E); //Сигнал записи команды

_delay_us(100); //Пауза для выполнения команды
}

//Программа записи данных в ЖКИ
void lcd_dat (unsigned char lcd)
{ unsigned char temp;

temp=((lcd&~(1<<RW))|(1<<RS))|(1<<E); //RS=1 – это данные
PORTD=temp; //Выводим на portD старшую тетраду данных, сигналы RS, E
_delay_us(2); //Небольшая задержка в 2 мкс, для стабилизации
PORTD=temp&~(1<<E); //Сигнал записи данных

temp=((lcd*16)|(1<<RS))|(1<<E); //RS=1 – это данные
PORTD=temp; //Выводим на portD младшую тетраду данных, сигналы RS, E
_delay_us(2); //Небольшая задержка в 2 мкс, для стабилизации
PORTD=temp&~(1<<E); //Сигнал записи данных

_delay_us(100); //Пауза для вывода данных
}

//Программа иниализации ЖКИ
void lcd_init (void)
{
_delay_ms(15);
lcd_com(0x33); //8-проводный интерфейс,
_delay_ms(4.1);
lcd_com(0x33); //8-проводный интерфейс,
_delay_us(100);
lcd_com(0x33); //8-проводный интерфейс,
_delay_us(100);
lcd_com(0x20); //4-проводный интерфейс,
lcd_com(0x08); // полное выключение дисплея
lcd_com(0x01); // очистка дисплея
_delay_us(100);
lcd_com(0x06); // сдвиг курсора вправо
lcd_com(0x0D); // включение дисплея дисплея, мигающий курсор
}

//Основная программа
int main(void)
{
DDRD=0xFE; //Инициализация portD
PORTD=0x00;

DDRC=0xFF;
PORTC=0xFF; //Инициализация portС

lcd_init(); //Инициализация ЖКИ


lcd_dat('w'); //Вывод "www.avrlab.com"
lcd_dat('w');
lcd_dat('w');
lcd_dat('.');
lcd_dat('a');
lcd_dat('v');
lcd_dat('r');
lcd_dat('l');
lcd_dat('a');
lcd_dat('b');
lcd_dat('.');
lcd_dat('c');
lcd_dat('o');
lcd_dat('m');

lcd_com(0xc0); //Ставим курсор на начало 2-й строки ЖКИ

lcd_dat('I'); //Записываем "It's so easy"
lcd_dat('t');
lcd_dat('"');
lcd_dat('s');
lcd_dat(' ');
lcd_dat('s');
lcd_dat('o');
lcd_dat(' ');
lcd_dat('e');
lcd_dat('a');
lcd_dat('s');
lcd_dat('y');


while (1)
{
PORTC=0xFE; //мигаем светодиодом для проверки работоспособности программы
_delay_ms(1000);//задержка 1 секунда
PORTC=0xFF;
_delay_ms(1000);//задержка 1 секунда
}

return 1;
}

в Протеусе теперь лог такой, но все равно ни в железе ни в протеусе не работает:
Нажмите для просмотра прикрепленного файла
Сергей Борщ
На вашей схеме Vee подключен к +питания. Так работать не будет. В первом сообщении вы писали, что регулировкой контрастности добиваететсь свечения верхнего ряда знакомест - вот в таком положении и оставьте регулировку. Насколько адекватен протеус в этом смыле - понятия не имею, подключите Vee к земле.
По программе - криминала не видно, разве что нет необходимости выключать дисплей (0x08) и команда 0x01 требует задержку 1.6мс минимум. Небольшой недочет - сдвигать lcd на 4 бита умножением на 16 не совсем красиво - есть команда сдвига: temp=((lcd << 4)&~(1<<RS))|(1<<E);
И проверьте, правильно ли вы указали частоту кварца в вашем проекте.
Melandr
Частоту кварца указал правильно. Сейчас подкоректирую программу и проверю. По поводу подсветки в протеусе подключил без подстроечного резистора, попробую поставить резистор.
roman_golovenkov
Попробуйте этот код, ток у меня на 16 меге. Все работает: ив Протеусе, и в железе.
CODE
#include <mega16.h>
#include <delay.h>

// Задание выводимой строки текста.
char flash *static_text = "Hello, world!";

// Задание регистров порта подключения ЖКИ-модуля.
#define LCD_PORT PORTD
#define LCD_DDR DDRD
// Задание номера бита порта для вывода сигнала Е.
#define LCD_E PORTD3
// Задание номера бита порта для вывода сигнала RS.
#define LCD_RS PORTD2

// Команда очистки экрана.
#define CLEAR_COMMAND 0b00000001

// Команда возврата курсора на начальную позицию.
#define HOME_COMMAND 0b00000010

// Команда выбора направления сдвига курсора и экрана:
// инкремент счетчика адреса,
// без сдвига изображения.
#define EMS_COMMAND 0b00000110

// Команда выбора отображения:
// изображение включено,
// курсор в виде подчерка выключен,
// курсор в виде мерцающего знакоместа выключен.
#define DISPLAY_COMMAND 0b00001100

// Команда задания сдвига курсора или экрана.
//#define SHIFT_COMMAND 0b0001xx--

// Команда инициализации и задания режима работы индикатора
// для 8-разрядного режима работы шины данных:
// 4-хразрядная шина данных.
// Здесь тетрады переставлены местами для корректной работы
// подпрограммы записи команды в ЖКИ-модуль.
#define INIT_8_COMMAND 0b00000010

// Команда инициализации и задания режима работы индикатора:
// использование двухстрочного режима отображения информации,
// матрица 5х8 точек,
// 4-хразрядная шина данных.
#define INIT_COMMAND 0b00101000

// Команда задания адреса в CGRAM.
#define CGRAM_COMMAND 0b01000000

// Команда задания адреса в DDRAM.
#define DDRAM_COMMAND 0b10000000

// Смещение первого знакоместа второй строки.
#define SECOND_ROW 0x40

// Количество одновременно отображаемых символов на ЖКИ.
#define TOTAL_CHARS 16

// Длительность программных задержек.
#define INIT_DELAY 50
#define INIT_CONTROL_DELAY 50
#define WAIT_LINE_DELAY 1
#define WRITE_DATA_DELAY 50
#define WRITE_DATA_LONG_DELAY 2000

// Переставляет тетрады в байте.
#pragma warn-
unsigned char swap(unsigned char data)
{
#asm
ld r30, Y
swap r30
#endasm
}
#pragma warn+

// Определение задержки для формирования сигналов на линиях.
#define lcd_wait_line() delay_us(WAIT_LINE_DELAY)

// Записывает данные в ЖКИ-модуль.
void _lcd_write_data(unsigned char data)
{
unsigned char lsn;

// Вывод данных на 4-хразрядную шину.

// Получение и вывод старшей тетрады.
lsn = LCD_PORT & 0x0F;
LCD_PORT = data & 0xF0 | lsn;

// Установка стробирующего сигнала Е.
LCD_PORT.LCD_E = 1;
// Задержка сигнала на линии.
lcd_wait_line();
// Снятие стробирующего сигнала Е.
LCD_PORT.LCD_E = 0;
// Задержка сигнала на линии.
lcd_wait_line();

// Получение и вывод младшей тетрады.
LCD_PORT = swap(data) & 0xF0 | lsn;

// Установка стробирующего сигнала Е.
LCD_PORT.LCD_E = 1;
// Задержка сигнала на линии.
lcd_wait_line();
// Снятие стробирующего сигнала Е.
LCD_PORT.LCD_E = 0;
// Задержка сигнала на линии.
lcd_wait_line();

// Формирование задержки для ожидания выполнения команды ЖКИ-модулем.
if (!LCD_PORT.LCD_RS && (CLEAR_COMMAND == data || HOME_COMMAND == data))
{
delay_us(WRITE_DATA_LONG_DELAY);
}
else
{
delay_us(WRITE_DATA_DELAY);
}
}

// Записывает команду в регистр IR ЖКИ-модуля.
void lcd_control(unsigned char control)
{
// Установка линии RS в низкое состояние - сигнал записи команды.
LCD_PORT.LCD_RS = 0;
// Задержка сигнала на линии.
lcd_wait_line();
_lcd_write_data(control);
}

// Записывает команду в регистр IR ЖКИ-модуля при инициализации.
void lcd_init_control(unsigned char control)
{
lcd_control(control);
// Задержка при инициализации должна быть больше.
delay_ms(INIT_CONTROL_DELAY);
}

// Записывает символ в регистр DR ЖКИ-модуля.
void lcd_putchar(unsigned char c)
{
// Установка линии RS в высокое состояние - сигнал записи данных.
LCD_PORT.LCD_RS = 1;
// Задержка сигнала на линии.
lcd_wait_line();
_lcd_write_data©;
}

// Инициализирует ЖКИ-модуль.
void lcd_init(void)
{
// Порт подключения ЖКИ-модуля работает на вывод.
LCD_DDR |= 0b11111100;

// Предварительная задержка.
delay_ms(INIT_DELAY);
// Отправка команды инициализации для 8-разрядного режима работы шины
// данных, переключение на 4-хразрядную шину.
lcd_init_control(INIT_8_COMMAND);
// Отправка команды инициализации уже для 4-хразрядного режима.
lcd_init_control(INIT_COMMAND);
// Повторная отправка команды инициализации.
lcd_init_control(INIT_COMMAND);
// Задание режима отображения.
lcd_init_control(DISPLAY_COMMAND);
// Очистка экрана.
lcd_init_control(CLEAR_COMMAND);
// Выбор направления сдвига курсора и экрана.
lcd_init_control(EMS_COMMAND);
}

// Записывает строку для отображения из памяти даных в ЖКИ-модуль.
#pragma used+
void lcd_puts(char *str)
{
char c;
#pragma warn-
while (c = *str++)
{
#pragma warn+
lcd_putchar©;
}
}
#pragma used-

// Записывает строку для отображения из памяти программ в ЖКИ-модуль.
#pragma used+
void lcd_putsf(char flash *str)
{
char c;
#pragma warn-
while (c = *str++)
{
#pragma warn+
lcd_putchar©;
}
}
#pragma used-

void main(void)
{
// Инициализация ЖКИ-модуля.
lcd_init();

// Вывод заданного текста в первой строке с первого знакоместа.
lcd_putsf(static_text);

// Переключение на четвёртое знакоместо второй строки.
lcd_control(DDRAM_COMMAND + SECOND_ROW + 3);

// Вывод заданного текста во второй строке с четвёртого знакоместа.
lcd_putsf(static_text);

for (;;)
{
}
Genadi Zawidowski
Цитата(Melandr @ Apr 29 2011, 21:12) *
Почитал http://electronix.ru/forum/index.php?s=&am...st&p=143374, и решил линию управления RW переключить с GND на линию PD1. Поэтому если будут исходники с чтением состояния ЖКИ, очень хотелось бы ознакомиться.


Вот работающий проект - разберётесь. WinAWR или атмеловский тулчейн. Интересующая Вас часть (работа с проверкой готовности) находится в файле hd44780.c
Melandr
Цитата(roman_golovenkov @ May 2 2011, 16:51) *
Попробуйте этот код, ток у меня на 16 меге. Все работает: ив Протеусе, и в железе.

У Вас компилятор IAR, а то я пытаюсь скомпилить в AVRStudio, а он ругается?

Цитата(Genadi Zawidowski @ May 3 2011, 00:41) *
Вот работающий проект - разберётесь. WinAWR или атмеловский тулчейн. Интересующая Вас часть (работа с проверкой готовности) находится в файле hd44780.c

Спасибо буду разбираться с Вашим исходником.
roman_golovenkov
Цитата
У Вас компилятор IAR, а то я пытаюсь скомпилить в AVRStudio, а он ругается?


Компилировал в CoDeVision
XVR
Вот это -
Код
temp=(lcd|(1<<RS))|(1<<E);
и все остальные манипуляции с lcd - неправильные
Нужно маскировать старшую часть lcd, иначе она у вас накладывается на управляющие сигналы:
Код
temp=((lcd&0x0F)|(1<<RS))|(1<<E);

Сергей Борщ
QUOTE (XVR @ May 3 2011, 13:18) *
иначе она у вас накладывается на управляющие сигналы:
Там маскируются те биты, для которых управляющие сигналы сброшены. А для тех, которые надо выставлять - совершенно неважно, была там единица или нет. Да, некрасиво, но работать должно.
XVR
Цитата(Сергей Борщ @ May 3 2011, 14:50) *
Там маскируются те биты, для которых управляющие сигналы сброшены. А для тех, которые надо выставлять - совершенно неважно, была там единица или нет.
Не маскируются вообще никакие биты. В частности бит E (там, где он стоять не должен)
Цитата
Да, некрасиво, но работать должно.
Неа, точнее не везде rolleyes.gif
Сергей Борщ
QUOTE (XVR @ May 3 2011, 16:41) *
Не маскируются вообще никакие биты. В частности бит E (там, где он стоять не должен)

Читаем по губам:
QUOTE (Melandr @ Apr 29 2011, 15:48) *
CODE
  temp=(lcd&~(1<<RS))|(1<<E);        //RS=0 – это команда
  PORTD=temp;                            //Выводим на portD старшую тетраду данных, сигналы RS, E  
   asm("nop");                        //Небольшая задержка в 1 такт МК, для стабилизации
  PORTD=temp&~(1<<E);                    //Сигнал записи данных
В первой строке (lcd&~(1<<RS)) маскируется RS, а E стоять должен и он стоять будет: |(1<<E). В последней E маскируется и в порт записывается число со сброшенным битом E

QUOTE (Melandr @ Apr 29 2011, 15:48) *
CODE
  temp=((lcd*16)&~(1<<RS))|(1<<E);    //RS=0 – это команда
  PORTD=temp;                            //Выводим на portD младшую тетраду команды, сигналы RS, E
В первой строке ((lcd*16)&~(1<<RS)) также сбрасывается RS, хотя он и так сброшен в процессе lcd*16, а E безусловно взводится.

QUOTE (XVR @ May 3 2011, 16:41) *
Неа, точнее не везде rolleyes.gif
Ну да, там где нужны остальные биты порта такая конструкция принесет приятные smile3046.gif сюрпризы.
XVR
Да, действительно. Не заметил sad.gif
Все равно это не комильфо sm.gif
Melandr
Я так понимаю, что хоть программа написана не сильно красиво, но должна работать? Я сам заметил, что немного неудобно манипулировать управляющими линиями ЖКИ, и одновременно передавать данные, но у меня сейчас стоит задача запустить ЖКИ, а дальше оптимизировать и улучшать код.

Цитата(roman_golovenkov @ May 2 2011, 16:51) *
Попробуйте этот код, ток у меня на 16 меге. Все работает: ив Протеусе, и в железе.


Так скомпилил в CodeVision, немного изменил, для мигания светодиодом. В протеусе запустил все норм, на экране в протеусе появилась надпись. В железе светодиод мигает, а изображения нет. Есть подозрение, что шлейф соединяющий отладочную плату с ЖКИ, не передает все сигналы. Так как изображения нет, но контрастность регулируется в верхней строке. Завтра прикуплю разьемы на шлейф, и переделаю.
Melandr
Цитата(roman_golovenkov @ May 2 2011, 16:51) *
Попробуйте этот код, ток у меня на 16 меге. Все работает: ив Протеусе, и в железе.

Все норм, спасибо. Заработало в железе, после того как шлейф переделал. Мой код правда не работает буду разбираться со своим кодом.
Melandr
Переделал код CodeVision под WinAVR. Вот код:
CODE

#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>

// Задание выводимой строки текста.
char *static_text PROGMEM = "Hello, world!";

// Задание регистров порта подключения ЖКИ-модуля.
#define LCD_PORT PORTD
#define LCD_DDR DDRD
// Задание номера бита порта для вывода сигнала Е.
#define LCD_E PD3
// Задание номера бита порта для вывода сигнала RS.
#define LCD_RS PD2
// Задание номера бита порта для вывода сигнала RW
#define LCD_RW PD1
//Задание регистров порта для светодиода
#define LED_PORT PORTC
#define LED_DDR DDRC
//Задание номера бита порта для светодиода
#define LED PC0

// Команда очистки экрана.
#define CLEAR_COMMAND 0b00000001

// Команда возврата курсора на начальную позицию.
#define HOME_COMMAND 0b00000010

// Команда выбора направления сдвига курсора и экрана:
// инкремент счетчика адреса,
// без сдвига изображения.
#define EMS_COMMAND 0b00000110

// Команда выбора отображения:
// изображение включено,
// курсор в виде подчерка выключен,
// курсор в виде мерцающего знакоместа выключен.
#define DISPLAY_COMMAND 0b00001100

// Команда задания сдвига курсора или экрана.
//#define SHIFT_COMMAND 0b0001xx--

// Команда инициализации и задания режима работы индикатора
// для 8-разрядного режима работы шины данных:
// 4-хразрядная шина данных.
// Здесь тетрады переставлены местами для корректной работы
// подпрограммы записи команды в ЖКИ-модуль.
#define INIT_8_COMMAND 0b00000010

// Команда инициализации и задания режима работы индикатора:
// использование двухстрочного режима отображения информации,
// матрица 5х8 точек,
// 4-хразрядная шина данных.
#define INIT_COMMAND 0b00101000

// Команда задания адреса в CGRAM.
#define CGRAM_COMMAND 0b01000000

// Команда задания адреса в DDRAM.
#define DDRAM_COMMAND 0b10000000

// Смещение первого знакоместа второй строки.
#define SECOND_ROW 0x40

// Количество одновременно отображаемых символов на ЖКИ.
#define TOTAL_CHARS 16

// Длительность программных задержек.
#define INIT_DELAY 50
#define INIT_CONTROL_DELAY 50
#define WAIT_LINE_DELAY 1
#define WRITE_DATA_DELAY 50
#define WRITE_DATA_LONG_DELAY 2000

// Переставляет тетрады в байте.
unsigned char swap(unsigned char data)
{
asm(
"swap %0":
"=r" (data):
"0" (data)
);
return data;
}

// Определение задержки для формирования сигналов на линиях.
#define lcd_wait_line() _delay_us(WAIT_LINE_DELAY)

// Записывает данные в ЖКИ-модуль.
void _lcd_write_data(unsigned char data)
{
unsigned char lsn;

// Вывод данных на 4-хразрядную шину.

// Получение и вывод старшей тетрады.
lsn = LCD_PORT & 0x0F;
LCD_PORT = (data & 0xF0) | lsn;

// Установка стробирующего сигнала Е.
LCD_PORT |=(1<<LCD_E);
// Задержка сигнала на линии.
lcd_wait_line();
// Снятие стробирующего сигнала Е.
LCD_PORT &= ~(1<<LCD_E);
// Задержка сигнала на линии.
lcd_wait_line();

// Получение и вывод младшей тетрады.
LCD_PORT = (swap(data) & 0xF0) | lsn;

// Установка стробирующего сигнала Е.
LCD_PORT |= (1<<LCD_E);
// Задержка сигнала на линии.
lcd_wait_line();
// Снятие стробирующего сигнала Е.
LCD_PORT &= ~(1<<LCD_E);
// Задержка сигнала на линии.
lcd_wait_line();

// Формирование задержки для ожидания выполнения команды ЖКИ-модулем.
if (!LCD_RS && (CLEAR_COMMAND == data || HOME_COMMAND == data))
{
_delay_us(WRITE_DATA_LONG_DELAY);
}
else
{
_delay_us(WRITE_DATA_DELAY);
}
}

// Записывает команду в регистр IR ЖКИ-модуля.
void lcd_control(unsigned char control)
{
// Установка линии RS в низкое состояние - сигнал записи команды.
LCD_PORT &= ~(1<<LCD_RS);
// Задержка сигнала на линии.
lcd_wait_line();
_lcd_write_data(control);
}

// Записывает команду в регистр IR ЖКИ-модуля при инициализации.
void lcd_init_control(unsigned char control)
{
lcd_control(control);
// Задержка при инициализации должна быть больше.
_delay_ms(INIT_CONTROL_DELAY);
}

// Записывает символ в регистр DR ЖКИ-модуля.
void lcd_putchar(unsigned char c)
{
// Установка линии RS в высокое состояние - сигнал записи данных.
LCD_PORT |= (1<<LCD_RS);
// Задержка сигнала на линии.
lcd_wait_line();
_lcd_write_data©;
}

// Инициализирует ЖКИ-модуль.
void lcd_init(void)
{
// Порт подключения ЖКИ-модуля работает на вывод.
LCD_DDR |= 0b11111100;

// Предварительная задержка.
_delay_ms(INIT_DELAY);
// Отправка команды инициализации для 8-разрядного режима работы шины
// данных, переключение на 4-хразрядную шину.
lcd_init_control(INIT_8_COMMAND);
// Отправка команды инициализации уже для 4-хразрядного режима.
lcd_init_control(INIT_COMMAND);
// Повторная отправка команды инициализации.
lcd_init_control(INIT_COMMAND);
// Задание режима отображения.
lcd_init_control(DISPLAY_COMMAND);
// Очистка экрана.
lcd_init_control(CLEAR_COMMAND);
// Выбор направления сдвига курсора и экрана.
lcd_init_control(EMS_COMMAND);
}

// Записывает строку для отображения из памяти даных в ЖКИ-модуль.
void lcd_puts(char *str)
{
char c;
while (c = *str++)
{
lcd_putchar©;
}
}

// Записывает строку для отображения из памяти программ в ЖКИ-модуль.
void lcd_putsf(char *str)
{
char c;
while (c = *str++)
{
lcd_putchar©;
}
}

int main(void)
{
// Инициализация ЖКИ-модуля.
lcd_init();

// Вывод заданного текста в первой строке с первого знакоместа.
lcd_putsf(static_text);

// Переключение на четвёртое знакоместо второй строки.
lcd_control(DDRAM_COMMAND + SECOND_ROW + 3);

// Вывод заданного текста во второй строке с четвёртого знакоместа.
lcd_putsf(static_text);

//Конфигурираем порт для мигания светодиодом
LED_DDR |= 0b11111111;

for (;;)
{
//Мигаем светодиодом для проверки работоспособности программы
LED_PORT |= (1<<LED);
_delay_ms(1000); //задержка 1 секунда
LED_PORT &= ~(1<<LED);
_delay_ms(1000); //задержка 1 секунда
}
return 0;
}


Выдает в строке
while (c = *str++)
такое предупреждение warning: suggest parentheses around assignment used as truth value
Также непонятно как использовать флеш память в функции

CODE

// Записывает строку для отображения из памяти программ в ЖКИ-модуль.
void lcd_putsf(char *str)
{
char c;
while (c = *str++)
{
lcd_putchar©;
}
}

Кто может подскажите.
=GM=
Компилятор ожидает логическое выражение в операторе while (c = *str++).

Не знаю логики программы, возможно, должно быть while (c == *str++)
Melandr
Цитата(=GM= @ May 7 2011, 14:44) *
Не знаю логики программы, возможно, должно быть while (c == *str++)


Код для CodeVision записан выше на странице, он нормально работает. Я просто переделываю код под WinAVR. Дело в том, что в коде для CodeVision для этого выражения отключены предупреждения компилятора. Я так понимаю это выражение служит для обработки строки символов в цикле. А выходом из цикла является символ конца строки "\0". Но WinAVR дает предупреждение, а не ошибку. А код не работает.
SysRq
Из памяти программ читать удобно чем-либо из WinAVR\avr\include\avr\pgmspace.h.

--

Насчёт предупреждения, - поставьте ещё скобки, вот так вот: while(( )). Явно показываем компилятору что мы не ошиблись, и на ноль\не ноль проверяем действительно результат операции присваивания.
Genadi Zawidowski
Цитата(Melandr @ May 7 2011, 14:21) *
Переделал код CodeVision под WinAVR. Вот код:
...
Кто может подскажите.

Вот странно... Человеку дали рабочий проект, под WinAWR. Вместо этого берётся драчёвый напильник и шлифуется плохопортируемый кусок кода, без изначально требуемой проверки готовности. Уж и комментарии на русском были. Просто скажите, что не устроило?
Да, в Вашем коде в ПЗУ размещяется указатель на тестовую строку, а не сама строка.
Melandr
Цитата(Genadi Zawidowski @ May 7 2011, 20:42) *
Вот странно... Человеку дали рабочий проект, под WinAWR. Вместо этого берётся драчёвый напильник и шлифуется плохопортируемый кусок кода, без изначально требуемой проверки готовности. Уж и комментарии на русском были. Просто скажите, что не устроило?

Скажу честно, я начинающий программист на СИ, потому с Вашим кодом сложнее разобраться, и я иду по пути наименьшего сопротивления. Сначала разбираюсь с менее сложным кодом, просто код на CodeVision уже работает сразу после компиляции, и я решил , что с наименьшими затратами портирую его на WinAVR. А потом буду уже разбираться с Вашим кодом, так как в нем есть опрос ЖКИ на предмет готовности. А у Вас готовый проект, сложнее разобраться. Но все равно спасибо за помощь. Я просто хочу сделать отдельную библиотеек для ЖКИ, а потом просто подключать хидер в другие проекты.
Melandr
Не могу понять где ошибка в коде, вроде изменил все, но изображение не выводится?
CODE

#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>

// Задание выводимой строки текста.
PROGMEM char static_text[] = "Hello, world!";

// Задание регистров порта подключения ЖКИ-модуля.
#define LCD_PORT PORTD
#define LCD_DDR DDRD
// Задание номера бита порта для вывода сигнала Е.
#define LCD_E PD3
// Задание номера бита порта для вывода сигнала RS.
#define LCD_RS PD2
// Задание номера бита порта для вывода сигнала RW
#define LCD_RW PD1
//Задание регистров порта для светодиода
#define LED_PORT PORTC
#define LED_DDR DDRC
//Задание номера бита порта для светодиода
#define LED PC0

// Команда очистки экрана.
#define CLEAR_COMMAND 0b00000001

// Команда возврата курсора на начальную позицию.
#define HOME_COMMAND 0b00000010

// Команда выбора направления сдвига курсора и экрана:
// инкремент счетчика адреса,
// без сдвига изображения.
#define EMS_COMMAND 0b00000110

// Команда выбора отображения:
// изображение включено,
// курсор в виде подчерка выключен,
// курсор в виде мерцающего знакоместа выключен.
#define DISPLAY_COMMAND 0b00001100

// Команда задания сдвига курсора или экрана.
//#define SHIFT_COMMAND 0b0001xx--

// Команда инициализации и задания режима работы индикатора
// для 8-разрядного режима работы шины данных:
// 4-хразрядная шина данных.
// Здесь тетрады переставлены местами для корректной работы
// подпрограммы записи команды в ЖКИ-модуль.
#define INIT_8_COMMAND 0b00000010

// Команда инициализации и задания режима работы индикатора:
// использование двухстрочного режима отображения информации,
// матрица 5х8 точек,
// 4-хразрядная шина данных.
#define INIT_COMMAND 0b00101000

// Команда задания адреса в CGRAM.
#define CGRAM_COMMAND 0b01000000

// Команда задания адреса в DDRAM.
#define DDRAM_COMMAND 0b10000000

// Смещение первого знакоместа второй строки.
#define SECOND_ROW 0x40

// Количество одновременно отображаемых символов на ЖКИ.
#define TOTAL_CHARS 16

// Длительность программных задержек.
#define INIT_DELAY 50
#define INIT_CONTROL_DELAY 50
#define WAIT_LINE_DELAY 1
#define WRITE_DATA_DELAY 50
#define WRITE_DATA_LONG_DELAY 2000

// Переставляет тетрады в байте.
unsigned char swap(unsigned char data)
{
asm(
"swap %0":
"=r" (data):
"0" (data)
);
return data;
}

// Определение задержки для формирования сигналов на линиях.
#define lcd_wait_line() _delay_us(WAIT_LINE_DELAY)

// Записывает данные в ЖКИ-модуль.
void _lcd_write_data(unsigned char data)
{
unsigned char lsn;

// Вывод данных на 4-хразрядную шину.

// Получение и вывод старшей тетрады.
lsn = LCD_PORT & 0x0F;
LCD_PORT = (data & 0xF0) | lsn;

// Установка стробирующего сигнала Е.
LCD_PORT |=(1<<LCD_E);
// Задержка сигнала на линии.
lcd_wait_line();
// Снятие стробирующего сигнала Е.
LCD_PORT &= ~(1<<LCD_E);
// Задержка сигнала на линии.
lcd_wait_line();

// Получение и вывод младшей тетрады.
LCD_PORT = (swap(data) & 0xF0) | lsn;

// Установка стробирующего сигнала Е.
LCD_PORT |= (1<<LCD_E);
// Задержка сигнала на линии.
lcd_wait_line();
// Снятие стробирующего сигнала Е.
LCD_PORT &= ~(1<<LCD_E);
// Задержка сигнала на линии.
lcd_wait_line();

// Формирование задержки для ожидания выполнения команды ЖКИ-модулем.
if (!LCD_RS && (CLEAR_COMMAND == data || HOME_COMMAND == data))
{
_delay_us(WRITE_DATA_LONG_DELAY);
}
else
{
_delay_us(WRITE_DATA_DELAY);
}
}

// Записывает команду в регистр IR ЖКИ-модуля.
void lcd_control(unsigned char control)
{
// Установка линии RS в низкое состояние - сигнал записи команды.
LCD_PORT &= ~(1<<LCD_RS);
// Задержка сигнала на линии.
lcd_wait_line();
_lcd_write_data(control);
}

// Записывает команду в регистр IR ЖКИ-модуля при инициализации.
void lcd_init_control(unsigned char control)
{
lcd_control(control);
// Задержка при инициализации должна быть больше.
_delay_ms(INIT_CONTROL_DELAY);
}

// Записывает символ в регистр DR ЖКИ-модуля.
void lcd_putchar(unsigned char c)
{
// Установка линии RS в высокое состояние - сигнал записи данных.
LCD_PORT |= (1<<LCD_RS);
// Задержка сигнала на линии.
lcd_wait_line();
_lcd_write_data©;
}

// Инициализирует ЖКИ-модуль.
void lcd_init(void)
{
// Порт подключения ЖКИ-модуля работает на вывод.
LCD_DDR |= 0b11111100;

// Предварительная задержка.
_delay_ms(INIT_DELAY);
// Отправка команды инициализации для 8-разрядного режима работы шины
// данных, переключение на 4-хразрядную шину.
lcd_init_control(INIT_8_COMMAND);
// Отправка команды инициализации уже для 4-хразрядного режима.
lcd_init_control(INIT_COMMAND);
// Повторная отправка команды инициализации.
lcd_init_control(INIT_COMMAND);
// Задание режима отображения.
lcd_init_control(DISPLAY_COMMAND);
// Очистка экрана.
lcd_init_control(CLEAR_COMMAND);
// Выбор направления сдвига курсора и экрана.
lcd_init_control(EMS_COMMAND);
}

// Записывает строку для отображения из памяти даных в ЖКИ-модуль.
void lcd_puts(char *str)
{
char c;
while (*str!='\0')
{
c = *str;
lcd_putchar©;
str++;
}
}

// Записывает строку для отображения из памяти программ в ЖКИ-модуль.
void lcd_putsf(PROGMEM char *str)
{
char c;
while (pgm_read_byte(str)!='\0')
{
c = pgm_read_byte(str);
lcd_putchar©;
str++;
}
}

int main(void)
{
// Инициализация ЖКИ-модуля.
lcd_init();

// Вывод заданного текста в первой строке с первого знакоместа.
lcd_putsf(static_text);

// Переключение на четвёртое знакоместо второй строки.
lcd_control(DDRAM_COMMAND + SECOND_ROW + 3);

// Вывод заданного текста во второй строке с четвёртого знакоместа.
lcd_putsf(static_text);

//Конфигурираем порт для мигания светодиодом
LED_DDR |= 0b11111111;

for (;;)
{
//Мигаем светодиодом для проверки работоспособности программы
LED_PORT |= (1<<LED);
_delay_ms(1000); //задержка 1 секунда
LED_PORT &= ~(1<<LED);
_delay_ms(1000); //задержка 1 секунда
}
return 0;
}

Melandr
Что-то все умерли? Все молчат, программу запустил с выводом символа из памяти данных, т.е. из ОЗУ. При выводе строки из памяти программ какой-то трабл. Не могли бы посмотреть по коду. Нужно ли вызывать функцию pgm_read_byte или pgm_read-word? Заранее благодарен за ответ
Сергей Борщ
Так праздник у цивилизованных людей.
QUOTE (Melandr @ May 9 2011, 11:35) *
программу запустил с выводом символа из памяти данных, т.е. из ОЗУ. При выводе строки из памяти программ какой-то трабл. Не могли бы посмотреть по коду. Нужно ли вызывать функцию pgm_read_byte или pgm_read-word?
Нормально все в вашем исходнике. Символ занимает в памяти байт, вы правильно используете pgm_read_byte(). Должно работать. Прикрепите к сообщению архив с проектом (и с выходными файлами), возможно проблема не в исходнике. Вот моя функция вывода, как видите - практически идентична вашей:
CODE
template <uint_fast8_t size_x, uint_fast8_t size_y>
void lcd_t<size_x, size_y>::put_P(PGM_P pString)
{
    char c;
    while( (c = pgm_read_byte(pString++)) )
    {
        put(c);
    }
}
Melandr
Наконец, добил я код для WinAVR. Вылаживаю его может кому сгодится.
CODE

#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>

// Задание выводимой строки текста.
char static_text[] PROGMEM = "Hello, world!";

// Задание регистров порта подключения ЖКИ-модуля.
#define LCD_PORT PORTD
#define LCD_DDR DDRD
// Задание номера бита порта для вывода сигнала Е.
#define LCD_E PD3
// Задание номера бита порта для вывода сигнала RS.
#define LCD_RS PD2
// Задание номера бита порта для вывода сигнала RW
#define LCD_RW PD1
//Задание регистров порта для светодиода
#define LED_PORT PORTC
#define LED_DDR DDRC
//Задание номера бита порта для светодиода
#define LED PC0

// Команда очистки экрана.
#define CLEAR_COMMAND 0b00000001

// Команда возврата курсора на начальную позицию.
#define HOME_COMMAND 0b00000010

// Команда выбора направления сдвига курсора и экрана:
// инкремент счетчика адреса,
// без сдвига изображения.
#define EMS_COMMAND 0b00000110

// Команда выбора отображения:
// изображение включено,
// курсор в виде подчерка выключен,
// курсор в виде мерцающего знакоместа выключен.
#define DISPLAY_COMMAND 0b00001100

// Команда задания сдвига курсора или экрана.
//#define SHIFT_COMMAND 0b0001xx--

// Команда инициализации и задания режима работы индикатора
// для 8-разрядного режима работы шины данных:
// 4-хразрядная шина данных.
// Здесь тетрады переставлены местами для корректной работы
// подпрограммы записи команды в ЖКИ-модуль.
#define INIT_8_COMMAND 0b00000010

// Команда инициализации и задания режима работы индикатора:
// использование двухстрочного режима отображения информации,
// матрица 5х8 точек,
// 4-хразрядная шина данных.
#define INIT_COMMAND 0b00101000

// Команда задания адреса в CGRAM.
#define CGRAM_COMMAND 0b01000000

// Команда задания адреса в DDRAM.
#define DDRAM_COMMAND 0b10000000

// Смещение первого знакоместа второй строки.
#define SECOND_ROW 0x40

// Количество одновременно отображаемых символов на ЖКИ.
#define TOTAL_CHARS 16

// Длительность программных задержек.
#define INIT_DELAY 50
#define INIT_CONTROL_DELAY 50
#define WAIT_LINE_DELAY 1
#define WRITE_DATA_DELAY 50
#define WRITE_DATA_LONG_DELAY 2000

// Переставляет тетрады в байте.
unsigned char swap(unsigned char data)
{
asm(
"swap %0":
"=r" (data):
"0" (data)
);
return data;
}

// Определение задержки для формирования сигналов на линиях.
#define lcd_wait_line() _delay_us(WAIT_LINE_DELAY)

// Записывает данные в ЖКИ-модуль.
void _lcd_write_data(unsigned char data)
{
unsigned char lsn;

// Вывод данных на 4-хразрядную шину.

// Получение и вывод старшей тетрады.
lsn = LCD_PORT & 0x0F;
LCD_PORT = (data & 0xF0) | lsn;

// Установка стробирующего сигнала Е.
LCD_PORT |=(1<<LCD_E);
// Задержка сигнала на линии.
lcd_wait_line();
// Снятие стробирующего сигнала Е.
LCD_PORT &= ~(1<<LCD_E);
// Задержка сигнала на линии.
lcd_wait_line();

// Получение и вывод младшей тетрады.
LCD_PORT = (swap(data) & 0xF0) | lsn;

// Установка стробирующего сигнала Е.
LCD_PORT |= (1<<LCD_E);
// Задержка сигнала на линии.
lcd_wait_line();
// Снятие стробирующего сигнала Е.
LCD_PORT &= ~(1<<LCD_E);
// Задержка сигнала на линии.
lcd_wait_line();

// Формирование задержки для ожидания выполнения команды ЖКИ-модулем.
if (!LCD_RS && (CLEAR_COMMAND == data || HOME_COMMAND == data))
{
_delay_us(WRITE_DATA_LONG_DELAY);
}
else
{
_delay_us(WRITE_DATA_DELAY);
}
}

// Записывает команду в регистр IR ЖКИ-модуля.
void lcd_control(unsigned char control)
{
// Установка линии RS в низкое состояние - сигнал записи команды.
LCD_PORT &= ~(1<<LCD_RS);
// Задержка сигнала на линии.
lcd_wait_line();
_lcd_write_data(control);
}

// Записывает команду в регистр IR ЖКИ-модуля при инициализации.
void lcd_init_control(unsigned char control)
{
lcd_control(control);
// Задержка при инициализации должна быть больше.
_delay_ms(INIT_CONTROL_DELAY);
}

// Записывает символ в регистр DR ЖКИ-модуля.
void lcd_putchar(unsigned char c)
{
// Установка линии RS в высокое состояние - сигнал записи данных.
LCD_PORT |= (1<<LCD_RS);
// Задержка сигнала на линии.
lcd_wait_line();
_lcd_write_data©;
}

// Инициализирует ЖКИ-модуль.
void lcd_init(void)
{
// Порт подключения ЖКИ-модуля работает на вывод.
LCD_DDR |= 0b11111110;

// Предварительная задержка.
_delay_ms(INIT_DELAY);
// Отправка команды инициализации для 8-разрядного режима работы шины
// данных, переключение на 4-хразрядную шину.
lcd_init_control(INIT_8_COMMAND);
// Отправка команды инициализации уже для 4-хразрядного режима.
lcd_init_control(INIT_COMMAND);
// Повторная отправка команды инициализации.
lcd_init_control(INIT_COMMAND);
// Задание режима отображения.
lcd_init_control(DISPLAY_COMMAND);
// Очистка экрана.
lcd_init_control(CLEAR_COMMAND);
// Выбор направления сдвига курсора и экрана.
lcd_init_control(EMS_COMMAND);
}

// Записывает строку для отображения из памяти даных в ЖКИ-модуль.
void lcd_puts(char *str)
{
char c;
while (*str!='\0')
{
c = *str;
lcd_putchar©;
str++;
}
}

// Записывает строку для отображения из памяти программ в ЖКИ-модуль.
void lcd_putsf(char *str)
{
char c;
while (pgm_read_byte(str)!='\0')
{
c = pgm_read_byte(str);
lcd_putchar©;
str++;
}
}

int main(void)
{
LCD_PORT &= ~(1<<LCD_RW);
// Инициализация ЖКИ-модуля.
lcd_init();

// Вывод заданного текста в первой строке с первого знакоместа.
lcd_putsf(static_text);

// Переключение на четвёртое знакоместо второй строки.
lcd_control(DDRAM_COMMAND + SECOND_ROW + 3);

// Вывод заданного текста во второй строке с четвёртого знакоместа.
lcd_putsf(static_text);

//Конфигурираем порт для мигания светодиодом
LED_DDR |= 0b11111111;

for (;;)
{
//Мигаем светодиодом для проверки работоспособности программы
LED_PORT |= (1<<LED);
_delay_ms(1000); //задержка 1 секунда
LED_PORT &= ~(1<<LED);
_delay_ms(1000); //задержка 1 секунда
}
return 0;
}

Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.