libВ порыве изучения stm32, стало очевидно, что возможны ситуации, когда придется портировать библиотеки с AVR или писать с нуля. Поэтому чуть поразмыслив, я решил расковырять какую нибудь либу и показать, как она работает, тем более уже были желающие вникнуть в этот процесс.

Исходные данные: имеется дисплейчик WH0802A-YGH-CT. Это символьный дисплей (с заранее зашитым алфавитом), две строки по восемь символов, на базе контроллера HD44780.

wh0802_ak

Задача: заставить его выводить информацию не используя какие либо библиотеки.

Когда производитель выпускает какое либо изделие, то он обязан выпустить документ с описанием и техническими характеристиками, подобная документация называется даташит (datasheet). В идеале, имея один лишь даташит, вы сможете приладить устройство к любому микроконтроллеру.

Поэтому первым делом ищем даташит на WH0802. Но, как выше говорилось, дисплей имеет свой собственный контроллер, поэтому ищем даташит на HD44780. Кстати, информации там намного больше и подробнее расписано.

wh0802_ygh

Начнем с описания ножек, которых имеется аж четырнадцать. Первые три это питание и настройка контрастности. А вот следующие три, очень даже интересны: RS — выбор того что передаем: данные (1) или команда (0). R/W: читаем информацию с дисплея(1), или передаем на него (0). E — передать данные (импульс 1-0). DB0-DB7  — ножки данных.

pindesk_lcd

Ничего не понятно. Чтобы хоть что то понять, нужно посмотреть временную диаграмму операции записи.

timing_lcd

Вероятно, опять ничего не понятно :). Давай смотреть внимательно. RS может быть как 1 так и 0, в зависимости от того, что мы будем делать: посылать команды (очистить дисплей, передвинуть курсор и т.п.) или передавать данные (числа, символы).

Одновременно с этим устанавливаем бит RW. Пока что читать данные с дисплея мы не собираемся, значит мы передаем данные на дисплей (например, выводим информацию), поэтому бит RW устанавливается в ноль.

После E устанавливается в 1. На ножках DB0-DB7 устанавливается число, допустим, нужно вывести символ ‘a’. В кодировке ASCII этот символ идет под номером 97, т.е. 0110 0001 в двоичной. Тоже самое мы увидим в таблице даташита LHHL LLLH или 0110 0001. Вот эти числа выставляем на ножках DB0-DB7. Остается установить E в ноль, таким образом данные отправятся на дисплей.

char_lcdhd44780

Еще раз, все просто:

1. выбрали команда или данные,

2. выбрали чтение или запись,

3. установили данные на ножках DB0-DB7,

4. подтвердили все это безобразие стробирующим импульсом на ножке E (перепадом с 1 на 0).

Все это справедливо, когда для передачи данных задействованы все 8 ножек DB0-DB7, так называемый 8битный режим. Есть альтернативный режим, когда используются только 4 ножки DB4-DB7, при этом скорость работы дисплея снижается, так как данные отправляются за два приема по 4 бита.

Если нужно отослать символ ‘a’ как было сказано выше, это 0110 0001 в двоичной, т.е. сначала выставляем на ножках DB4-DB7=0110, отсылаем. Потом выставляем DB4-DB7=0001, отсылаем.

Предлагаю сразу нарисовать схему, допустим мне удобно использовать портD, используем 4битный режим ибо ножек всегда не хватает.

sch_lcdhd44780

Дабы не испытывать потом неудобств определим названия ножек с помощью дефайнов, т.е. запись RS=1; и PORTD.0=1; будет делать одно и тоже выставлять единицу в нулевую ножку портаД.

#define RS PORTD.0 //теперь вместо PORTD.0 можно писать RS
#define RW PORTD.1 //тоже самое для остальных ножек
#define E  PORTD.2 //
#define DB4 PORTD.4 //
#define DB5 PORTD.5 //
#define DB6 PORTD.6 //
#define DB7 PORTD.7 //

Перед тем как выводить данные на дисплей нужно его настроить, т.е. инициализировать. Ищем в даташите такую табличку инициализации 4 битного режима. Я спецом подписал красным номера операций.

init_hd44780

Включили питание и подождали 40мс. Далее следует первая операция. Обратим внимание, справа в пояснениях указано, что дисплей находится в 8битном режиме. Сама операция относится к выбору интерфейса. Время выполнения операции 37мкс.
RS=0 — команды, RW =0 — передаем данные на дисплей, на ножках DB5=1 DB4=1, DB7=0, DB6=0.

function_sethd447801

Значит в исходник поместим следующий код:

delay_ms(40);
DB7=0; DB6=0; DB5=1; DB4=1; RS=0; RW=0;  //выставляем биты
E=1;    //отправляем данные
delay_us(2);
E=0;
delay_us(37);

В пояснениях написано BF cannot be checked before this instruction. BF — busy flag, т.е. флаг занятости дисплея. Допустим вы отсылаете команду, она выполняется определенное время, в течение этого времени вы не можете выполнить другую команду — дисплей не схавает. Для того чтобы определить, выполнилась ли операция или нет, можно либо выдерживать временные задержки, либо проверять флаг занятости дисплея, пока он занят на ножке DB7 будет ноль. Таким образом в пояснениях написано, что пока использовать флаг занятости мы еще не можем.

Ждем 4.1мс, выполняем второй и третий пункт, они аналогичны. Обращаем внимание на подсказки — дисплей все еще в восьмибитном режиме!

Переходим к четвертому пункту, переводу дисплея из восьмибитного в четырехбитный режим. Все еще используется Function set, если смотреть справа налево, DB0=- DB1=- DB2=F DB3=N DB4=DL DB5=1 DB6=0 DB7=0

function_sethd447801

так как пока нас интересует только перевод из 8битного в 4 битный, поэтому DB4=0, так как DL=0 при четырехбитном. Соответственно все как в четвертом пункте DB7=0; DB6=0; DB5=1; DB4=0; RS=0; RW=0;

В пятом пункте операция повторяется. Получается как бы мы отправили первую часть Function set DB4-DB7, а теперь нужно отправить вторую часть, которая описана  в битах DB0-DB3, т.е. количество строк и шрифт. Как раз вторая строка пятого пункта DB4=* DB5=* DB6=F DB7=N. Количество строк — две, а используемый шрифт 5х8, значит DB7=1; DB6=0; DB5=0; DB4=0; RS=0; RW=0;

Пункт 6 называется Display off. Тут нужно быть внимательным и обязательно читать описание функции:

function_sethd4478012

Первый раз отсылаем нули, это вроде должно быть понятно, а вот во второй отсылке грабли, ибо нарисовано DB7=1; DB6=0; DB5=0; DB4=0; RS=0; RW=0;  а в описании функции DB7=1 DB6=D DB5=C DB4=B, откуда следует  D — включить/выключить дисплей, посему =1, C — показывать/скрыть курсор, он нам не нужен значит =0, B — мигающий/не мигающий символ, тоже не надо = 0, таким образом DB7=1 DB6=1 DB5=0 DB4=0. Так что доверяй, но проверяй.

Седьмым пунктом идет очистка экрана, тут вроде все как есть, сначала нули, потом DB4=1. Последним, восьмым пунктом Entry mode set — выход из режима настройки, сначала шлем нули, затем DB7=0 DB6=1 DB5=ID DB4=S. ID — выбор сдвига курсора 1- вправо, 0 — влево. S — сдвиг экрана. Получает DB7=0 DB6=1 DB5=1 DB4=0

Все, на этом инициализация окончена. Теперь дисплей готов передавать данные. Передаем все тот же символ ‘a’

  RS=1;	        //теперь отправляем данные
  RW=0;         //пишем
  DB7=0;DB6=1;DB5=1;DB4=0; //первая половина данных
  E=1;	        
  delay_us(2);
  E=0;	
 
  DB7=0;DB6=0;DB5=0;DB4=1; //вторая половина данных
  E=1;	        
  delay_us(2);
  E=0;

Полный исходник

#include <mega8.h>
#include <delay.h> 
 
#define RS PORTD.0
#define RW PORTD.1
#define E  PORTD.2 
#define DB4 PORTD.4
#define DB5 PORTD.5
#define DB6 PORTD.6
#define DB7 PORTD.7
 
 
void main(void)
{
  DDRD = 0xff; //ножки на выход
  PORTD = 0xfF;  
  RW=0; //запись
  delay_ms(40);
 
  //1. Восьмибитный режим
  DB7=0; DB6=0; DB5=1; DB4=1; RS=0; RW=0;  
  E=1;	        
  delay_us(2);
  E=0;	
  delay_us(37);
  delay_ms(5);
 
  //2. Восьмибитный режим
  DB7=0; DB6=0; DB5=1; DB4=1; RS=0; RW=0;  
  E=1;	        
  delay_us(2);
  E=0;	
  delay_us(37); 
  delay_us(100);
 
  //3. Восьмибитный режим
  DB7=0; DB6=0; DB5=1; DB4=1; RS=0; RW=0;  
  E=1;	  
  delay_us(2);
  E=0;	
  delay_us(37); 
 
  //4. Переходим из восьмибитного в 4битный
  DB7=0; DB6=0; DB5=1; DB4=0; RS=0; RW=0;  
  E=1;
  delay_us(2);
  E=0;
  delay_us(37); 
 
  //5.1 4-х разрядная шина, 
  DB7=0; DB6=0; DB5=1; DB4=0; RS=0; RW=0;  
  E=1;	  
  delay_us(2);
  E=0;	
  delay_us(37);
 
  //5.2 2 - строки, шрифт 5х8
  DB7=1; DB6=0; DB5=0; DB4=0; RS=0; RW=0;  
  E=1;	       
  delay_us(2);
  E=0;	
  delay_us(37);
 
  //6.1 Display off
  DB7=0; DB6=0; DB5=0; DB4=0; RS=0; RW=0;  
  E=1;	   
  delay_us(2);
  E=0;
  delay_us(37);  
 
  //6.2
  DB7=1; DB6=0; DB5=0; DB4=0; RS=0; RW=0;  
  E=1;	
  delay_us(2);
  E=0;
  delay_us(37); 
 
  //7.Очистка экрана
  DB7=0; DB6=0; DB5=0; DB4=0; RS=0; RW=0;  
  E=1;	 
  delay_us(2);
  E=0;	
  delay_us(37);   
 
  DB7=0; DB6=0; DB5=0; DB4=1; RS=0; RW=0;  
  E=1;	 
  delay_us(2);
  E=0;	
  delay_us(37);  
 
  //8 Выход из режима настройки 
  delay_ms(2);
  DB7=0; DB6=0; DB5=0; DB4=0; RS=0; RW=0;  
  E=1;	  
  delay_us(2);
  E=0;	
  delay_us(37);  
 
  delay_ms(2);
  DB7=1; DB6=1; DB5=0; DB4=0; RS=0; RW=0;  
  E=1;	  
  delay_us(2);
  E=0;	
  delay_us(37); 
 
  //вывод символа'a'
  RS=1;	        //данные
  RW=0; //пишем
  DB7=0;DB6=1;DB5=1;DB4=0;
  E=1;	        
  delay_us(2);
  E=0;
  delay_us(37); 	
 
  DB7=0;DB6=0;DB5=0;DB4=1;
  E=1;
  delay_us(2);
  E=0;
  delay_us(37); 
 
while (1)
      {
      };
}

Залил прошивку в atmega8, дисплейчик схавал — работает однако!
hd44780_worked

Теперь можно улучшить прошивку. Для начала убрать повторяющиеся строки в функцию например

  E=1;	        
  delay_us(2);
  E=0;	
  delay_us(37);

Функцию можно обозвать _lcd_send(). Исходник сократится, также инициализацию можно поместить в отдельную функцию.

#include <mega8.h>
#include <delay.h> 
 
#define RS PORTD.0
#define RW PORTD.1
#define E  PORTD.2 
#define DB4 PORTD.4
#define DB5 PORTD.5
#define DB6 PORTD.6
#define DB7 PORTD.7
 
void _lcd_send()
{
  E=1;	        
  delay_us(2);
  E=0;	
  delay_us(37);
}
void lcd_init()
{
     DDRD = 0xff; //ножки на выход
  PORTD = 0xfF;  
  RW=0; //запись
  delay_ms(40);
 
  //1. Восьмибитный режим
  DB7=0; DB6=0; DB5=1; DB4=1; RS=0; RW=0;  
  _lcd_send();
  delay_ms(5);
 
  //2. Восьмибитный режим
  DB7=0; DB6=0; DB5=1; DB4=1; RS=0; RW=0;  
  _lcd_send(); 
  delay_us(100);
 
  //3. Восьмибитный режим
  DB7=0; DB6=0; DB5=1; DB4=1; RS=0; RW=0;  
  _lcd_send(); 
 
  //4. Переходим из восьмибитного в 4битный
  DB7=0; DB6=0; DB5=1; DB4=0; RS=0; RW=0;  
  _lcd_send(); 
 
  //5.1 4-х разрядная шина, 
  DB7=0; DB6=0; DB5=1; DB4=0; RS=0; RW=0;  
  _lcd_send();
 
  //5.2 2 - строки, шрифт 5х8
  DB7=1; DB6=0; DB5=0; DB4=0; RS=0; RW=0;  
  _lcd_send();
 
  //6.1 Display off
  DB7=0; DB6=0; DB5=0; DB4=0; RS=0; RW=0;  
  _lcd_send(); 
 
  //6.2
  DB7=1; DB6=0; DB5=0; DB4=0; RS=0; RW=0;  
  _lcd_send();
 
  //7.Очистка экрана
  DB7=0; DB6=0; DB5=0; DB4=0; RS=0; RW=0;  
  _lcd_send();   
 
  DB7=0; DB6=0; DB5=0; DB4=1; RS=0; RW=0;  
  _lcd_send();  
 
  //8 Выход из режима настройки 
  delay_ms(2);
  DB7=0; DB6=0; DB5=0; DB4=0; RS=0; RW=0;  
  _lcd_send();  
 
  delay_ms(2);
  DB7=1; DB6=1; DB5=0; DB4=0; RS=0; RW=0;  
  _lcd_send(); 
}
 
void main(void)
{
  lcd_init();
  //вывод символа'a'
  RS=1;	        //данные
  RW=0; //пишем
  DB7=0;DB6=1;DB5=1;DB4=0;
  _lcd_send();	
 
  DB7=0;DB6=0;DB5=0;DB4=1;
  _lcd_send(); 
 
while (1)
      {
      };
}

Осталось раздерибанить функцию отправки. Итак есть символ, пускай опять же ‘a’. Как говорилось выше, если вы присвоите некой переменной x=’a’ это будет равносильно x=97, ибо номер a в кодировке ASCII 97. Т.е. нам нужно номер символа растащить на биты, 7 бит присвоить DB7, 6 — DB6, 5 — DB5 и 4 — DB4, отправить, потом 3 бит присвоить DB7, 2 — DB6…. и снова отправить.

Как же вытащить 1 бит из целого числа data в переменную x, допустим седьмой. Вначале нужно присвоить остальные биты нулю x= data & 0b10000000, таким образом все кроме седьмого бита станут равными нулю. Если седьмой был единицей он и останется единицей, если нулем то нулем. В этом смысл логического и. Теперь нужно этот бит сдвинуть в нулевой ибо сейчас х в результате этой операции либо 0 либо 128, а нам надо 0 или 1. Поэтому воспользуемся операцией логического сдвига, т.е. сдвинем семь раз вправо запишется это так DB7=(data & 0b10000000)>>7. Если нужно сдвинуть 5 бит DB5=(data & 0b00100000)>>5.

В результате функция посылки байта будет выглядеть так:

void lcd_putchar(char data)
{
  RS=1;	        //данные
  RW=0; //пишем
  DB7=(data&0b10000000)>>7;DB6=(data&0b01000000)>>6;DB5=(data&0b00100000)>>5;DB4=(data&0b00010000)>>4;
  _lcd_send();	
 
  DB7=(data&0b00001000)>>3;DB6=(data&0b00000100)>>2;DB5=(data&0b00000010)>>1;DB4=data&0b00000001;
  _lcd_send(); 
}

Теперь осталось все это безобразие поместить в отдельный файл, например lcd_hard.h и закинуть в него эти функции. Содержание нашей свежеиспеченной либы:

#include <delay.h>
 
#define RS PORTD.0
#define RW PORTD.1
#define E  PORTD.2 
#define DB4 PORTD.4
#define DB5 PORTD.5
#define DB6 PORTD.6
#define DB7 PORTD.7
 
 
void _lcd_send()
{
  E=1;	        
  delay_us(2);
  E=0;	
  delay_us(37);
}
void lcd_putchar(char data)
{
  RS=1;	        //данные
  RW=0; //пишем
  DB7=data>>7;DB6=(data&0b01000000)>>6;DB5=(data&0b00100000)>>5;DB4=(data&0b00010000)>>4;
  _lcd_send();	
 
  DB7=(data&0b00001000)>>3;DB6=(data&0b00000100)>>2;DB5=(data&0b00000010)>>1;DB4=data&0b00000001;
  _lcd_send(); 
}
void lcd_init()
{
     DDRD = 0xff; //ножки на выход
  PORTD = 0xfF;  
  RW=0; //запись
  delay_ms(40);
 
  //1. Восьмибитный режим
  DB7=0; DB6=0; DB5=1; DB4=1; RS=0; RW=0;  
  _lcd_send();
  delay_ms(5);
 
  //2. Восьмибитный режим
  DB7=0; DB6=0; DB5=1; DB4=1; RS=0; RW=0;  
  _lcd_send(); 
  delay_us(100);
 
  //3. Восьмибитный режим
  DB7=0; DB6=0; DB5=1; DB4=1; RS=0; RW=0;  
  _lcd_send(); 
 
  //4. Переходим из восьмибитного в 4битный
  DB7=0; DB6=0; DB5=1; DB4=0; RS=0; RW=0;  
  _lcd_send(); 
 
  //5.1 4-х разрядная шина, 
  DB7=0; DB6=0; DB5=1; DB4=0; RS=0; RW=0;  
  _lcd_send();
 
  //5.2 2 - строки, шрифт 5х8
  DB7=1; DB6=0; DB5=0; DB4=0; RS=0; RW=0;  
  _lcd_send();
 
  //6.1 Display off
  DB7=0; DB6=0; DB5=0; DB4=0; RS=0; RW=0;  
  _lcd_send(); 
 
  //6.2
  DB7=1; DB6=0; DB5=0; DB4=0; RS=0; RW=0;  
  _lcd_send();
 
  //7.Очистка экрана
  DB7=0; DB6=0; DB5=0; DB4=0; RS=0; RW=0;  
  _lcd_send();   
 
  DB7=0; DB6=0; DB5=0; DB4=1; RS=0; RW=0;  
  _lcd_send();  
 
  //8 Выход из режима настройки 
  delay_ms(2);
  DB7=0; DB6=0; DB5=0; DB4=0; RS=0; RW=0;  
  _lcd_send();  
 
  delay_ms(2);
  DB7=1; DB6=1; DB5=0; DB4=0; RS=0; RW=0;  
  _lcd_send(); 
}

Содержание основного текста теперь станет более нам привычным:

#include <mega8.h>
#include <delay.h> 
#include <lcd_hard.h>
 
void main(void)
{
  lcd_init(); 
  lcd_putchar('c');
 
 
while (1)
      {
      };
}

По вкусу, можно добавить функцию очистки экрана и добавить прочие плюшки и настройки. Также, пока не пахнет универсальностью, но суть статьи в том, что можно получить либу просто внимательно читая даташит. Конечно есть тонкости, но главное ничего сверхъестественного нет, все реально.

30 комментариев: Как пишутся библиотеки.

  • Не понял , а как тут указать место символов?
    Обычно lcd_gotoxy(0,1); , а тут как?

  • Позиция курсора задается командой, как — можно посмотреть в даташите

  • Dart. Похоже вас, уже начали доставать «тупые вопросы » от начинающих..
    Но самое главное большое Вам спасибо, что вы сделали столько хороших примеров с исходниками!
    А насчет датшита , думаю года через три я уже научусь в них смотреть с пониманием, а не как сейчас как «баран на новые ворота».

  • Сергей, сама статья предполагает то что вы решились написать свою библиотеку. Нужно очень плотно работать с даташитом. Да это сложно, но скорее морально, чем остальное. Поэтому я могу написать команду, которая сдвигает курсор, но скорее всего ваш вопрос не в этом, уточняйте — подскажу

  • Здравствуйте, можно ли использовать в либах прерывания?
    Допустим:
    В теле основной функции я не определил прерывание, а в либе уже определяют и задаю значение таймера.
    После выполнения либы мне не нужно прерывание и я его отключаю.

  • можно, но нужно будет как то решить вопрос с зависимостью платформы

  • А у меня не получается завести дисплей BC2004A (4 строки*20 символов на базе KS0066), повесил его на порт D контроллера ATmega8 в 4-битном режиме, подсветка горит, но ничего не отображается, контрастность меняется, но не в больших пределах. Возможно есть какие-то особенности подключения 4-х строковых дисплеев??

  • 20 символьные дисплеи отличаются по инициализации. Все что могу посоветовать попробуйте стандартную либу CAVR, или читайте даташит и пишите свою либу

  • -Что значит эта Эс?) В моем мире это… хД Шутка)
    lcd_putchar(‘c’); // не пойму что это в скобках) переменная типа char?
    А где у вас хранится информация для отправки? чето невдупляю.
    void lcd_putchar(char data) //параметры этой функции — data и char. Они должны быть объявлены в начале? или они относятся только к функции и не являются глобальными?

    DB7=data>>7;DB6=(data&0b01000000)>>6;// этими операциями мы сохраняем в «чаре» информацию? а потом уже вызываем?
    -lcd_putchar(‘c’);
    Получается что если мне нужно будет вывести числа (например 132 и 123 и тд ) я должен в data записать эти числа? и потом из «чаир» выдернуть чтоб они появились где-то еще?

  • char это тип, data это переменная, получается переменная типа char, т.е. принимает значения от 0 до 255. Получается что функция принимает значение ‘c’, ‘c’ — это символ ASCII, который имеет определенный номер. Итого все переменные data, что внутри скобок функции будут равны номеру ‘c’. Подробнее, почитайте про передачу параметров в функцию, любой язык программирования.
    Если надо вывести числа, то нужно понимать что вы имеете ввиду, если именно число 0x132 или 3 символа ASII таблицы, подозреваю что последнее, тогда
    lcd_putchar(‘1’)
    lcd_putchar(‘2’)
    lcd_putchar(‘3’)

  • Да)спасибо) Но каким образом задать эти символы?Символы это 8 битное число) так?) а если мне нужно вывести на дисплей слово состоящее из символов)каким образом я их выведу. Получается мне нужно где то сохранить набор битов этих символов?

  • Не совсем понятен Ваш вопрос. Символы зашиты внутри дисплея, у него есть своя память и свой контроллер именно для этого. Он знает, что если ему говорят вывести символ под номером 0x30, то он выведет ‘0’. Любая строка это набор символов, естественно они где то должны храниться, для этого у микроконтроллера есть своя память. Вывод любой строки тоже ведется посимвольно, но можно написать свою функцию, которая будет сама выводить массив символов.

  • туплю) блин) спасибо)

  • так.. чем дальше тем тупее… хД Смотрите я тут почитал немного) `a` это символьная константа ( =0 я вот не знал что это) и компилятор сам знает что ему надо преобразовать её в 8битное число ASCII . Так?) Я просто не понимал откуда он берет данные)я понимал что зашиты символы в памяти . Но как они распознаются было непонятно)
    Все-таки навыки программирования и знания в этой области необходимы… раньше я не понимал… да и сейчас то не понимаю кроме инициализации портов ничерта)) мда у меня уходит уже больше года на мигалку хD //В общем спасибо)

  • У меня на мигалку тоже ушло больше года, так что переживать не стоит. Было бы желание, остальное придет

  • админ, я извиняюсь конечно, но наврное у вас ошибка есть//8 Выход из режима настройки
    delay_ms(2);
    DB7=0; DB6=0; DB5=0; DB4=0; RS=0; RW=0;
    _lcd_send();

    delay_ms(2);
    DB7=1; DB6=1; DB5=0; DB4=0; RS=0; RW=0;
    _lcd_send();
    вот так должно быть по настройкам что вы написали , виход из настроек дисплея. DB7=0; DB6=1; DB5=1; DB4=0; RS=0; RW=0;

  • может, лень проверять 🙂

  • Админ, доброе утро! или день уже) В общем написал я инициализацию для лсд в атмел студио 6.2 по вашему примеру. Залил реальную атмегу, не работает… Установил кодевизион, сделал как у вас. Залили, заработало.

  • ответ очевиден, значит в студии код отличается

  • опять вы меня не поняли, я код переделал под атмел студио.

  • то что вы его переделали, не значит что код идентичен. Кроме того не забывайте про оптимизацию, может компилятор AS выкинул то что посчитал не нужным

  • Админ, вечер добрый. С вами могласен но понять не могу почему при 0 оптимизации ошибка вилазит. Может найдеться немного времени посмотреть код, может у вас в атмел студио заработает
    #define F_CPU 4000000
    #include
    #include
    //Хедер для LCD дисплея
    #define D4 PD4
    #define D5 PD5
    #define D6 PD6
    #define D7 PD7

    #define RS PD0
    #define RW PD1
    #define E PD2

    #define PDD PORTD

    int main(void)

    { _delay_ms(200);
    DDRD =0xFF;
    PDD =0xFF;

    PDD =0x02;
    _delay_ms(40);
    ////1.
    PDD =0x30;

    PDD =0x04;
    _delay_us(2);
    PDD =0x00;
    _delay_us(37);
    _delay_ms(5);

    ///2.
    PDD =0x30;
    PDD =0x04;
    _delay_us(2);
    PDD =0x00;
    _delay_us(37);
    _delay_us(100);

    //3….
    PDD =0x30;
    PDD =0x04;
    _delay_us(2);
    PDD =0x00;
    _delay_us(37);

    //4.
    PDD =0x20;
    PDD =0x04;
    _delay_us(2);
    PDD =0x00;
    _delay_us(37);

    // 5.1
    PDD =0x20;
    PDD =0x04;
    _delay_us(2);
    PDD =0x00;
    _delay_us(37);

    //5.2
    PDD =0x80;
    PDD =0x04;
    _delay_us(2);
    PDD =0x00;
    _delay_us(37);

    //6.1
    PDD =0x00;
    PDD =0x04;
    _delay_us(2);
    PDD =0x00;
    _delay_us(37);

    //6.2

    PDD =0x80;
    PDD =0x04;
    _delay_us(2);
    PDD =0x00;
    _delay_us(37);

    //7.1

    PDD =0x00;
    PDD =0x04;
    _delay_us(2);
    PDD =0x00;
    _delay_us(37);

    //7.2
    PDD =0x10;
    PDD =0x04;
    _delay_us(2);
    PDD =0x00;
    _delay_us(37);

    //8.1
    PDD =0x00;
    PDD =0x04;
    _delay_us(2);
    PDD =0x00;
    _delay_us(37);

    //8.2
    PDD =0xC0;
    PDD =0x04;
    _delay_us(2);
    PDD =0x00;
    _delay_us(37);

    // simvol a

    PDD =0x01;
    PDD =0x00;
    //1 полу байт
    PDD =0x60;
    PDD =0x04;
    _delay_us(2);
    PDD =0x00;
    _delay_us(37);
    // 2 полубайт
    PDD =0x10;
    PDD =0x04;
    _delay_us(2);
    PDD =0x00;
    _delay_us(37);
    while(1)
    {

    }
    }

  • строчки идущие подряд вроде:
    PDD =0x30;
    PDD =0x04;
    компилятор запросто может выкосить

  • Поставил я оптимизацию на 0 , но тогда атмел ругаеться. Кстати переобразования чисел в строку еще не могу понять. но нашол замену функции sprintf, функцией itoa.

  • А зачем задержки delay_ms(2); во время отправки 8-ой команды?

  • смотрите в даташит, там самая правильная инфа

  • добрый день.
    скажите пожалуйсто,
    если в коде программы присутствует, скажем такая строка:
    if ( ! mfrc522.PICC_IsNewCardPresent())
    —- — —
    то это значит, что mfrc522.PICC_IsNewCardPresent() ,должна быть библиотечная функция
    mfrc522.h хидера?

  • mfrc522 это всего навсего имя некой структуры, которое может быть любым, соотнести это имя и имя библиотеки содержащей эту структуру без наличия исходников невозможно.

  • В заголовочных файлах lcd.h только объявление (прототипы) функций, а описание (реализация) в lcd_lib.с.

  • В заголовочных файлах lcd.h декларация, объявление функций, а описание, реализация в lcd_lib.c.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Последние комментарии
  • Загрузка...
Счетчик
Яндекс.Метрика