Перейти к содержанию
    

Попробуйте этот код, ток у меня на 16 меге. Все работает: ив Протеусе, и в железе.

#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 (;;)
{
}

post-44637-1304344256_thumb.png

Изменено пользователем roman_golovenkov

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Почитал http://electronix.ru/forum/index.php?s=&am...st&p=143374, и решил линию управления RW переключить с GND на линию PD1. Поэтому если будут исходники с чтением состояния ЖКИ, очень хотелось бы ознакомиться.

 

Вот работающий проект - разберётесь. WinAWR или атмеловский тулчейн. Интересующая Вас часть (работа с проверкой готовности) находится в файле hd44780.c

Изменено пользователем Genadi Zawidowski

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Попробуйте этот код, ток у меня на 16 меге. Все работает: ив Протеусе, и в железе.

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

 

Вот работающий проект - разберётесь. WinAWR или атмеловский тулчейн. Интересующая Вас часть (работа с проверкой готовности) находится в файле hd44780.c

Спасибо буду разбираться с Вашим исходником.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Компилировал в CoDeVision

Изменено пользователем roman_golovenkov

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот это -

temp=(lcd|(1<<RS))|(1<<E);

и все остальные манипуляции с lcd - неправильные

Нужно маскировать старшую часть lcd, иначе она у вас накладывается на управляющие сигналы:

temp=((lcd&0x0F)|(1<<RS))|(1<<E);

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

иначе она у вас накладывается на управляющие сигналы:
Там маскируются те биты, для которых управляющие сигналы сброшены. А для тех, которые надо выставлять - совершенно неважно, была там единица или нет. Да, некрасиво, но работать должно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Там маскируются те биты, для которых управляющие сигналы сброшены. А для тех, которые надо выставлять - совершенно неважно, была там единица или нет.
Не маскируются вообще никакие биты. В частности бит E (там, где он стоять не должен)

Да, некрасиво, но работать должно.
Неа, точнее не везде :rolleyes:

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не маскируются вообще никакие биты. В частности бит E (там, где он стоять не должен)

Читаем по губам:

  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

 

  temp=((lcd*16)&~(1<<RS))|(1<<E);    //RS=0 – это команда 
  PORTD=temp;                            //Выводим на portD младшую тетраду команды, сигналы RS, E

В первой строке ((lcd*16)&~(1<<RS)) также сбрасывается RS, хотя он и так сброшен в процессе lcd*16, а E безусловно взводится.

 

Неа, точнее не везде :rolleyes:
Ну да, там где нужны остальные биты порта такая конструкция принесет приятные :smile3046: сюрпризы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, действительно. Не заметил :(

Все равно это не комильфо :)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я так понимаю, что хоть программа написана не сильно красиво, но должна работать? Я сам заметил, что немного неудобно манипулировать управляющими линиями ЖКИ, и одновременно передавать данные, но у меня сейчас стоит задача запустить ЖКИ, а дальше оптимизировать и улучшать код.

 

Попробуйте этот код, ток у меня на 16 меге. Все работает: ив Протеусе, и в железе.

 

Так скомпилил в CodeVision, немного изменил, для мигания светодиодом. В протеусе запустил все норм, на экране в протеусе появилась надпись. В железе светодиод мигает, а изображения нет. Есть подозрение, что шлейф соединяющий отладочную плату с ЖКИ, не передает все сигналы. Так как изображения нет, но контрастность регулируется в верхней строке. Завтра прикуплю разьемы на шлейф, и переделаю.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Попробуйте этот код, ток у меня на 16 меге. Все работает: ив Протеусе, и в железе.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Переделал код CodeVision под WinAVR. Вот код:

#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

Также непонятно как использовать флеш память в функции

 

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

Кто может подскажите.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Не знаю логики программы, возможно, должно быть while (c == *str++)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не знаю логики программы, возможно, должно быть while (c == *str++)

 

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

Изменено пользователем Melandr

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Из памяти программ читать удобно чем-либо из WinAVR\avr\include\avr\pgmspace.h.

 

--

 

Насчёт предупреждения, - поставьте ещё скобки, вот так вот: while(( )). Явно показываем компилятору что мы не ошиблись, и на ноль\не ноль проверяем действительно результат операции присваивания.

Изменено пользователем SysRq

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...