Дисплей от телефона к ардуино

Offline

Зарегистрирован: 17.06.2014

Сподвигнули меня на подборки дисплея разбитый шилд 3,5″ для ардуино уно, и интерес запуска почти дармовых дисплеев. // странно, на шилде стабилизатор 3,3v использовался напрямую для подсветки. (тогда уж можно было запитать подсветку через резистор от 5v). Сам дисплей и микросхемы преобразователи уровней питались от 3,3v что шли с ардуины! , тогда по идее нафиг не нужен был стабилизатор на шилде.

В магазе по запчастям от сотиков http://www.la-bora.ru/categories/15  нашёл похожие дислеи 3,2″ по смешной цене  39руб :) называется «Дисплей для china iphone  тип 2 » (как удалось потом запустить , забрал ещё парочку) , дисплеи поменьше, идут уже с тачем . //(потом там же куплены для опытов 3,0″ 320×240 и 400×240, есть ещё много подобных дешёвых магазов  www.megaopt.ru , … )   .   На шлейфе ничего не написано, неизвесто название и распиновка. Попрозванивал, примерно прикинул что где может быт, распиновка 37пин — одна из стандартных,. зелёный шилд пришлось закинуть, ибо там через микросхемы согласователи иногда лупят в дисплей 4,5v , как-то не надёжно. Подключал через резисторы 10к, в итоге питание дисплея свыше 4v ибо пересиливается через входа . В итоге пришёл к резистивным делителям 10к-22к, просто и безопасно для дисплея и ардуины. 

Подключил к меге , UTFT v2.77 (в v2.79 убрана поддержка ili9320 , в связи с тем что производители шилдов не захотели башлять бабосы за использование UTFT ) . и тупо перебирал все виды дисплеев от 0 до 32 (потом пришлось DB0-DB15 перевернуть, потому как в разных распиновках поразному) , пока экран качественно не запустился на UTFT myGLCD(22,38,39,40,41);   ( это CTE28)  . 

потом уже потратил ещё несколько дней на написание проги по считыванию ID дисплея 

Подключение дисплея 1602

// программа для определения ID контроллера дисплея, подключать все 16бит
// (эт чтоб найти старшие биты , ибо в большинстве случаев именно они используются для 8ми битного режима)
//
// в верхней строчке покажет 16 бит ответа с дисплея , начиная со старшего бита
// в нижней строчке в HEX коде старший и младший байты. (для ILI контроллеров это будет 9325, 9320, 9327,…)
// при угадывании правильного подключения шины данных дисплея должно получиться к примеру:
// 1я строчка: 1001 0011 0010 0101
// 2я строчка: 9 3 2 5 ,т.е. это контроллер ILI9325
// подсветку дисплея через ом~20-30 к +5v, питание дисплея от ардуиновских 3.3v (если надо то занизить стабилитроном
// или стабилизатором до 2.8v — т.к. иногда инициализации дисплеев приводятся для 2.8v — там константы напряжений
// для правильной работы ЖК матрицы)
//
// выводы дисплея желательно подключать через резист. делители к примеру 10к+22к , на крайняк тупо через 10к,
// но тогда на питание диспл. посадить стабилитрон 3,0-3,1v и запитывать через резист. ом~20-30 от +3,3v,
// иначе дисплей запитается через выводы и ~4-5v пересилят ардуиновские +3,3v
//
// выводы подключать стандартно UTFT на arduino mega RS(CD),WR, CS, RST
// Standard Arduino Mega/Due shield : <display model>,38, 39, 40, 41
// CTE TFT LCD/SD Shield for Arduino Mega : <display model>,38, 39, 40, 41
//
//выводы ардуино меги 22-29 к предполагаемым выводам дисплея DB8-DB15
//выводы ардуино меги 30-37 к предполагаемым выводам дисплея DB8-DB0
// и дополнительно, для получения ответа от дисплея, необходимо
// к выв. ардуино меги 42 подключить вывод RD дисплея. (по умолчанию на шилдах он кинут на +3.3v)
// Дисплей 1602, выводы VSS, VDD, RS, E, D4, D5, D6, D7
// к выводам ардуино меги GND, +5v, 13, 12, 11, 10, 9, 8
// помним на дисплее поставить резистор 3,3к между VO и VSS(+) , RW замкнуть на VSS(+), подключить A и K к VSS(+) и VDD
#include <LiquidCrystal.h>

#define CD_Pin 38 // (RS)
#define WR_Pin 39
#define CS_Pin 40
#define RST_Pin 41
#define RD_Pin 42

LiquidCrystal lcd(13, 12, 11, 10, 9, 8);
int i;
byte byteH;
byte byteL;
void setup()
{
lcd.begin(16, 2);

digitalWrite(CS_Pin, 1); // деактивация диспл. (отключение его шины данных DB0..DB15)
digitalWrite(RST_Pin, 0); // сброс дисплея
//for (i=22; i<=42;i++) { digitalWrite(i, 0); } // всё лог.0
for (i=22; i<=42;i++) { pinMode(i, OUTPUT); } // конфиг всех пинов на выход + управляющие пины
digitalWrite(RST_Pin, 1); // вывод дисплея из сброса

// запишем команду
digitalWrite(RD_Pin, 1); // уст. порта дисплея на приём (ввод данных в дисплей)
digitalWrite(CD_Pin, 0); // будем работать 0-команда 1-данные
digitalWrite(CS_Pin, 0); // выбор дисплея (активация)
PORTA=0x00; PORTC=0x00; // это команда для считывания ID дисплея =0x00
digitalWrite(WR_Pin, 1); // дёргаем WR
digitalWrite(WR_Pin, 0);
digitalWrite(CS_Pin, 1); // деактивация диспл. (отключение его шины данных DB0..DB15)

//чтение данных
DDRA=0x00; DDRC=0x00; // или for (i=22; i<=37;i++) { pinMode(i, INPUT); } // конфиг всех пинов на вход
digitalWrite(RD_Pin, 0); // уст. порта дисплея на передачу (вывод данных с дисплея)
digitalWrite(CD_Pin, 1); // будем работать с 0-команда 1-данные
digitalWrite(CS_Pin, 0); // выбор дисплея (активация )
digitalWrite(WR_Pin, 1); // дёргаем WR
digitalWrite(WR_Pin, 0);

lcd.setCursor(0, 0);
byteH=0;
if ( digitalRead(29) ) { byteH=byteH+128; lcd.print(1); } else lcd.print(0);
if ( digitalRead(28) ) { byteH=byteH+64; lcd.print(1); } else lcd.print(0);
if ( digitalRead(27) ) { byteH=byteH+32; lcd.print(1); } else lcd.print(0);
if ( digitalRead(26) ) { byteH=byteH+16; lcd.print(1); } else lcd.print(0);
if ( digitalRead(25) ) { byteH=byteH+8; lcd.print(1); } else lcd.print(0);
if ( digitalRead(24) ) { byteH=byteH+4; lcd.print(1); } else lcd.print(0);
if ( digitalRead(23) ) { byteH=byteH+2; lcd.print(1); } else lcd.print(0);
if ( digitalRead(22) ) { byteH=byteH+1; lcd.print(1); } else lcd.print(0);
byteL=0;
if ( digitalRead(30) ) { byteL=byteL+128; lcd.print(1); } else lcd.print(0);
if ( digitalRead(31) ) { byteL=byteL+64; lcd.print(1); } else lcd.print(0);
if ( digitalRead(32) ) { byteL=byteL+32; lcd.print(1); } else lcd.print(0);
if ( digitalRead(33) ) { byteL=byteL+16; lcd.print(1); } else lcd.print(0);
if ( digitalRead(34) ) { byteL=byteL+8; lcd.print(1); } else lcd.print(0);
if ( digitalRead(35) ) { byteL=byteL+4; lcd.print(1); } else lcd.print(0);
if ( digitalRead(36) ) { byteL=byteL+2; lcd.print(1); } else lcd.print(0);
if ( digitalRead(37) ) { byteL=byteL+1; lcd.print(1); } else lcd.print(0);

lcd.setCursor(0, 1);
lcd.print(«ID display: «);
lcd.print(byteH, HEX);lcd.print(byteL, HEX);

digitalWrite(CS_Pin, 1); // деактивация диспл. (отключение шины данных DB0..DB15)
DDRA=0xFF; DDRC=0xFF; // или for (i=22; i<=37;i++) { pinMode(i, OUTPUT); } // конф. шины данных ARDUINO на выход
digitalWrite(RD_Pin, 1); // уст. порта дисплея на приём (ввод данных в дисплей)
//digitalWrite(RST_Pin, 1);

// вставка для UTFT
// pinMode(42, OUTPUT); // конф.ардуино для RD на выход
// digitalWrite(42, 1); // уст. RD=1 — чтобы порт дисплея был на приём (ввод данных в дисплей)

//delay(100);
}

void loop() {
// put your main code here, to run repeatedly:

}

Именно на этом шлейфе дисплея не оказалось перемычек R1 R2….(для SPI или 8 бит режима) , шлейфом железно он на 16 бит. Разве что дорожки резать, ну нафиг, буду эти дисплеи использовать на mini pro или UNO c A6 и A7, для построения графиков по входному АЦП, ног хватит. , А т.к. шина данных дисплея отключается по CS , то можно и все цифровые пины использовать.

Приобрёл также по  39-79руб 2,8″-3,0″ TFT8K1465 и TFT8K1465  400×240 вроде там ili9326 и R61509V (на их шлейфах есть R1-R4 для перевода в 8 бит и SPI) , после долгих поисков нашёл много разной инициализации на них, но незнаю как их вкорячить в UTFT хотябы взамен похожих,    henningkarlsen.com ответил что работает только с изготовителями шилдов или консультация за деньги.  

 Также можно дисплеи поискать у от FLY , там много китайчины TFT8K… . Не советую  увлекатьсям долгим поиском названий, в китае много фирмочек делают дисплеи, ставят какие угодно контроллеры,  разнообразные шлейфы придумывая свои названия что по ним нереально найти что либо. Можно ещё прикидывать по самим контроллерам, что примерно в шлейф от них куда идёт. 

Распиновки, если надо, кину позже , как соберу их до кучи со всех компов. 

разделы: AVR , SPI , PCD8544 , дата: 23 ноября 2017г.

Графический дисплей на контроллере PCD8544

Дисплей от мобильного телефона Nokia 5110/3310 — это довольно известный графический дисплей начального уровня на управляющем контроллере pcd8544. Цена на него колеблется в пределах ста рублей, что сделало его широко распространенным «народным» дисплеем, наряду со знакогенерирующим LCD1602. Несмотря на широкое распространение, имеющаяся информация по этому дисплею или противоречива, или обрывочна(например). Ниже приводится лог недельного изучения девайса с примерами кода от простого к сложному. Вначале я пытался использовать Proteus для большей наглядности, но его возможностей, увы, хватило только на три примера. Поэтому остальные примеры идут для реальной связки ATmega8+дисплей. Так или иначе примеры с Proteus работают и на настоящем устройстве. Ко всем примерами, исходники к ним, скомпилированные прошивками и сборочные Makefile можно скачать здесь https://gitlab.com/flank1er/pcd8544_atmega8.

Должен сразу сказать, что для русификации дисплея я использовал кодировку CP866, и сделал я это удобным для Linux-пользователей способом. В Windows это получится использовать разве что из CYGWIN (понадобится утилита iconv).

Также должен упомянуть, что у меня были сложности с управлением дисплеем через аппаратный SPI. Она заключается в том, что и USBasp, и дисплей используют SPI порт ATmega8, и чтобы загрузить прошивку в микроконтроллер, дисплей приходится отключать. Это просто неудобно. Поэтому почти во всех примерах используется подключение дисплея по программному SPI. Подключение через аппаратный SPI используется только во втором и в последнем (финишном) примере (там не сложно, лишь нужно поменять пару строчек в коде и переподключиться к нужным пинам).

В целом, говоря про графические дисплеи, скажу, что эти штуки быстро «съедают» оперативную и флеш память и легко занимают всю пропускную способность SPI шины ;)

    Содержание статьи:

  1. Основные характеристики дисплея на контроллере pcd8544;
  2. Подключение дисплея к Arduino;
  3. Пишем HelloWorld для ATmega8+PCD8544 в Proteus;
  4. Переподключение дисплея на аппаратный SPI в Proteus;
  5. Функции масштабирование шрифта в два и три раза;
  6. Создание проекта для реального микроконтроллера ATmega8, чтение таблицы ASCII из флеш-памяти;
  7. Добавляем кириллицу в кодировке CP866
  8. Добавление фреймбуфера. Программа рисования фрактала.
  9. Делаем скринсейвер «сквозь звездное небо»
  10. Функции рисования прямых линий, и окружностей
  11. Интерфейс для метеостанции
  12. Интерфейс для FM-радиоприемника
  13. Финальная версия библиотеки на аппаратном SPI

1) Основные характеристики дисплея на контроллере pcd8544

    Они следующие:

  • Напряжение питания дисплея: от 2.7 до 3.3 Вольт, пины данных толерантны к 5 Вольт;
  • Разрешение дисплея 48×84 пикселов;
  • Управление осуществляется через SPI интерфейс(три провода). Всего в управлении задействовано 5 линий;
  • Предельная частота SPI шины 4MBit/s;
  • Дисплей имеет шесть строк(банков) на каждой их которых может разместиться 12 символов. Итого экран имеет текстовую емкость 6 х 12 = 72 символа. Графическая емкость дисплея равна 48 х 84 = 4032 бита/пикселов, или 504 байта;
  • Базовый шрифт для дисплея имеет размерность 5×7 пикселов, знакоместо для одной литеры имеет графическую размерность 7(ш)x8(в).
  • Дисплей имеет два набора команд: базовый и расширенный. Расширенный набор команд используется для конфигурации дисплея, его настройки. Для вывода картинки на экран используется базовый набор команд.

Нужно осознавать, что дисплеи покупаемые на али или ибэе, это не оригинальные дисплеи на контроллере pcd8544, а совместимые с ним noname девайсы(подробности здесь). По крайней мере в продаже на mouser я их не нашел. Это не плохо, но параметры устройства могут не соответствовать документации на оригинальный чип, что как бы уже нехорошо.

Далее немного справочной информации.

Datasheet на дисплей можно скачать например отсюда: https://www.sparkfun.com/datasheets/LCD/Monochrome/Nokia5110.pdf

Распиновка. Модули с экраном от Nokia 5110/3310 продаются в двух вариантах: красные и синие. Синий модуль имеет следующий ряд контактов:

Здесь:
Gnd — это «земля»,
BL — подсветка +3.3 Вольта,
Vcc — питание +3.3 Вольта,
Clk — линия тактирования,
Din — линия данных «Data input»,
DC или D/C— выбор между регистрами данных или команд, аналогичен RS в HD44780,
CE или SCE — Chip Enable, он же CS/SS, Chip Select,
RST — это линия сброса контроллера PCD8544.

Мой экземпляр экрана имеет красную расцветку, от синего он отличается тем, что подсветка LIGHT включается подключением к «земле», а не к питанию. В остальном все тоже самое.

Стрелочкой обозначен верх дисплея.

Адресация видеопамяти:

Начало координат располагается в верхнем левом углу. Очередность байтов при линейном заполнении видеопамяти такая:

Также хочется сказать пару слов о подключении дисплея с 3.3 вольтовой логикой к микроконтроллеру ATmega8. Все знают, что в частности Аrduino — это 5 вольтовая логика. Однако микроконтроллеры ATmega могут работать на 3.3 Вольтах.

Я лично использовал такую самодельную DevBoard:

Линейный стабилизатор LM1117 3.3 позволяет переключать внешнее питание с 5 Вольт на 3.3Вольт. Однако при подключении программатора USBasp линейный стабилизатор не задействуется, вместо этого на самом программаторе переключается джампик питания микроконтроллера на 3.3V.

На моей DevBoard установлен кварц на 16MHz, хотя по документации на ATmega8, при напряжении питания 3.3Вольт частота clkcpu не должна превышать 10МГц. И хотя при комнатной температуре это будет работать скорее всего без проблем, технически это является overclocking’ом.

2) Подключение экрана Nokia 5110 к Arduino

Для проверки дисплея на работоспособность, можно попробовать подключить его к Arduino.

На официальном сайте Arduino имеется небольшой скетч — HelloWorld, с помощью которого можно проверить работоспособность дисплея. Этот скетч не требует установки каких-либо библиотек для своей работы.

#define PIN_SCE   7
#define PIN_RESET 6
#define PIN_DC    5
#define PIN_SDIN  4
#define PIN_SCLK  3

#define LCD_C     LOW
#define LCD_D     HIGH

#define LCD_X     84
#define LCD_Y     48

static const byte ASCII[][5] =
{
 {0x00, 0x00, 0x00, 0x00, 0x00} 20
,{0x00, 0x00, 0x5f, 0x00, 0x00} 21
,{0x00, 0x07, 0x00, 0x07, 0x00} 22"
,{0x14, 0x7f, 0x14, 0x7f, 0x14} 23
,{0x24, 0x2a, 0x7f, 0x2a, 0x12} 24
,{0x23, 0x13, 0x08, 0x64, 0x62} 25
,{0x36, 0x49, 0x55, 0x22, 0x50} 26
,{0x00, 0x05, 0x03, 0x00, 0x00} 27
,{0x00, 0x1c, 0x22, 0x41, 0x00} 28
,{0x00, 0x41, 0x22, 0x1c, 0x00} 29
,{0x14, 0x08, 0x3e, 0x08, 0x14} 
,{0x08, 0x08, 0x3e, 0x08, 0x08} 
,{0x00, 0x50, 0x30, 0x00, 0x00} 
,{0x08, 0x08, 0x08, 0x08, 0x08} 
,{0x00, 0x60, 0x60, 0x00, 0x00} 
,{0x20, 0x10, 0x08, 0x04, 0x02} 2f
,{0x3e, 0x51, 0x49, 0x45, 0x3e} 300
,{0x00, 0x42, 0x7f, 0x40, 0x00} 311
,{0x42, 0x61, 0x51, 0x49, 0x46} 322
,{0x21, 0x41, 0x45, 0x4b, 0x31} 333
,{0x18, 0x14, 0x12, 0x7f, 0x10} 344
,{0x27, 0x45, 0x45, 0x45, 0x39} 355
,{0x3c, 0x4a, 0x49, 0x49, 0x30} 366
,{0x01, 0x71, 0x09, 0x05, 0x03} 377
,{0x36, 0x49, 0x49, 0x49, 0x36} 388
,{0x06, 0x49, 0x49, 0x29, 0x1e} 399
,{0x00, 0x36, 0x36, 0x00, 0x00} 
,{0x00, 0x56, 0x36, 0x00, 0x00} 
,{0x08, 0x14, 0x22, 0x41, 0x00} 
,{0x14, 0x14, 0x14, 0x14, 0x14} 
,{0x00, 0x41, 0x22, 0x14, 0x08} 
,{0x02, 0x01, 0x51, 0x09, 0x06} 3f
,{0x32, 0x49, 0x79, 0x41, 0x3e} 40
,{0x7e, 0x11, 0x11, 0x11, 0x7e} 41
,{0x7f, 0x49, 0x49, 0x49, 0x36} 42
,{0x3e, 0x41, 0x41, 0x41, 0x22} 43
,{0x7f, 0x41, 0x41, 0x22, 0x1c} 44
,{0x7f, 0x49, 0x49, 0x49, 0x41} 45
,{0x7f, 0x09, 0x09, 0x09, 0x01} 46
,{0x3e, 0x41, 0x49, 0x49, 0x7a} 47
,{0x7f, 0x08, 0x08, 0x08, 0x7f} 48
,{0x00, 0x41, 0x7f, 0x41, 0x00} 49
,{0x20, 0x40, 0x41, 0x3f, 0x01} 
,{0x7f, 0x08, 0x14, 0x22, 0x41} 
,{0x7f, 0x40, 0x40, 0x40, 0x40} 
,{0x7f, 0x02, 0x0c, 0x02, 0x7f} 
,{0x7f, 0x04, 0x08, 0x10, 0x7f} 
,{0x3e, 0x41, 0x41, 0x41, 0x3e} 4f
,{0x7f, 0x09, 0x09, 0x09, 0x06} 50
,{0x3e, 0x41, 0x51, 0x21, 0x5e} 51
,{0x7f, 0x09, 0x19, 0x29, 0x46} 52
,{0x46, 0x49, 0x49, 0x49, 0x31} 53
,{0x01, 0x01, 0x7f, 0x01, 0x01} 54
,{0x3f, 0x40, 0x40, 0x40, 0x3f} 55
,{0x1f, 0x20, 0x40, 0x20, 0x1f} 56
,{0x3f, 0x40, 0x38, 0x40, 0x3f} 57
,{0x63, 0x14, 0x08, 0x14, 0x63} 58
,{0x07, 0x08, 0x70, 0x08, 0x07} 59
,{0x61, 0x51, 0x49, 0x45, 0x43} 
,{0x00, 0x7f, 0x41, 0x41, 0x00} 
,{0x02, 0x04, 0x08, 0x10, 0x20} 
,{0x00, 0x41, 0x41, 0x7f, 0x00} 
,{0x04, 0x02, 0x01, 0x02, 0x04} 
,{0x40, 0x40, 0x40, 0x40, 0x40} 5f
,{0x00, 0x01, 0x02, 0x04, 0x00} 60
,{0x20, 0x54, 0x54, 0x54, 0x78} 61
,{0x7f, 0x48, 0x44, 0x44, 0x38} 62
,{0x38, 0x44, 0x44, 0x44, 0x20} 63
,{0x38, 0x44, 0x44, 0x48, 0x7f} 64
,{0x38, 0x54, 0x54, 0x54, 0x18} 65
,{0x08, 0x7e, 0x09, 0x01, 0x02} 66
,{0x0c, 0x52, 0x52, 0x52, 0x3e} 67
,{0x7f, 0x08, 0x04, 0x04, 0x78} 68
,{0x00, 0x44, 0x7d, 0x40, 0x00} 69
,{0x20, 0x40, 0x44, 0x3d, 0x00} 
,{0x7f, 0x10, 0x28, 0x44, 0x00} 
,{0x00, 0x41, 0x7f, 0x40, 0x00} 
,{0x7c, 0x04, 0x18, 0x04, 0x78} 
,{0x7c, 0x08, 0x04, 0x04, 0x78} 
,{0x38, 0x44, 0x44, 0x44, 0x38} 6f
,{0x7c, 0x14, 0x14, 0x14, 0x08} 70
,{0x08, 0x14, 0x14, 0x18, 0x7c} 71
,{0x7c, 0x08, 0x04, 0x04, 0x08} 72
,{0x48, 0x54, 0x54, 0x54, 0x20} 73
,{0x04, 0x3f, 0x44, 0x40, 0x20} 74
,{0x3c, 0x40, 0x40, 0x20, 0x7c} 75
,{0x1c, 0x20, 0x40, 0x20, 0x1c} 76
,{0x3c, 0x40, 0x30, 0x40, 0x3c} 77
,{0x44, 0x28, 0x10, 0x28, 0x44} 78
,{0x0c, 0x50, 0x50, 0x50, 0x3c} 79
,{0x44, 0x64, 0x54, 0x4c, 0x44} 
,{0x00, 0x08, 0x36, 0x41, 0x00} 
,{0x00, 0x00, 0x7f, 0x00, 0x00} 
,{0x00, 0x41, 0x36, 0x08, 0x00} 
,{0x10, 0x08, 0x08, 0x10, 0x08} 
,{0x78, 0x46, 0x41, 0x46, 0x78} 7f
};

void LcdCharacter(char character)
{
  LcdWrite(LCD_D, 0x00);
  for (int index = 0; index < 5; index++)
  {
    LcdWrite(LCD_D, ASCII[character - 0x20][index]);
  }
  LcdWrite(LCD_D, 0x00);
}

void LcdClear(void)
{
  for (int index = 0; index < LCD_X * LCD_Y / 8; index++)
  {
    LcdWrite(LCD_D, 0x00);
  }
}

void LcdInitialise(void)
{
  pinMode(PIN_SCE, OUTPUT);
  pinMode(PIN_RESET, OUTPUT);
  pinMode(PIN_DC, OUTPUT);
  pinMode(PIN_SDIN, OUTPUT);
  pinMode(PIN_SCLK, OUTPUT);
  digitalWrite(PIN_RESET, LOW);
  digitalWrite(PIN_RESET, HIGH);
  LcdWrite(LCD_C, 0x21 );  
  LcdWrite(LCD_C, 0xBA );  
  LcdWrite(LCD_C, 0x04 );  0x04
  LcdWrite(LCD_C, 0x14 );  148.0x13
  LcdWrite(LCD_C, 0x20 );  
  LcdWrite(LCD_C, 0x0C );  
}

void LcdString(char *characters)
{
  while (*characters)
  {
    LcdCharacter(*characters++);
  }
}

void LcdWrite(byte dc, byte data)
{
  digitalWrite(PIN_DC, dc);
  digitalWrite(PIN_SCE, LOW);
  shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data);
  digitalWrite(PIN_SCE, HIGH);
}

void setup(void)
{
  LcdInitialise();
  LcdClear();
  LcdString("Hello World!");
}

void loop(void)
{
}

При успешном подключении, на экране дисплея появится строка: Hello World!

Данный скетч я буду использовать как образец для написания кода под ATmega8.

3)Пишем HelloWorld для ATmega8+PCD8544 в Proteus

В Proteus 8.5 дисплей на контролере pcd8544 уже имеется в библиотеке, так что ничего искать и скачивать не надо, нужно просто добавить его в проект:

После статьи о сдвиговых регистрах, у меня в Proteus остался проект с ATmega8 настроенный на работу на 2МГц, его я и буду продолжать использовать:

Код для микроконтроллера я пишу в самом Proteus, и вариант приведенного выше кода для ATmega8 будет выглядеть так:

показать код

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

#define PIN_SCE   PD7
#define PIN_RESET PD6
#define PIN_DC    PD5
#define PIN_SDIN  PD4
#define PIN_SCLK  PD3

#define LCD_C     0x00
#define LCD_D     0x01

#define LCD_X     84
#define LCD_Y     48

#define PORT_PCD8544 PORTD
#define DDR_PCD8544  DDRD

static const uint8_t ASCII[][5] =
{
 {0x00, 0x00, 0x00, 0x00, 0x00} 20
,{0x00, 0x00, 0x5f, 0x00, 0x00} 21
,{0x00, 0x07, 0x00, 0x07, 0x00} 22"
,{0x14, 0x7f, 0x14, 0x7f, 0x14} 23
,{0x24, 0x2a, 0x7f, 0x2a, 0x12} 24
,{0x23, 0x13, 0x08, 0x64, 0x62} 25
,{0x36, 0x49, 0x55, 0x22, 0x50} 26
,{0x00, 0x05, 0x03, 0x00, 0x00} 27
,{0x00, 0x1c, 0x22, 0x41, 0x00} 28
,{0x00, 0x41, 0x22, 0x1c, 0x00} 29
,{0x14, 0x08, 0x3e, 0x08, 0x14} 
,{0x08, 0x08, 0x3e, 0x08, 0x08} 
,{0x00, 0x50, 0x30, 0x00, 0x00} 
,{0x08, 0x08, 0x08, 0x08, 0x08} 
,{0x00, 0x60, 0x60, 0x00, 0x00} 
,{0x20, 0x10, 0x08, 0x04, 0x02} 2f
,{0x3e, 0x51, 0x49, 0x45, 0x3e} 300
,{0x00, 0x42, 0x7f, 0x40, 0x00} 311
,{0x42, 0x61, 0x51, 0x49, 0x46} 322
,{0x21, 0x41, 0x45, 0x4b, 0x31} 333
,{0x18, 0x14, 0x12, 0x7f, 0x10} 344
,{0x27, 0x45, 0x45, 0x45, 0x39} 355
,{0x3c, 0x4a, 0x49, 0x49, 0x30} 366
,{0x01, 0x71, 0x09, 0x05, 0x03} 377
,{0x36, 0x49, 0x49, 0x49, 0x36} 388
,{0x06, 0x49, 0x49, 0x29, 0x1e} 399
,{0x00, 0x36, 0x36, 0x00, 0x00} 
,{0x00, 0x56, 0x36, 0x00, 0x00} 
,{0x08, 0x14, 0x22, 0x41, 0x00} 
,{0x14, 0x14, 0x14, 0x14, 0x14} 
,{0x00, 0x41, 0x22, 0x14, 0x08} 
,{0x02, 0x01, 0x51, 0x09, 0x06} 3f
,{0x32, 0x49, 0x79, 0x41, 0x3e} 40
,{0x7e, 0x11, 0x11, 0x11, 0x7e} 41
,{0x7f, 0x49, 0x49, 0x49, 0x36} 42
,{0x3e, 0x41, 0x41, 0x41, 0x22} 43
,{0x7f, 0x41, 0x41, 0x22, 0x1c} 44
,{0x7f, 0x49, 0x49, 0x49, 0x41} 45
,{0x7f, 0x09, 0x09, 0x09, 0x01} 46
,{0x3e, 0x41, 0x49, 0x49, 0x7a} 47
,{0x7f, 0x08, 0x08, 0x08, 0x7f} 48
,{0x00, 0x41, 0x7f, 0x41, 0x00} 49
,{0x20, 0x40, 0x41, 0x3f, 0x01} 
,{0x7f, 0x08, 0x14, 0x22, 0x41} 
,{0x7f, 0x40, 0x40, 0x40, 0x40} 
,{0x7f, 0x02, 0x0c, 0x02, 0x7f} 
,{0x7f, 0x04, 0x08, 0x10, 0x7f} 
,{0x3e, 0x41, 0x41, 0x41, 0x3e} 4f
,{0x7f, 0x09, 0x09, 0x09, 0x06} 50
,{0x3e, 0x41, 0x51, 0x21, 0x5e} 51
,{0x7f, 0x09, 0x19, 0x29, 0x46} 52
,{0x46, 0x49, 0x49, 0x49, 0x31} 53
,{0x01, 0x01, 0x7f, 0x01, 0x01} 54
,{0x3f, 0x40, 0x40, 0x40, 0x3f} 55
,{0x1f, 0x20, 0x40, 0x20, 0x1f} 56
,{0x3f, 0x40, 0x38, 0x40, 0x3f} 57
,{0x63, 0x14, 0x08, 0x14, 0x63} 58
,{0x07, 0x08, 0x70, 0x08, 0x07} 59
,{0x61, 0x51, 0x49, 0x45, 0x43} 
,{0x00, 0x7f, 0x41, 0x41, 0x00} 
,{0x02, 0x04, 0x08, 0x10, 0x20} 
,{0x00, 0x41, 0x41, 0x7f, 0x00} 
,{0x04, 0x02, 0x01, 0x02, 0x04} 
,{0x40, 0x40, 0x40, 0x40, 0x40} 5f
,{0x00, 0x01, 0x02, 0x04, 0x00} 60
,{0x20, 0x54, 0x54, 0x54, 0x78} 61
,{0x7f, 0x48, 0x44, 0x44, 0x38} 62
,{0x38, 0x44, 0x44, 0x44, 0x20} 63
,{0x38, 0x44, 0x44, 0x48, 0x7f} 64
,{0x38, 0x54, 0x54, 0x54, 0x18} 65
,{0x08, 0x7e, 0x09, 0x01, 0x02} 66
,{0x0c, 0x52, 0x52, 0x52, 0x3e} 67
,{0x7f, 0x08, 0x04, 0x04, 0x78} 68
,{0x00, 0x44, 0x7d, 0x40, 0x00} 69
,{0x20, 0x40, 0x44, 0x3d, 0x00} 
,{0x7f, 0x10, 0x28, 0x44, 0x00} 
,{0x00, 0x41, 0x7f, 0x40, 0x00} 
,{0x7c, 0x04, 0x18, 0x04, 0x78} 
,{0x7c, 0x08, 0x04, 0x04, 0x78} 
,{0x38, 0x44, 0x44, 0x44, 0x38} 6f
,{0x7c, 0x14, 0x14, 0x14, 0x08} 70
,{0x08, 0x14, 0x14, 0x18, 0x7c} 71
,{0x7c, 0x08, 0x04, 0x04, 0x08} 72
,{0x48, 0x54, 0x54, 0x54, 0x20} 73
,{0x04, 0x3f, 0x44, 0x40, 0x20} 74
,{0x3c, 0x40, 0x40, 0x20, 0x7c} 75
,{0x1c, 0x20, 0x40, 0x20, 0x1c} 76
,{0x3c, 0x40, 0x30, 0x40, 0x3c} 77
,{0x44, 0x28, 0x10, 0x28, 0x44} 78
,{0x0c, 0x50, 0x50, 0x50, 0x3c} 79
,{0x44, 0x64, 0x54, 0x4c, 0x44} 
,{0x00, 0x08, 0x36, 0x41, 0x00} 
,{0x00, 0x00, 0x7f, 0x00, 0x00} 
,{0x00, 0x41, 0x36, 0x08, 0x00} 
,{0x10, 0x08, 0x08, 0x10, 0x08} 
,{0x78, 0x46, 0x41, 0x46, 0x78} 7f
};

void pcd8544_init(void);
void pcd8544_send(uint8_t dc, uint8_t data);
void pcd8544_print_string(char *str);
void pcd8544_send_char(uint8_t ch);
void pcd8544_clear(void);

int main(void)
{
   pcd8544_init();
   pcd8544_clear();
   pcd8544_print_string("Hello World!");

   for (;;){
      _delay_ms(1000);
   }

   return 0;
}

void pcd8544_init(void)
{
   
   DDR_PCD8544 |= (1<<PIN_SCE) | (1<<PIN_RESET) | (1<<PIN_DC) | (1<<PIN_SDIN) | (1<<PIN_SCLK);
   PORT_PCD8544&=~(1<<PIN_RESET);
   PORT_PCD8544|=(1<<PIN_RESET);
   pcd8544_send(LCD_C, 0x21 );  
   pcd8544_send(LCD_C, 0xBA );  
   pcd8544_send(LCD_C, 0x04 );  0x04
   pcd8544_send(LCD_C, 0x14 );  148.0x13
   pcd8544_send(LCD_C, 0x20 );  
   pcd8544_send(LCD_C, 0x0C );  
}

void pcd8544_send(uint8_t dc, uint8_t data)
{
   uint8_t i;
   if (dc == LCD_D)
      PORT_PCD8544 |= (1<<PIN_DC);
   else
      PORT_PCD8544 &= ~(1<<PIN_DC);

   PORT_PCD8544&=~(1<<PIN_SCE);
   for (i=0; i<8; i++)
   {
      PORT_PCD8544=(data & 0x80) ? PORT_PCD8544 | (1<<PIN_SDIN) : PORT_PCD8544 & ~(1<<PIN_SDIN);

      data=(data<<1);

      PORT_PCD8544|=(1<<PIN_SCLK);
      PORT_PCD8544&=~(1<<PIN_SCLK);
   }
   PORT_PCD8544|=(1<<PIN_SCE);
}

void pcd8544_print_string(char *str)
{
   while (*str)
   {
      pcd8544_send_char(*str++);
   }
}

void pcd8544_send_char(uint8_t ch)
{
   int i;
   if (ch >= 0x20 && ch <= 0x80)
   {
      pcd8544_send(LCD_D, 0x00);
      for (i = 0; i < 5; i++)
      {
         pcd8544_send(LCD_D,  ASCII[ch - 0x20][i]);
      }
      pcd8544_send(LCD_D, 0x00);
   }
}

void pcd8544_clear(void)
{
   int i;
   for (i=0; i < LCD_X * LCD_Y / 8; i++)
   {
      pcd8544_send(LCD_D, 0x00);
   }
}

Результат работы:

Начало положено, начнём добавлять функционал. Что мы можем сделать на этом этапе? Первое, что хотелось бы сделать, это чтение ASCII таблицы из флеш-памяти, и поддержку кириллицы. Но Proteus такие штуки не осилит. Поэтому начнем с малого, установка курсора на определенную позицию экрана, сейчас это нам вполне по силам.

Добавляем функцию установки курсора:

void pcd8544_set_cursor(uint8_t x, uint8_t y) {
    x=x%12; y=y%6;
    pcd8544_send(LCD_C, 0x40+y);
    pcd8544_send(LCD_C, 0x80+x*7);
} 

Чтобы каждый раз не вызывать эту функцию, добавим функцию печати строки с определенной позиции:

void pcd8544_print_at(char *str, uint8_t x, uint8_t y)
{
    pcd8544_set_cursor(x,y);

    while (*str)
    {
        pcd8544_send_char(*str++);
    }
    break;
}

Теперь можно написать на дисплее уже что-то более осмысленное:

int main(void)
{
   pcd8544_init();
   pcd8544_clear();
   pcd8544_print_at("Nokia 3310",1,0);
   pcd8544_print_at("Connecting",1,2);
   pcd8544_print_at("People",6,3);

   for (;;){
      _delay_ms(1000);
   }

   return 0;
}

показать полный код

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

#define PIN_SCE   PD7
#define PIN_RESET PD6
#define PIN_DC    PD5
#define PIN_SDIN  PD4
#define PIN_SCLK  PD3

#define LCD_C     0x00
#define LCD_D     0x01

#define LCD_X     84
#define LCD_Y     48

#define PORT_PCD8544 PORTD
#define DDR_PCD8544  DDRD

static const uint8_t ASCII[][5] =
{
 {0x00, 0x00, 0x00, 0x00, 0x00} 20
,{0x00, 0x00, 0x5f, 0x00, 0x00} 21
,{0x00, 0x07, 0x00, 0x07, 0x00} 22"
,{0x14, 0x7f, 0x14, 0x7f, 0x14} 23
,{0x24, 0x2a, 0x7f, 0x2a, 0x12} 24
,{0x23, 0x13, 0x08, 0x64, 0x62} 25
,{0x36, 0x49, 0x55, 0x22, 0x50} 26
,{0x00, 0x05, 0x03, 0x00, 0x00} 27
,{0x00, 0x1c, 0x22, 0x41, 0x00} 28
,{0x00, 0x41, 0x22, 0x1c, 0x00} 29
,{0x14, 0x08, 0x3e, 0x08, 0x14} 
,{0x08, 0x08, 0x3e, 0x08, 0x08} 
,{0x00, 0x50, 0x30, 0x00, 0x00} 
,{0x08, 0x08, 0x08, 0x08, 0x08} 
,{0x00, 0x60, 0x60, 0x00, 0x00} 
,{0x20, 0x10, 0x08, 0x04, 0x02} 2f
,{0x3e, 0x51, 0x49, 0x45, 0x3e} 300
,{0x00, 0x42, 0x7f, 0x40, 0x00} 311
,{0x42, 0x61, 0x51, 0x49, 0x46} 322
,{0x21, 0x41, 0x45, 0x4b, 0x31} 333
,{0x18, 0x14, 0x12, 0x7f, 0x10} 344
,{0x27, 0x45, 0x45, 0x45, 0x39} 355
,{0x3c, 0x4a, 0x49, 0x49, 0x30} 366
,{0x01, 0x71, 0x09, 0x05, 0x03} 377
,{0x36, 0x49, 0x49, 0x49, 0x36} 388
,{0x06, 0x49, 0x49, 0x29, 0x1e} 399
,{0x00, 0x36, 0x36, 0x00, 0x00} 
,{0x00, 0x56, 0x36, 0x00, 0x00} 
,{0x08, 0x14, 0x22, 0x41, 0x00} 
,{0x14, 0x14, 0x14, 0x14, 0x14} 
,{0x00, 0x41, 0x22, 0x14, 0x08} 
,{0x02, 0x01, 0x51, 0x09, 0x06} 3f
,{0x32, 0x49, 0x79, 0x41, 0x3e} 40
,{0x7e, 0x11, 0x11, 0x11, 0x7e} 41
,{0x7f, 0x49, 0x49, 0x49, 0x36} 42
,{0x3e, 0x41, 0x41, 0x41, 0x22} 43
,{0x7f, 0x41, 0x41, 0x22, 0x1c} 44
,{0x7f, 0x49, 0x49, 0x49, 0x41} 45
,{0x7f, 0x09, 0x09, 0x09, 0x01} 46
,{0x3e, 0x41, 0x49, 0x49, 0x7a} 47
,{0x7f, 0x08, 0x08, 0x08, 0x7f} 48
,{0x00, 0x41, 0x7f, 0x41, 0x00} 49
,{0x20, 0x40, 0x41, 0x3f, 0x01} 
,{0x7f, 0x08, 0x14, 0x22, 0x41} 
,{0x7f, 0x40, 0x40, 0x40, 0x40} 
,{0x7f, 0x02, 0x0c, 0x02, 0x7f} 
,{0x7f, 0x04, 0x08, 0x10, 0x7f} 
,{0x3e, 0x41, 0x41, 0x41, 0x3e} 4f
,{0x7f, 0x09, 0x09, 0x09, 0x06} 50
,{0x3e, 0x41, 0x51, 0x21, 0x5e} 51
,{0x7f, 0x09, 0x19, 0x29, 0x46} 52
,{0x46, 0x49, 0x49, 0x49, 0x31} 53
,{0x01, 0x01, 0x7f, 0x01, 0x01} 54
,{0x3f, 0x40, 0x40, 0x40, 0x3f} 55
,{0x1f, 0x20, 0x40, 0x20, 0x1f} 56
,{0x3f, 0x40, 0x38, 0x40, 0x3f} 57
,{0x63, 0x14, 0x08, 0x14, 0x63} 58
,{0x07, 0x08, 0x70, 0x08, 0x07} 59
,{0x61, 0x51, 0x49, 0x45, 0x43} 
,{0x00, 0x7f, 0x41, 0x41, 0x00} 
,{0x02, 0x04, 0x08, 0x10, 0x20} 
,{0x00, 0x41, 0x41, 0x7f, 0x00} 
,{0x04, 0x02, 0x01, 0x02, 0x04} 
,{0x40, 0x40, 0x40, 0x40, 0x40} 5f
,{0x00, 0x01, 0x02, 0x04, 0x00} 60
,{0x20, 0x54, 0x54, 0x54, 0x78} 61
,{0x7f, 0x48, 0x44, 0x44, 0x38} 62
,{0x38, 0x44, 0x44, 0x44, 0x20} 63
,{0x38, 0x44, 0x44, 0x48, 0x7f} 64
,{0x38, 0x54, 0x54, 0x54, 0x18} 65
,{0x08, 0x7e, 0x09, 0x01, 0x02} 66
,{0x0c, 0x52, 0x52, 0x52, 0x3e} 67
,{0x7f, 0x08, 0x04, 0x04, 0x78} 68
,{0x00, 0x44, 0x7d, 0x40, 0x00} 69
,{0x20, 0x40, 0x44, 0x3d, 0x00} 
,{0x7f, 0x10, 0x28, 0x44, 0x00} 
,{0x00, 0x41, 0x7f, 0x40, 0x00} 
,{0x7c, 0x04, 0x18, 0x04, 0x78} 
,{0x7c, 0x08, 0x04, 0x04, 0x78} 
,{0x38, 0x44, 0x44, 0x44, 0x38} 6f
,{0x7c, 0x14, 0x14, 0x14, 0x08} 70
,{0x08, 0x14, 0x14, 0x18, 0x7c} 71
,{0x7c, 0x08, 0x04, 0x04, 0x08} 72
,{0x48, 0x54, 0x54, 0x54, 0x20} 73
,{0x04, 0x3f, 0x44, 0x40, 0x20} 74
,{0x3c, 0x40, 0x40, 0x20, 0x7c} 75
,{0x1c, 0x20, 0x40, 0x20, 0x1c} 76
,{0x3c, 0x40, 0x30, 0x40, 0x3c} 77
,{0x44, 0x28, 0x10, 0x28, 0x44} 78
,{0x0c, 0x50, 0x50, 0x50, 0x3c} 79
,{0x44, 0x64, 0x54, 0x4c, 0x44} 
,{0x00, 0x08, 0x36, 0x41, 0x00} 
,{0x00, 0x00, 0x7f, 0x00, 0x00} 
,{0x00, 0x41, 0x36, 0x08, 0x00} 
,{0x10, 0x08, 0x08, 0x10, 0x08} 
,{0x78, 0x46, 0x41, 0x46, 0x78} 7f
};

void pcd8544_init(void);
void pcd8544_send(uint8_t dc, uint8_t data);
void pcd8544_print_string(char *str);
void pcd8544_send_char(uint8_t ch);
void pcd8544_clear(void);
void pcd8544_set_cursor(uint8_t x, uint8_t y);
void pcd8544_print_at(char *str, uint8_t x, uint8_t y);

int main(void)
{
   pcd8544_init();
   pcd8544_clear();
   pcd8544_print_at("Nokia 3310",1,0);
   pcd8544_print_at("Connecting",1,2);
   pcd8544_print_at("People",6,3);

   for (;;){
      _delay_ms(1000);
   }

   return 0;
}

void pcd8544_init(void)
{
   
   DDR_PCD8544 |= (1<<PIN_SCE) | (1<<PIN_RESET) | (1<<PIN_DC) | (1<<PIN_SDIN) | (1<<PIN_SCLK);
   PORT_PCD8544&=~(1<<PIN_RESET);
   PORT_PCD8544|=(1<<PIN_RESET);
   pcd8544_send(LCD_C, 0x21 );  
   pcd8544_send(LCD_C, 0xBA );  
   pcd8544_send(LCD_C, 0x04 );  0x04
   pcd8544_send(LCD_C, 0x14 );  148.0x13
   pcd8544_send(LCD_C, 0x20 );  
   pcd8544_send(LCD_C, 0x0C );  
}

void pcd8544_send(uint8_t dc, uint8_t data)
{
   uint8_t i;
   if (dc == LCD_D)
      PORT_PCD8544 |= (1<<PIN_DC);
   else
      PORT_PCD8544 &= ~(1<<PIN_DC);

   PORT_PCD8544&=~(1<<PIN_SCE);
   for (i=0; i<8; i++)
   {
      PORT_PCD8544=(data & 0x80) ? PORT_PCD8544 | (1<<PIN_SDIN) : PORT_PCD8544 & ~(1<<PIN_SDIN);

      data=(data<<1);

      PORT_PCD8544|=(1<<PIN_SCLK);
      PORT_PCD8544&=~(1<<PIN_SCLK);
   }
   PORT_PCD8544|=(1<<PIN_SCE);
}

void pcd8544_print_string(char *str)
{
   while (*str)
   {
      pcd8544_send_char(*str++);
   }
}

void pcd8544_send_char(uint8_t ch)
{
   int i;
   if (ch >= 0x20 && ch <= 0x80)
   {
      pcd8544_send(LCD_D, 0x00);
      for (i = 0; i < 5; i++)
      {
     pcd8544_send(LCD_D,  ASCII[ch - 0x20][i]);
      }
      pcd8544_send(LCD_D, 0x00);
   }
}
void pcd8544_clear(void)
{
   int i;
   for (i=0; i < LCD_X * LCD_Y / 8; i++)
   {
      pcd8544_send(LCD_D, 0x00);
   }
}

void pcd8544_set_cursor(uint8_t x, uint8_t y) {
    x=x%12; y=y%6;
    pcd8544_send(LCD_C, 0x40+y);
    pcd8544_send(LCD_C, 0x80+x*7);
}

void pcd8544_print_at(char *str, uint8_t x, uint8_t y)
{
    pcd8544_set_cursor(x,y);
    while (*str)
    {
        pcd8544_send_char(*str++);
    }
}

Результат:

4) Переподключение дисплея на аппаратный SPI в Proteus

Теперь мы можем переподключить дисплей на аппаратную SPI шину ATmega8.

Для использования SPI, дисплей нужно будет переподключить следующим образом:

Обращаю внимание, что вывод D/C— дисплея я переподключил с PD5 на PD7. В этом нет особой необходимости, просто мне удобнее использовать крайние пины.

Именованные константы:

#define PIN_SCE   PD7
#define PIN_RESET PD6
#define PIN_DC    PD5
#define PIN_SDIN  PD4
#define PIN_SCLK  PD3

меняются на:

#define PIN_RESET PD6
#define PIN_DC    PD7

#define PIN_SCE   PB2
#define PIN_SDIN  PB3
#define PIN_SCLK  PB5

В функции инициализации дисплея void pcd8544_init(void), строка:

DDR_PCD8544 |= (1<<PIN_SCE) | (1<<PIN_RESET) | (1<<PIN_DC) | (1<<PIN_SDIN) | (1<<PIN_SCLK);

заменяется на:

DDR_PCD8544 |=(1<<PIN_RESET) | (1<<PIN_DC);
DDRB |= (1<<PIN_SCE) | (1<<PIN_SDIN) | (1<<PIN_SCLK);


SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0); 

Ну и последнее, в функции void pcd8544_send(uint8_t dc, uint8_t data), программный SPI:

PORT_PCD8544&=~(1<<PIN_SCE);
for (i=0; i<8; i++)
{
  PORT_PCD8544=(data & 0x80) ? PORT_PCD8544 | (1<<PIN_SDIN) : PORT_PCD8544 & ~(1<<PIN_SDIN);

  data=(data<<1);

  PORT_PCD8544|=(1<<PIN_SCLK);
  PORT_PCD8544&=~(1<<PIN_SCLK);
}
PORT_PCD8544|=(1<<PIN_SCE);

заменяется на аппаратный:

PORTB&=~(1<<PIN_SCE);

SPDR=data;
while(!(SPSR & (1<<SPIF)));

PORTB|=(1<<PIN_SCE);

Это все. Полный исходник под спойлером.

показать полный код

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

#define PIN_RESET PD6
#define PIN_DC    PD7

#define PIN_SCE   PB2
#define PIN_SDIN  PB3
#define PIN_SCLK  PB5

#define LCD_C     0x00
#define LCD_D     0x01

#define LCD_X     84
#define LCD_Y     48

#define PORT_PCD8544 PORTD
#define DDR_PCD8544  DDRD

static const uint8_t ASCII[][5] =
{
 {0x00, 0x00, 0x00, 0x00, 0x00} 20
,{0x00, 0x00, 0x5f, 0x00, 0x00} 21
,{0x00, 0x07, 0x00, 0x07, 0x00} 22"
,{0x14, 0x7f, 0x14, 0x7f, 0x14} 23
,{0x24, 0x2a, 0x7f, 0x2a, 0x12} 24
,{0x23, 0x13, 0x08, 0x64, 0x62} 25
,{0x36, 0x49, 0x55, 0x22, 0x50} 26
,{0x00, 0x05, 0x03, 0x00, 0x00} 27
,{0x00, 0x1c, 0x22, 0x41, 0x00} 28
,{0x00, 0x41, 0x22, 0x1c, 0x00} 29
,{0x14, 0x08, 0x3e, 0x08, 0x14} 
,{0x08, 0x08, 0x3e, 0x08, 0x08} 
,{0x00, 0x50, 0x30, 0x00, 0x00} 
,{0x08, 0x08, 0x08, 0x08, 0x08} 
,{0x00, 0x60, 0x60, 0x00, 0x00} 
,{0x20, 0x10, 0x08, 0x04, 0x02} 2f
,{0x3e, 0x51, 0x49, 0x45, 0x3e} 300
,{0x00, 0x42, 0x7f, 0x40, 0x00} 311
,{0x42, 0x61, 0x51, 0x49, 0x46} 322
,{0x21, 0x41, 0x45, 0x4b, 0x31} 333
,{0x18, 0x14, 0x12, 0x7f, 0x10} 344
,{0x27, 0x45, 0x45, 0x45, 0x39} 355
,{0x3c, 0x4a, 0x49, 0x49, 0x30} 366
,{0x01, 0x71, 0x09, 0x05, 0x03} 377
,{0x36, 0x49, 0x49, 0x49, 0x36} 388
,{0x06, 0x49, 0x49, 0x29, 0x1e} 399
,{0x00, 0x36, 0x36, 0x00, 0x00} 
,{0x00, 0x56, 0x36, 0x00, 0x00} 
,{0x08, 0x14, 0x22, 0x41, 0x00} 
,{0x14, 0x14, 0x14, 0x14, 0x14} 
,{0x00, 0x41, 0x22, 0x14, 0x08} 
,{0x02, 0x01, 0x51, 0x09, 0x06} 3f
,{0x32, 0x49, 0x79, 0x41, 0x3e} 40
,{0x7e, 0x11, 0x11, 0x11, 0x7e} 41
,{0x7f, 0x49, 0x49, 0x49, 0x36} 42
,{0x3e, 0x41, 0x41, 0x41, 0x22} 43
,{0x7f, 0x41, 0x41, 0x22, 0x1c} 44
,{0x7f, 0x49, 0x49, 0x49, 0x41} 45
,{0x7f, 0x09, 0x09, 0x09, 0x01} 46
,{0x3e, 0x41, 0x49, 0x49, 0x7a} 47
,{0x7f, 0x08, 0x08, 0x08, 0x7f} 48
,{0x00, 0x41, 0x7f, 0x41, 0x00} 49
,{0x20, 0x40, 0x41, 0x3f, 0x01} 
,{0x7f, 0x08, 0x14, 0x22, 0x41} 
,{0x7f, 0x40, 0x40, 0x40, 0x40} 
,{0x7f, 0x02, 0x0c, 0x02, 0x7f} 
,{0x7f, 0x04, 0x08, 0x10, 0x7f} 
,{0x3e, 0x41, 0x41, 0x41, 0x3e} 4f
,{0x7f, 0x09, 0x09, 0x09, 0x06} 50
,{0x3e, 0x41, 0x51, 0x21, 0x5e} 51
,{0x7f, 0x09, 0x19, 0x29, 0x46} 52
,{0x46, 0x49, 0x49, 0x49, 0x31} 53
,{0x01, 0x01, 0x7f, 0x01, 0x01} 54
,{0x3f, 0x40, 0x40, 0x40, 0x3f} 55
,{0x1f, 0x20, 0x40, 0x20, 0x1f} 56
,{0x3f, 0x40, 0x38, 0x40, 0x3f} 57
,{0x63, 0x14, 0x08, 0x14, 0x63} 58
,{0x07, 0x08, 0x70, 0x08, 0x07} 59
,{0x61, 0x51, 0x49, 0x45, 0x43} 
,{0x00, 0x7f, 0x41, 0x41, 0x00} 
,{0x02, 0x04, 0x08, 0x10, 0x20} 
,{0x00, 0x41, 0x41, 0x7f, 0x00} 
,{0x04, 0x02, 0x01, 0x02, 0x04} 
,{0x40, 0x40, 0x40, 0x40, 0x40} 5f
,{0x00, 0x01, 0x02, 0x04, 0x00} 60
,{0x20, 0x54, 0x54, 0x54, 0x78} 61
,{0x7f, 0x48, 0x44, 0x44, 0x38} 62
,{0x38, 0x44, 0x44, 0x44, 0x20} 63
,{0x38, 0x44, 0x44, 0x48, 0x7f} 64
,{0x38, 0x54, 0x54, 0x54, 0x18} 65
,{0x08, 0x7e, 0x09, 0x01, 0x02} 66
,{0x0c, 0x52, 0x52, 0x52, 0x3e} 67
,{0x7f, 0x08, 0x04, 0x04, 0x78} 68
,{0x00, 0x44, 0x7d, 0x40, 0x00} 69
,{0x20, 0x40, 0x44, 0x3d, 0x00} 
,{0x7f, 0x10, 0x28, 0x44, 0x00} 
,{0x00, 0x41, 0x7f, 0x40, 0x00} 
,{0x7c, 0x04, 0x18, 0x04, 0x78} 
,{0x7c, 0x08, 0x04, 0x04, 0x78} 
,{0x38, 0x44, 0x44, 0x44, 0x38} 6f
,{0x7c, 0x14, 0x14, 0x14, 0x08} 70
,{0x08, 0x14, 0x14, 0x18, 0x7c} 71
,{0x7c, 0x08, 0x04, 0x04, 0x08} 72
,{0x48, 0x54, 0x54, 0x54, 0x20} 73
,{0x04, 0x3f, 0x44, 0x40, 0x20} 74
,{0x3c, 0x40, 0x40, 0x20, 0x7c} 75
,{0x1c, 0x20, 0x40, 0x20, 0x1c} 76
,{0x3c, 0x40, 0x30, 0x40, 0x3c} 77
,{0x44, 0x28, 0x10, 0x28, 0x44} 78
,{0x0c, 0x50, 0x50, 0x50, 0x3c} 79
,{0x44, 0x64, 0x54, 0x4c, 0x44} 
,{0x00, 0x08, 0x36, 0x41, 0x00} 
,{0x00, 0x00, 0x7f, 0x00, 0x00} 
,{0x00, 0x41, 0x36, 0x08, 0x00} 
,{0x10, 0x08, 0x08, 0x10, 0x08} 
,{0x78, 0x46, 0x41, 0x46, 0x78} 7f
};

void pcd8544_init(void);
void pcd8544_send(uint8_t dc, uint8_t data);
void pcd8544_print_string(char *str);
void pcd8544_send_char(uint8_t ch);
void pcd8544_clear(void);
void pcd8544_set_cursor(uint8_t x, uint8_t y);
void pcd8544_print_at(char *str, uint8_t x, uint8_t y);

int main(void)
{
   pcd8544_init();
   pcd8544_clear();
   pcd8544_print_at("Nokia 3310",1,0);
   pcd8544_print_at("Connecting",1,2);
   pcd8544_print_at("People",6,3);

   for (;;){
      _delay_ms(1000);
   }

   return 0;
}

void pcd8544_init(void)
{

   
   DDR_PCD8544 |=(1<<PIN_RESET) | (1<<PIN_DC);
   DDRB |= (1<<PIN_SCE) | (1<<PIN_SDIN) | (1<<PIN_SCLK);

   
   SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0); 

   PORT_PCD8544&=~(1<<PIN_RESET);
   PORT_PCD8544|=(1<<PIN_RESET);
   pcd8544_send(LCD_C, 0x21 );  
   pcd8544_send(LCD_C, 0xBA );  
   pcd8544_send(LCD_C, 0x04 );  0x04
   pcd8544_send(LCD_C, 0x14 );  148.0x13
   pcd8544_send(LCD_C, 0x20 );  
   pcd8544_send(LCD_C, 0x0C );  
}

void pcd8544_send(uint8_t dc, uint8_t data)
{
   
   if (dc == LCD_D)
      PORT_PCD8544 |= (1<<PIN_DC);
   else
      PORT_PCD8544 &= ~(1<<PIN_DC);

   PORTB&=~(1<<PIN_SCE);

   SPDR=data;
   while(!(SPSR & (1<<SPIF)));

   PORTB|=(1<<PIN_SCE);
}

void pcd8544_print_string(char *str)
{
   while (*str)
   {
      pcd8544_send_char(*str++);
   }
}

void pcd8544_send_char(uint8_t ch)
{
   int i;
   if (ch >= 0x20 && ch <= 0x80)
   {
      pcd8544_send(LCD_D, 0x00);
      for (i = 0; i < 5; i++)
      {
        pcd8544_send(LCD_D,  ASCII[ch - 0x20][i]);
      }
      pcd8544_send(LCD_D, 0x00);
   }
}
void pcd8544_clear(void)
{
   int i;
   for (i=0; i < LCD_X * LCD_Y / 8; i++)
   {
      pcd8544_send(LCD_D, 0x00);
   }
}

void pcd8544_set_cursor(uint8_t x, uint8_t y) {
    x=x%12; y=y%6;
    pcd8544_send(LCD_C, 0x40+y);
    pcd8544_send(LCD_C, 0x80+x*7);
}

void pcd8544_print_at(char *str, uint8_t x, uint8_t y)
{
    pcd8544_set_cursor(x,y);
    while (*str)
    {
        pcd8544_send_char(*str++);
    }
}

5) Функции масштабирование шрифта в два и три раза

Пока отбросим аппаратный SPI в сторону и продолжим работать с программным.

Т.к. дисплей маленький, одной из самых востребованных функций является алгоритмическое увеличение шрифта.

Для увеличения шрифта в два раза добавим такую функцию:

void pcd8544_send_char_size2(uint8_t ch, uint8_t x, uint8_t y) {
    uint8_t s[5]; 
    uint8_t r[20]; 
    uint8_t i,j;
   
    if (ch >= 0x20 && ch <= 0x80)
    {
        for (i=0; i < 5; i++)
        {
            s[i]=ASCII[ch-0x20][i];
        }
    }
    
    for(i=0;i<5;i++)
    {
        uint8_t b=0;
        uint8_t a=0;
        for(j=0;j<4;j++)
        {
            b=(s[i]>>j) & 0x01;
            a|=(b<<(j<<1)) | (b<<((j<<1)+1));
        }
        r[(i<<1)]=a;
        r[(i<<1)+1]=a;
    }

    for(i=0;i<5;i++)
    {
        uint8_t b=0;
        uint8_t a=0;
        for(j=0;j<4;j++)
        {
            b=(s[i]>>(j+4)) & 0x01;
            a|=(b<<(j<<1)) | (b<<((j<<1)+1));
        }
        r[(i<<1)+10]=a;
        r[(i<<1)+11]=a;
    }
    
    pcd8544_set_cursor(x,y);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    for(i=0;i<10;i++)
        pcd8544_send(LCD_D, r[i]);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);

    pcd8544_set_cursor(x,y+1);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    for(i=10;i<20;i++)
        pcd8544_send(LCD_D, r[i]);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
}

А увеличение в три раза будет делать такая функция:

void pcd8544_send_char_size3(uint8_t ch, uint8_t x, uint8_t y) {
    uint8_t s[5]; 
    uint8_t r[45]; 
    uint8_t i;
    
    if (ch >= 0x20 && ch <= 0x80)
    {
        for (i=0; i < 5; i++)
        {
            s[i]=ASCII[ch-0x20][i];
        }
    }
    
    for(i=0;i<5;i++)
    {
        uint8_t b,a;
        b=(s[i] & 0x01);
        a=(b) ? 0x7 : 0;
        b=(s[i]>>1) & 0x01;
        if (b) a|=0x38;
        b=(s[i]>>2) & 0x01;
        a|=(b<<6)|(b<<7);

        r[i*3]=a;
        r[i*3+1]=a;
        r[i*3+2]=a;

        r[i*3+15]=b;
        r[i*3+16]=b;
        r[i*3+17]=b;
    }

    for(i=0;i<5;i++)
    {
        uint8_t b,a;
        b=(s[i]>>3) & 0x01;
        a=(b) ? 0x0e : 0;
        b=(s[i]>>4) & 0x01;
        if (b) a|=0x70;
        b=(s[i]>>5) & 0x01;
        a|=(b<<7);

        r[i*3+15]|=a;
        r[i*3+16]|=a;
        r[i*3+17]|=a;
     }

    for(i=0;i<5;i++)
    {
        uint8_t b,a;
        b=(s[i]>>5) & 0x01;
        a=(b) ? 0x3 : 0;
        b=(s[i]>>6) & 0x01;
        if (b) a|=0x1c;
        b=(s[i]>>7) & 0x01;
        if (b) a|=0xe0;

        r[i*3+30]=a;
        r[i*3+31]=a;
        r[i*3+32]=a;
     }

    
    pcd8544_set_cursor(x,y);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    for(i=0;i<15;i++)
        pcd8544_send(LCD_D, r[i]);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);

    pcd8544_set_cursor(x,y+1);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    for(i=15;i<30;i++)
        pcd8544_send(LCD_D, r[i]);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);

    pcd8544_set_cursor(x,y+2);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    for(i=30;i<45;i++)
        pcd8544_send(LCD_D, r[i]);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
}

Чтобы можно было печатать строки нужным размером шрифта, недавно введенную функцию void pcd8544_print_at() приведем к такому виду:

void pcd8544_print_at(char *str, uint8_t size,  uint8_t x, uint8_t y)
{
    uint8_t i=0;
    pcd8544_set_cursor(x,y);
    switch (size) {
      case 3:
      while (*str)
      {
         pcd8544_send_char_size3(*str++,x+i,y);
         i+=3;
      }
      break;
      case 2:
      while (*str)
      {
        pcd8544_send_char_size2(*str++,x+i,y);
        i+=2;
      }
      break;
      default:
      while (*str)
      {
        pcd8544_send_char(*str++);
      }
      break;
   }
}

И последнее, что нам нужно от шрифтов, это печать небольшого целого числа.

void pcd8544_print_uint8_at(uint8_t num, uint8_t size, uint8_t x, uint8_t y){
    uint8_t sym[3];
    int8_t i=2;
    do  {
      if (num == 0 && i<2)
        sym[i]=0x20; 
      else
        sym[i]=0x30+num%10;

      num=num/10;
      i--;

    } while (i>=0);

    uint8_t j=0;
    for (i=0;i<3;i++)
    {
        if (!(i<2 && sym[i] == 0x20))
        {
            switch(size) {
            case 3:
                pcd8544_send_char_size3(sym[i],x+j*size,y);
                break;
            case 2:
                pcd8544_send_char_size2(sym[i],x+j*size,y);
                break;
            default:
                pcd8544_send_char(sym[i]);
                break;
            }
            j++;
        }
    }

Для теста, в функции main() сделаем печать шрифта крупным шрифтом:

int main(void)
{
   pcd8544_init();
   uint8_t i=0;
   for (;;){
      pcd8544_clear();
      pcd8544_print_at(">",3,0,2);
      pcd8544_print_uint8_at(i++,3,3,2);
      _delay_ms(1000);
   }

   return 0;
}

Результат работы, без анимации:

Полный листинг программы под спойлером:

показать полный код

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

#define PIN_SCE   PD7
#define PIN_RESET PD6
#define PIN_DC    PD5
#define PIN_SDIN  PD4
#define PIN_SCLK  PD3

#define LCD_C     0x00
#define LCD_D     0x01

#define LCD_X     84
#define LCD_Y     48

#define PORT_PCD8544 PORTD
#define DDR_PCD8544  DDRD

static const uint8_t ASCII[][5] =
{
 {0x00, 0x00, 0x00, 0x00, 0x00} 20
,{0x00, 0x00, 0x5f, 0x00, 0x00} 21
,{0x00, 0x07, 0x00, 0x07, 0x00} 22"
,{0x14, 0x7f, 0x14, 0x7f, 0x14} 23
,{0x24, 0x2a, 0x7f, 0x2a, 0x12} 24
,{0x23, 0x13, 0x08, 0x64, 0x62} 25
,{0x36, 0x49, 0x55, 0x22, 0x50} 26
,{0x00, 0x05, 0x03, 0x00, 0x00} 27
,{0x00, 0x1c, 0x22, 0x41, 0x00} 28
,{0x00, 0x41, 0x22, 0x1c, 0x00} 29
,{0x14, 0x08, 0x3e, 0x08, 0x14} 
,{0x08, 0x08, 0x3e, 0x08, 0x08} 
,{0x00, 0x50, 0x30, 0x00, 0x00} 
,{0x08, 0x08, 0x08, 0x08, 0x08} 
,{0x00, 0x60, 0x60, 0x00, 0x00} 
,{0x20, 0x10, 0x08, 0x04, 0x02} 2f
,{0x3e, 0x51, 0x49, 0x45, 0x3e} 300
,{0x00, 0x42, 0x7f, 0x40, 0x00} 311
,{0x42, 0x61, 0x51, 0x49, 0x46} 322
,{0x21, 0x41, 0x45, 0x4b, 0x31} 333
,{0x18, 0x14, 0x12, 0x7f, 0x10} 344
,{0x27, 0x45, 0x45, 0x45, 0x39} 355
,{0x3c, 0x4a, 0x49, 0x49, 0x30} 366
,{0x01, 0x71, 0x09, 0x05, 0x03} 377
,{0x36, 0x49, 0x49, 0x49, 0x36} 388
,{0x06, 0x49, 0x49, 0x29, 0x1e} 399
,{0x00, 0x36, 0x36, 0x00, 0x00} 
,{0x00, 0x56, 0x36, 0x00, 0x00} 
,{0x08, 0x14, 0x22, 0x41, 0x00} 
,{0x14, 0x14, 0x14, 0x14, 0x14} 
,{0x00, 0x41, 0x22, 0x14, 0x08} 
,{0x02, 0x01, 0x51, 0x09, 0x06} 3f
,{0x32, 0x49, 0x79, 0x41, 0x3e} 40
,{0x7e, 0x11, 0x11, 0x11, 0x7e} 41
,{0x7f, 0x49, 0x49, 0x49, 0x36} 42
,{0x3e, 0x41, 0x41, 0x41, 0x22} 43
,{0x7f, 0x41, 0x41, 0x22, 0x1c} 44
,{0x7f, 0x49, 0x49, 0x49, 0x41} 45
,{0x7f, 0x09, 0x09, 0x09, 0x01} 46
,{0x3e, 0x41, 0x49, 0x49, 0x7a} 47
,{0x7f, 0x08, 0x08, 0x08, 0x7f} 48
,{0x00, 0x41, 0x7f, 0x41, 0x00} 49
,{0x20, 0x40, 0x41, 0x3f, 0x01} 
,{0x7f, 0x08, 0x14, 0x22, 0x41} 
,{0x7f, 0x40, 0x40, 0x40, 0x40} 
,{0x7f, 0x02, 0x0c, 0x02, 0x7f} 
,{0x7f, 0x04, 0x08, 0x10, 0x7f} 
,{0x3e, 0x41, 0x41, 0x41, 0x3e} 4f
,{0x7f, 0x09, 0x09, 0x09, 0x06} 50
,{0x3e, 0x41, 0x51, 0x21, 0x5e} 51
,{0x7f, 0x09, 0x19, 0x29, 0x46} 52
,{0x46, 0x49, 0x49, 0x49, 0x31} 53
,{0x01, 0x01, 0x7f, 0x01, 0x01} 54
,{0x3f, 0x40, 0x40, 0x40, 0x3f} 55
,{0x1f, 0x20, 0x40, 0x20, 0x1f} 56
,{0x3f, 0x40, 0x38, 0x40, 0x3f} 57
,{0x63, 0x14, 0x08, 0x14, 0x63} 58
,{0x07, 0x08, 0x70, 0x08, 0x07} 59
,{0x61, 0x51, 0x49, 0x45, 0x43} 
,{0x00, 0x7f, 0x41, 0x41, 0x00} 
,{0x02, 0x04, 0x08, 0x10, 0x20} 
,{0x00, 0x41, 0x41, 0x7f, 0x00} 
,{0x04, 0x02, 0x01, 0x02, 0x04} 
,{0x40, 0x40, 0x40, 0x40, 0x40} 5f
,{0x00, 0x01, 0x02, 0x04, 0x00} 60
,{0x20, 0x54, 0x54, 0x54, 0x78} 61
,{0x7f, 0x48, 0x44, 0x44, 0x38} 62
,{0x38, 0x44, 0x44, 0x44, 0x20} 63
,{0x38, 0x44, 0x44, 0x48, 0x7f} 64
,{0x38, 0x54, 0x54, 0x54, 0x18} 65
,{0x08, 0x7e, 0x09, 0x01, 0x02} 66
,{0x0c, 0x52, 0x52, 0x52, 0x3e} 67
,{0x7f, 0x08, 0x04, 0x04, 0x78} 68
,{0x00, 0x44, 0x7d, 0x40, 0x00} 69
,{0x20, 0x40, 0x44, 0x3d, 0x00} 
,{0x7f, 0x10, 0x28, 0x44, 0x00} 
,{0x00, 0x41, 0x7f, 0x40, 0x00} 
,{0x7c, 0x04, 0x18, 0x04, 0x78} 
,{0x7c, 0x08, 0x04, 0x04, 0x78} 
,{0x38, 0x44, 0x44, 0x44, 0x38} 6f
,{0x7c, 0x14, 0x14, 0x14, 0x08} 70
,{0x08, 0x14, 0x14, 0x18, 0x7c} 71
,{0x7c, 0x08, 0x04, 0x04, 0x08} 72
,{0x48, 0x54, 0x54, 0x54, 0x20} 73
,{0x04, 0x3f, 0x44, 0x40, 0x20} 74
,{0x3c, 0x40, 0x40, 0x20, 0x7c} 75
,{0x1c, 0x20, 0x40, 0x20, 0x1c} 76
,{0x3c, 0x40, 0x30, 0x40, 0x3c} 77
,{0x44, 0x28, 0x10, 0x28, 0x44} 78
,{0x0c, 0x50, 0x50, 0x50, 0x3c} 79
,{0x44, 0x64, 0x54, 0x4c, 0x44} 
,{0x00, 0x08, 0x36, 0x41, 0x00} 
,{0x00, 0x00, 0x7f, 0x00, 0x00} 
,{0x00, 0x41, 0x36, 0x08, 0x00} 
,{0x10, 0x08, 0x08, 0x10, 0x08} 
,{0x78, 0x46, 0x41, 0x46, 0x78} 7f
};

void pcd8544_init(void);
void pcd8544_send(uint8_t dc, uint8_t data);
void pcd8544_print_string(char *str);
void pcd8544_send_char(uint8_t ch);
void pcd8544_clear(void);
void pcd8544_set_cursor(uint8_t x, uint8_t y);
void pcd8544_print_at(char *str, uint8_t size, uint8_t x, uint8_t y);
void pcd8544_send_char_size2(uint8_t ch, uint8_t x, uint8_t y);
void pcd8544_send_char_size3(uint8_t ch, uint8_t x, uint8_t y);
void pcd8544_print_uint8_at(uint8_t num, uint8_t size, uint8_t x, uint8_t y);

int main(void)
{
   pcd8544_init();
   uint8_t i=0;
   for (;;){
      pcd8544_clear();
      pcd8544_print_at(">",3,0,2);
      pcd8544_print_uint8_at(i++,3,3,2);
      _delay_ms(1000);
   }

   return 0;
}

void pcd8544_init(void)
{
   
   DDR_PCD8544 |= (1<<PIN_SCE) | (1<<PIN_RESET) | (1<<PIN_DC) | (1<<PIN_SDIN) | (1<<PIN_SCLK);
   PORT_PCD8544&=~(1<<PIN_RESET);
   PORT_PCD8544|=(1<<PIN_RESET);
   pcd8544_send(LCD_C, 0x21 );  
   pcd8544_send(LCD_C, 0xBA );  
   pcd8544_send(LCD_C, 0x04 );  0x04
   pcd8544_send(LCD_C, 0x14 );  148.0x13
   pcd8544_send(LCD_C, 0x20 );  
   pcd8544_send(LCD_C, 0x0C );  
}

void pcd8544_send(uint8_t dc, uint8_t data)
{
   uint8_t i;
   if (dc == LCD_D)
      PORT_PCD8544 |= (1<<PIN_DC);
   else
      PORT_PCD8544 &= ~(1<<PIN_DC);

   PORT_PCD8544&=~(1<<PIN_SCE);
   for (i=0; i<8; i++)
   {
      PORT_PCD8544=(data & 0x80) ? PORT_PCD8544 | (1<<PIN_SDIN) : PORT_PCD8544 & ~(1<<PIN_SDIN);

      data=(data<<1);

      PORT_PCD8544|=(1<<PIN_SCLK);
      PORT_PCD8544&=~(1<<PIN_SCLK);
   }
   PORT_PCD8544|=(1<<PIN_SCE);
}

void pcd8544_print_string(char *str)
{
   while (*str)
   {
      pcd8544_send_char(*str++);
   }
}

void pcd8544_send_char(uint8_t ch)
{
   int i;
   if (ch >= 0x20 && ch <= 0x80)
   {
      pcd8544_send(LCD_D, 0x00);
      for (i = 0; i < 5; i++)
      {
         pcd8544_send(LCD_D,  ASCII[ch - 0x20][i]);
      }
      pcd8544_send(LCD_D, 0x00);
   }
}
void pcd8544_clear(void)
{
   int i;
   for (i=0; i < LCD_X * LCD_Y / 8; i++)
   {
      pcd8544_send(LCD_D, 0x00);
   }
}

void pcd8544_set_cursor(uint8_t x, uint8_t y) {
    x=x%12; y=y%6;
    pcd8544_send(LCD_C, 0x40+y);
    pcd8544_send(LCD_C, 0x80+x*7);
}

void pcd8544_print_at(char *str, uint8_t size,  uint8_t x, uint8_t y)
{
    uint8_t i=0;
    pcd8544_set_cursor(x,y);
    switch (size) {
      case 3:
      while (*str)
      {
         pcd8544_send_char_size3(*str++,x+i,y);
         i+=3;
      }
      break;
      case 2:
      while (*str)
      {
        pcd8544_send_char_size2(*str++,x+i,y);
        i+=2;
      }
      break;
      default:
      while (*str)
      {
        pcd8544_send_char(*str++);
      }
      break;
   }
}

void pcd8544_send_char_size2(uint8_t ch, uint8_t x, uint8_t y) {
    uint8_t s[5]; 
    uint8_t r[20]; 
    uint8_t i,j;
   
    if (ch >= 0x20 && ch <= 0x80)
    {
        for (i=0; i < 5; i++)
        {
            s[i]=ASCII[ch-0x20][i];
        }
    }
    
    for(i=0;i<5;i++)
    {
        uint8_t b=0;
        uint8_t a=0;
        for(j=0;j<4;j++)
        {
            b=(s[i]>>j) & 0x01;
            a|=(b<<(j<<1)) | (b<<((j<<1)+1));
        }
        r[(i<<1)]=a;
        r[(i<<1)+1]=a;
    }

    for(i=0;i<5;i++)
    {
        uint8_t b=0;
        uint8_t a=0;
        for(j=0;j<4;j++)
        {
            b=(s[i]>>(j+4)) & 0x01;
            a|=(b<<(j<<1)) | (b<<((j<<1)+1));
        }
        r[(i<<1)+10]=a;
        r[(i<<1)+11]=a;
    }
    
    pcd8544_set_cursor(x,y);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    for(i=0;i<10;i++)
        pcd8544_send(LCD_D, r[i]);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);

    pcd8544_set_cursor(x,y+1);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    for(i=10;i<20;i++)
        pcd8544_send(LCD_D, r[i]);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
}
void pcd8544_send_char_size3(uint8_t ch, uint8_t x, uint8_t y) {
    uint8_t s[5]; 
    uint8_t r[45]; 
    uint8_t i;
    
    if (ch >= 0x20 && ch <= 0x80)
    {
        for (i=0; i < 5; i++)
        {
            s[i]=ASCII[ch-0x20][i];
        }
    }
    
    for(i=0;i<5;i++)
    {
        uint8_t b,a;
        b=(s[i] & 0x01);
        a=(b) ? 0x7 : 0;
        b=(s[i]>>1) & 0x01;
        if (b) a|=0x38;
        b=(s[i]>>2) & 0x01;
        a|=(b<<6)|(b<<7);

        r[i*3]=a;
        r[i*3+1]=a;
        r[i*3+2]=a;

        r[i*3+15]=b;
        r[i*3+16]=b;
        r[i*3+17]=b;
    }

    for(i=0;i<5;i++)
    {
        uint8_t b,a;
        b=(s[i]>>3) & 0x01;
        a=(b) ? 0x0e : 0;
        b=(s[i]>>4) & 0x01;
        if (b) a|=0x70;
        b=(s[i]>>5) & 0x01;
        a|=(b<<7);

        r[i*3+15]|=a;
        r[i*3+16]|=a;
        r[i*3+17]|=a;
     }

    for(i=0;i<5;i++)
    {
        uint8_t b,a;
        b=(s[i]>>5) & 0x01;
        a=(b) ? 0x3 : 0;
        b=(s[i]>>6) & 0x01;
        if (b) a|=0x1c;
        b=(s[i]>>7) & 0x01;
        if (b) a|=0xe0;

        r[i*3+30]=a;
        r[i*3+31]=a;
        r[i*3+32]=a;
     }

    
    pcd8544_set_cursor(x,y);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    for(i=0;i<15;i++)
        pcd8544_send(LCD_D, r[i]);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);

    pcd8544_set_cursor(x,y+1);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    for(i=15;i<30;i++)
        pcd8544_send(LCD_D, r[i]);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);

    pcd8544_set_cursor(x,y+2);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    for(i=30;i<45;i++)
        pcd8544_send(LCD_D, r[i]);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
}

void pcd8544_print_uint8_at(uint8_t num, uint8_t size, uint8_t x, uint8_t y){
    uint8_t sym[3];
    int8_t i=2;
    do  {
      if (num == 0 && i<2)
        sym[i]=0x20; 
      else
        sym[i]=0x30+num%10;

      num=num/10;
      i--;

    } while (i>=0);

    uint8_t j=0;
    for (i=0;i<3;i++)
    {
        if (!(i<2 && sym[i] == 0x20))
        {
            switch(size) {
            case 3:
                pcd8544_send_char_size3(sym[i],x+j*size,y);
                break;
            case 2:
                pcd8544_send_char_size2(sym[i],x+j*size,y);
                break;
            default:
                pcd8544_send_char(sym[i]);
                break;
            }
            j++;
        }
    }
}

6) Создание проекта для реального микроконтроллера ATmega8, чтение таблицы ASCII из флеш-памяти

К сожалению, это все на был способен Proteus, поэтому переходим к реальному железу. Сейчас мы создадим проект и заодно перепишем код на хранение ascii-таблицы в флеш-памяти, с последующим чтением ее оттуда. Так следовало бы сделать с самого начала, если бы не Proteus :(

Итак, предполагаем, что используется Linux или CYGWIN в случае с Windows. Т.к. работа с флеш-памятью может меняться в зависимости от то ли версии avr-gcc то ли версии avr-libc, скажу что avr-libc у меня версии 1.8.1, а версия avr-gcc:

$ avr-gcc --version
avr-gcc (GCC) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Создаем структуру каталогов будущего проекта:

$ mkdir -p ./06_flash_ascii/{inc,src}

Заходим:

$ cd ./06_flash_ascii

Создаем Makefile такого содержания:

MCU=atmega8
OBJCOPY=avr-objcopy
CC=avr-gcc
CFLAGS=-mmcu=$(MCU) -Os -fdata-sections -ffunction-sections -DF_CPU=16000000UL -Wall -I ./inc
LDFLAGS=-mmcu=$(MCU) -Wl,--gc-sections  -Werror
OBJ=main.o pcd8544_soft.o
TARGET=lcd
.PHONY: all install clean

%.o:    ./src/%.c
        $(CC)  -c -o $@ $< $(CFLAGS)
all:    $(OBJ)
        $(CC) $(LDFLAGS) -o $(TARGET).elf  $(OBJ)
        $(OBJCOPY) -O ihex $(TARGET).elf $(TARGET).hex
install:
        avrdude  -p$(MCU) -c usbasp -p m8   -U flash:w:./$(TARGET).hex:i
clean:
        @rm -v *.elf *.hex $(OBJ)

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

Теперь создадим файл ./inc/ascii.h с нашей табличкой:

показать ./inc/ascii.h

#ifndef __ASCII_H__
#define __ASCII_H__
#include <avr/pgmspace.h>

const uint8_t ASCII[][5] PROGMEM = {
 {0x00, 0x00, 0x00, 0x00, 0x00} 20
,{0x00, 0x00, 0x5f, 0x00, 0x00} 21
,{0x00, 0x07, 0x00, 0x07, 0x00} 22"
,{0x14, 0x7f, 0x14, 0x7f, 0x14} 23
,{0x24, 0x2a, 0x7f, 0x2a, 0x12} 24
,{0x23, 0x13, 0x08, 0x64, 0x62} 25
,{0x36, 0x49, 0x55, 0x22, 0x50} 26
,{0x00, 0x05, 0x03, 0x00, 0x00} 27
,{0x00, 0x1c, 0x22, 0x41, 0x00} 28
,{0x00, 0x41, 0x22, 0x1c, 0x00} 29
,{0x14, 0x08, 0x3e, 0x08, 0x14} 
,{0x08, 0x08, 0x3e, 0x08, 0x08} 
,{0x00, 0x50, 0x30, 0x00, 0x00} 
,{0x08, 0x08, 0x08, 0x08, 0x08} 
,{0x00, 0x60, 0x60, 0x00, 0x00} 
,{0x20, 0x10, 0x08, 0x04, 0x02} 2f
,{0x3e, 0x51, 0x49, 0x45, 0x3e} 300
,{0x00, 0x42, 0x7f, 0x40, 0x00} 311
,{0x42, 0x61, 0x51, 0x49, 0x46} 322
,{0x21, 0x41, 0x45, 0x4b, 0x31} 333
,{0x18, 0x14, 0x12, 0x7f, 0x10} 344
,{0x27, 0x45, 0x45, 0x45, 0x39} 355
,{0x3c, 0x4a, 0x49, 0x49, 0x30} 366
,{0x01, 0x71, 0x09, 0x05, 0x03} 377
,{0x36, 0x49, 0x49, 0x49, 0x36} 388
,{0x06, 0x49, 0x49, 0x29, 0x1e} 399
,{0x00, 0x36, 0x36, 0x00, 0x00} 
,{0x00, 0x56, 0x36, 0x00, 0x00} 
,{0x08, 0x14, 0x22, 0x41, 0x00} 
,{0x14, 0x14, 0x14, 0x14, 0x14} 
,{0x00, 0x41, 0x22, 0x14, 0x08} 
,{0x02, 0x01, 0x51, 0x09, 0x06} 3f
,{0x32, 0x49, 0x79, 0x41, 0x3e} 40
,{0x7e, 0x11, 0x11, 0x11, 0x7e} 41
,{0x7f, 0x49, 0x49, 0x49, 0x36} 42
,{0x3e, 0x41, 0x41, 0x41, 0x22} 43
,{0x7f, 0x41, 0x41, 0x22, 0x1c} 44
,{0x7f, 0x49, 0x49, 0x49, 0x41} 45
,{0x7f, 0x09, 0x09, 0x09, 0x01} 46
,{0x3e, 0x41, 0x49, 0x49, 0x7a} 47
,{0x7f, 0x08, 0x08, 0x08, 0x7f} 48
,{0x00, 0x41, 0x7f, 0x41, 0x00} 49
,{0x20, 0x40, 0x41, 0x3f, 0x01} 
,{0x7f, 0x08, 0x14, 0x22, 0x41} 
,{0x7f, 0x40, 0x40, 0x40, 0x40} 
,{0x7f, 0x02, 0x0c, 0x02, 0x7f} 
,{0x7f, 0x04, 0x08, 0x10, 0x7f} 
,{0x3e, 0x41, 0x41, 0x41, 0x3e} 4f
,{0x7f, 0x09, 0x09, 0x09, 0x06} 50
,{0x3e, 0x41, 0x51, 0x21, 0x5e} 51
,{0x7f, 0x09, 0x19, 0x29, 0x46} 52
,{0x46, 0x49, 0x49, 0x49, 0x31} 53
,{0x01, 0x01, 0x7f, 0x01, 0x01} 54
,{0x3f, 0x40, 0x40, 0x40, 0x3f} 55
,{0x1f, 0x20, 0x40, 0x20, 0x1f} 56
,{0x3f, 0x40, 0x38, 0x40, 0x3f} 57
,{0x63, 0x14, 0x08, 0x14, 0x63} 58
,{0x07, 0x08, 0x70, 0x08, 0x07} 59
,{0x61, 0x51, 0x49, 0x45, 0x43} 
,{0x00, 0x7f, 0x41, 0x41, 0x00} 
,{0x02, 0x04, 0x08, 0x10, 0x20} 
,{0x00, 0x41, 0x41, 0x7f, 0x00} 
,{0x04, 0x02, 0x01, 0x02, 0x04} 
,{0x40, 0x40, 0x40, 0x40, 0x40} 5f
,{0x00, 0x01, 0x02, 0x04, 0x00} 60
,{0x20, 0x54, 0x54, 0x54, 0x78} 61
,{0x7f, 0x48, 0x44, 0x44, 0x38} 62
,{0x38, 0x44, 0x44, 0x44, 0x20} 63
,{0x38, 0x44, 0x44, 0x48, 0x7f} 64
,{0x38, 0x54, 0x54, 0x54, 0x18} 65
,{0x08, 0x7e, 0x09, 0x01, 0x02} 66
,{0x0c, 0x52, 0x52, 0x52, 0x3e} 67
,{0x7f, 0x08, 0x04, 0x04, 0x78} 68
,{0x00, 0x44, 0x7d, 0x40, 0x00} 69
,{0x20, 0x40, 0x44, 0x3d, 0x00} 
,{0x7f, 0x10, 0x28, 0x44, 0x00} 
,{0x00, 0x41, 0x7f, 0x40, 0x00} 
,{0x7c, 0x04, 0x18, 0x04, 0x78} 
,{0x7c, 0x08, 0x04, 0x04, 0x78} 
,{0x38, 0x44, 0x44, 0x44, 0x38} 6f
,{0x7c, 0x14, 0x14, 0x14, 0x08} 70
,{0x08, 0x14, 0x14, 0x18, 0x7c} 71
,{0x7c, 0x08, 0x04, 0x04, 0x08} 72
,{0x48, 0x54, 0x54, 0x54, 0x20} 73
,{0x04, 0x3f, 0x44, 0x40, 0x20} 74
,{0x3c, 0x40, 0x40, 0x20, 0x7c} 75
,{0x1c, 0x20, 0x40, 0x20, 0x1c} 76
,{0x3c, 0x40, 0x30, 0x40, 0x3c} 77
,{0x44, 0x28, 0x10, 0x28, 0x44} 78
,{0x0c, 0x50, 0x50, 0x50, 0x3c} 79
,{0x44, 0x64, 0x54, 0x4c, 0x44} 
,{0x00, 0x08, 0x36, 0x41, 0x00} 
,{0x00, 0x00, 0x7f, 0x00, 0x00} 
,{0x00, 0x41, 0x36, 0x08, 0x00} 
,{0x10, 0x08, 0x08, 0x10, 0x08} 
,{0x78, 0x46, 0x41, 0x46, 0x78} 7f
};

#endif

А также заголовочный файл библиотеки pcd8544 ./scr/pcd8544_soft.h

#ifndef __PCD8544_SOFT_H__
#define __PCD8544_SOFT_H__

#define PIN_SCE   PD7
#define PIN_RESET PD6
#define PIN_DC    PD5
#define PIN_SDIN  PD4
#define PIN_SCLK  PD3

#define LCD_C     0x00
#define LCD_D     0x01

#define LCD_X     84
#define LCD_Y     48

#define PORT_PCD8544 PORTD
#define DDR_PCD8544  DDRD

extern void pcd8544_init(void);
extern void pcd8544_send(uint8_t dc, uint8_t data);
extern void pcd8544_print_string(char *str);
extern void pcd8544_send_char(uint8_t ch);
extern void pcd8544_clear(void);
extern void pcd8544_set_cursor(uint8_t x, uint8_t y);
extern void pcd8544_print_at(char *str, uint8_t size, uint8_t x, uint8_t y);
extern void pcd8544_send_char_size2(uint8_t ch, uint8_t x, uint8_t y);
extern void pcd8544_send_char_size3(uint8_t ch, uint8_t x, uint8_t y);
extern void pcd8544_print_uint8_at(uint8_t num, uint8_t size, uint8_t x, uint8_t y);

#endif

В функции pcd8544_send_char(uint8_t ch):

void pcd8544_send_char(uint8_t ch)
{
   int i;
   if (ch >= 0x20 && ch <= 0x80)
   {
      pcd8544_send(LCD_D, 0x00);
      for (i = 0; i < 5; i++)
      {
         pcd8544_send(LCD_D,  ASCII[ch - 0x20][i]);
      }
      pcd8544_send(LCD_D, 0x00);
   }
}

— нужно будет добавить чтение из флеш-памяти(тема рассматривалась здесь)

void pcd8544_send_char(uint8_t ch)
{
   int i;
   char * ptr= (char *)(&ASCII);
   if (ch >= 0x20 && ch <= 0x80)
   {
      pcd8544_send(LCD_D, 0x00);
      for (i = 0; i < 5; i++)
      {
            uint8_t c=ch - 0x20;
            c=pgm_read_byte(ptr+c*5+i);
            pcd8544_send(LCD_D,  c);
      }
      pcd8544_send(LCD_D, 0x00);
   }
}

Тоже самое нужно будет сделать в функциях void pcd8544_send_char_size2(uint8_t ch, uint8_t x, uint8_t y) и void pcd8544_send_char_size3(uint8_t ch, uint8_t x, uint8_t y).

Все функции мы скинем в библиотечный файл /src/pcd8544_soft.c

показать /src/pcd8544_soft.c

#include "ascii.h"
#include "pcd8544_soft.h"

void pcd8544_init(void)
{
   
   DDR_PCD8544 |= (1<<PIN_SCE) | (1<<PIN_RESET) | (1<<PIN_DC) | (1<<PIN_SDIN) | (1<<PIN_SCLK);
   PORT_PCD8544&=~(1<<PIN_RESET);
   PORT_PCD8544|=(1<<PIN_RESET);
   pcd8544_send(LCD_C, 0x21 );  
   pcd8544_send(LCD_C, 0xBA );  
   pcd8544_send(LCD_C, 0x04 );  0x04
   pcd8544_send(LCD_C, 0x14 );  148.0x13
   pcd8544_send(LCD_C, 0x20 );  
   pcd8544_send(LCD_C, 0x0C );  
}

void pcd8544_send(uint8_t dc, uint8_t data)
{
   uint8_t i;
   if (dc == LCD_D)
      PORT_PCD8544 |= (1<<PIN_DC);
   else
      PORT_PCD8544 &= ~(1<<PIN_DC);

   PORT_PCD8544&=~(1<<PIN_SCE);
   for (i=0; i<8; i++)
   {
      PORT_PCD8544=(data & 0x80) ? PORT_PCD8544 | (1<<PIN_SDIN) : PORT_PCD8544 & ~(1<<PIN_SDIN);

      data=(data<<1);

      PORT_PCD8544|=(1<<PIN_SCLK);
      PORT_PCD8544&=~(1<<PIN_SCLK);
   }
   PORT_PCD8544|=(1<<PIN_SCE);
}

void pcd8544_print_string(char *str)
{
   while (*str)
   {
      pcd8544_send_char(*str++);
   }
}

void pcd8544_send_char(uint8_t ch)
{
   int i;
   char * ptr= (char *)(&ASCII);
   if (ch >= 0x20 && ch <= 0x80)
   {
      pcd8544_send(LCD_D, 0x00);
      for (i = 0; i < 5; i++)
      {
            uint8_t c=ch - 0x20;
            c=pgm_read_byte(ptr+c*5+i);
            pcd8544_send(LCD_D,  c);
      }
      pcd8544_send(LCD_D, 0x00);
   }
}
void pcd8544_clear(void)
{
   int i;
   for (i=0; i < LCD_X * LCD_Y / 8; i++)
   {
      pcd8544_send(LCD_D, 0x00);
   }
}

void pcd8544_set_cursor(uint8_t x, uint8_t y) {
    x=x%12; y=y%6;
    pcd8544_send(LCD_C, 0x40+y);
    pcd8544_send(LCD_C, 0x80+x*7);
}

void pcd8544_print_at(char *str, uint8_t size,  uint8_t x, uint8_t y)
{
    uint8_t i=0;
    pcd8544_set_cursor(x,y);
    switch (size) {
      case 3:
      while (*str)
      {
         pcd8544_send_char_size3(*str++,x+i,y);
         i+=3;
      }
      break;
      case 2:
      while (*str)
      {
        pcd8544_send_char_size2(*str++,x+i,y);
        i+=2;
      }
      break;
      default:
      while (*str)
      {
        pcd8544_send_char(*str++);
      }
      break;
   }
}

void pcd8544_send_char_size2(uint8_t ch, uint8_t x, uint8_t y) {
    uint8_t s[5]; 
    uint8_t r[20]; 
    uint8_t i,j;
   
    char * ptr= (char *)(&ASCII);
    if (ch >= 0x20 && ch <= 0x80)
    {
        for (i=0; i < 5; i++)
        {
              uint8_t c=ch - 0x20;
              s[i]=pgm_read_byte(ptr+c*5+i);
        }
    }
    
    for(i=0;i<5;i++)
    {
        uint8_t b=0;
        uint8_t a=0;
        for(j=0;j<4;j++)
        {
            b=(s[i]>>j) & 0x01;
            a|=(b<<(j<<1)) | (b<<((j<<1)+1));
        }
        r[(i<<1)]=a;
        r[(i<<1)+1]=a;
    }

    for(i=0;i<5;i++)
    {
        uint8_t b=0;
        uint8_t a=0;
        for(j=0;j<4;j++)
        {
            b=(s[i]>>(j+4)) & 0x01;
            a|=(b<<(j<<1)) | (b<<((j<<1)+1));
        }
        r[(i<<1)+10]=a;
        r[(i<<1)+11]=a;
    }
    
    pcd8544_set_cursor(x,y);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    for(i=0;i<10;i++)
        pcd8544_send(LCD_D, r[i]);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);

    pcd8544_set_cursor(x,y+1);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    for(i=10;i<20;i++)
        pcd8544_send(LCD_D, r[i]);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
}
void pcd8544_send_char_size3(uint8_t ch, uint8_t x, uint8_t y) {
    uint8_t s[5]; 
    uint8_t r[45]; 
    uint8_t i;
    
    char * ptr= (char *)(&ASCII);
    if (ch >= 0x20 && ch <= 0x80)
    {
        for (i=0; i < 5; i++)
        {
              uint8_t c=ch - 0x20;
              s[i]=pgm_read_byte(ptr+c*5+i);
        }
    }
    
    for(i=0;i<5;i++)
    {
        uint8_t b,a;
        b=(s[i] & 0x01);
        a=(b) ? 0x7 : 0;
        b=(s[i]>>1) & 0x01;
        if (b) a|=0x38;
        b=(s[i]>>2) & 0x01;
        a|=(b<<6)|(b<<7);

        r[i*3]=a;
        r[i*3+1]=a;
        r[i*3+2]=a;

        r[i*3+15]=b;
        r[i*3+16]=b;
        r[i*3+17]=b;
    }

    for(i=0;i<5;i++)
    {
        uint8_t b,a;
        b=(s[i]>>3) & 0x01;
        a=(b) ? 0x0e : 0;
        b=(s[i]>>4) & 0x01;
        if (b) a|=0x70;
        b=(s[i]>>5) & 0x01;
        a|=(b<<7);

        r[i*3+15]|=a;
        r[i*3+16]|=a;
        r[i*3+17]|=a;
     }

    for(i=0;i<5;i++)
    {
        uint8_t b,a;
        b=(s[i]>>5) & 0x01;
        a=(b) ? 0x3 : 0;
        b=(s[i]>>6) & 0x01;
        if (b) a|=0x1c;
        b=(s[i]>>7) & 0x01;
        if (b) a|=0xe0;

        r[i*3+30]=a;
        r[i*3+31]=a;
        r[i*3+32]=a;
     }

    
    pcd8544_set_cursor(x,y);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    for(i=0;i<15;i++)
        pcd8544_send(LCD_D, r[i]);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);

    pcd8544_set_cursor(x,y+1);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    for(i=15;i<30;i++)
        pcd8544_send(LCD_D, r[i]);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);

    pcd8544_set_cursor(x,y+2);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    for(i=30;i<45;i++)
        pcd8544_send(LCD_D, r[i]);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
    pcd8544_send(LCD_D, 0x00);
}

void pcd8544_print_uint8_at(uint8_t num, uint8_t size, uint8_t x, uint8_t y){
    uint8_t sym[3];
    int8_t i=2;
    do  {
      if (num == 0 && i<2)
        sym[i]=0x20; 
      else
        sym[i]=0x30+num%10;

      num=num/10;
      i--;

    } while (i>=0);

    uint8_t j=0;
    for (i=0;i<3;i++)
    {
        if (!(i<2 && sym[i] == 0x20))
        {
            switch(size) {
            case 3:
                pcd8544_send_char_size3(sym[i],x+j*size,y);
                break;
            case 2:
                pcd8544_send_char_size2(sym[i],x+j*size,y);
                break;
            default:
                pcd8544_send_char(sym[i]);
                break;
            }
            j++;
        }
    }
}

В итоге остается непосредственно сама программа в main.c

#include "avr/io.h"
#include "util/delay.h"
#include "pcd8544_soft.h"

int main(void)
{
   pcd8544_init();
   uint8_t i=0;
   for (;;){
      pcd8544_clear();
      pcd8544_print_at(">",3,0,2);
      pcd8544_print_uint8_at(i++,3,3,2);
      _delay_ms(1000);
   }

   return 0;
}

По-моему гораздо, лучше, чем все в одном файле.

Результат работы:

Полные исходники к этому примеру можно посмотреть здесь:
https://gitlab.com/flank1er/pcd8544_atmega8/tree/master/06_flash_ascii

7) Добавляем кириллицу в кодировке CP866

Сложность с выводом русского текста на экран графического дисплея заключается в том, что тексты программ мы пишем в двухбайтовом юникоде. Не будем же вы кодировку юникода записывать в микроконтроллер? Поэтому вспоминаются былинные 8-битные кодировки: cp866, koi8-r и cp1251. И значит возникает необходимость преобразования одной кодировки в другую. Доходит до того, что это преобразование пытаются выполнять на стороне микроконтроллера. Нда..

Я выбрал кодировку CP866 из-за того, что там есть псевдографика. В свое время с ее использованием много чего делали: Лексикон, Дос Навигатор, Нортон Командер и т.д. Однако пока псевдографику трогать не будем, а будем заниматься непосредственно кириллицей. Кодовую таблицу CP866 можно посмотреть например здесь Таблица CP 866 DOS — Kvodo

Обращаю внимание, что строчными буквами «п» и «р» имеется разрыв на 48 символа псевдографики. В своей ASCII таблице мы все символы запишем единым массивом, соответственно индекс символа нужно будет корректировать.

Это значит, что вместо строки:

uint8_t c=ch - 0x20;

нужно будет использовать:

uint8_t c=(ch<0xe0) ? ch - 0x20 : ch - 0x50;

Для преобразования кодировок, в Makefile добавим новую цель:

prepare:
        cat main.c|iconv -f utf8 -t cp866 > cp866.c

Теперь для того чтобы перекодировать и сразу скомпилировать программу достаточно будет ввести команду:

$ make prepare && make all

Осталось табличный файл c ASCII дополнить русскими буквами:

показать /inc/ascii.h

#ifndef __ASCII_H__
#define __ASCII_H__
#include <avr/pgmspace.h>

480
const uint8_t ASCII[][5] PROGMEM = {
 {0x00, 0x00, 0x00, 0x00, 0x00} 20
,{0x00, 0x00, 0x5f, 0x00, 0x00} 21
,{0x00, 0x07, 0x00, 0x07, 0x00} 22"
,{0x14, 0x7f, 0x14, 0x7f, 0x14} 23
,{0x24, 0x2a, 0x7f, 0x2a, 0x12} 24
,{0x23, 0x13, 0x08, 0x64, 0x62} 25
,{0x36, 0x49, 0x55, 0x22, 0x50} 26
,{0x00, 0x05, 0x03, 0x00, 0x00} 27
,{0x00, 0x1c, 0x22, 0x41, 0x00} 28
,{0x00, 0x41, 0x22, 0x1c, 0x00} 29
,{0x14, 0x08, 0x3e, 0x08, 0x14} 
,{0x08, 0x08, 0x3e, 0x08, 0x08} 
,{0x00, 0x50, 0x30, 0x00, 0x00} 
,{0x08, 0x08, 0x08, 0x08, 0x08} 
,{0x00, 0x60, 0x60, 0x00, 0x00} 
,{0x20, 0x10, 0x08, 0x04, 0x02} 2f
,{0x3e, 0x51, 0x49, 0x45, 0x3e} 300
,{0x00, 0x42, 0x7f, 0x40, 0x00} 311
,{0x42, 0x61, 0x51, 0x49, 0x46} 322
,{0x21, 0x41, 0x45, 0x4b, 0x31} 333
,{0x18, 0x14, 0x12, 0x7f, 0x10} 344
,{0x27, 0x45, 0x45, 0x45, 0x39} 355
,{0x3c, 0x4a, 0x49, 0x49, 0x30} 366
,{0x01, 0x71, 0x09, 0x05, 0x03} 377
,{0x36, 0x49, 0x49, 0x49, 0x36} 388
,{0x06, 0x49, 0x49, 0x29, 0x1e} 399
,{0x00, 0x36, 0x36, 0x00, 0x00} 
,{0x00, 0x56, 0x36, 0x00, 0x00} 
,{0x08, 0x14, 0x22, 0x41, 0x00} 
,{0x14, 0x14, 0x14, 0x14, 0x14} 
,{0x00, 0x41, 0x22, 0x14, 0x08} 
,{0x02, 0x01, 0x51, 0x09, 0x06} 3f
,{0x32, 0x49, 0x79, 0x41, 0x3e} 40
,{0x7e, 0x11, 0x11, 0x11, 0x7e} 41
,{0x7f, 0x49, 0x49, 0x49, 0x36} 42
,{0x3e, 0x41, 0x41, 0x41, 0x22} 43
,{0x7f, 0x41, 0x41, 0x22, 0x1c} 44
,{0x7f, 0x49, 0x49, 0x49, 0x41} 45
,{0x7f, 0x09, 0x09, 0x09, 0x01} 46
,{0x3e, 0x41, 0x49, 0x49, 0x7a} 47
,{0x7f, 0x08, 0x08, 0x08, 0x7f} 48
,{0x00, 0x41, 0x7f, 0x41, 0x00} 49
,{0x20, 0x40, 0x41, 0x3f, 0x01} 
,{0x7f, 0x08, 0x14, 0x22, 0x41} 
,{0x7f, 0x40, 0x40, 0x40, 0x40} 
,{0x7f, 0x02, 0x0c, 0x02, 0x7f} 
,{0x7f, 0x04, 0x08, 0x10, 0x7f} 
,{0x3e, 0x41, 0x41, 0x41, 0x3e} 4f
,{0x7f, 0x09, 0x09, 0x09, 0x06} 50
,{0x3e, 0x41, 0x51, 0x21, 0x5e} 51
,{0x7f, 0x09, 0x19, 0x29, 0x46} 52
,{0x46, 0x49, 0x49, 0x49, 0x31} 53
,{0x01, 0x01, 0x7f, 0x01, 0x01} 54
,{0x3f, 0x40, 0x40, 0x40, 0x3f} 55
,{0x1f, 0x20, 0x40, 0x20, 0x1f} 56
,{0x3f, 0x40, 0x38, 0x40, 0x3f} 57
,{0x63, 0x14, 0x08, 0x14, 0x63} 58
,{0x07, 0x08, 0x70, 0x08, 0x07} 59
,{0x61, 0x51, 0x49, 0x45, 0x43} 
,{0x00, 0x7f, 0x41, 0x41, 0x00} 
,{0x02, 0x04, 0x08, 0x10, 0x20} 
,{0x00, 0x41, 0x41, 0x7f, 0x00} 
,{0x04, 0x02, 0x01, 0x02, 0x04} 
,{0x40, 0x40, 0x40, 0x40, 0x40} 5f
,{0x00, 0x01, 0x02, 0x04, 0x00} 60
,{0x20, 0x54, 0x54, 0x54, 0x78} 61
,{0x7f, 0x48, 0x44, 0x44, 0x38} 62
,{0x38, 0x44, 0x44, 0x44, 0x20} 63
,{0x38, 0x44, 0x44, 0x48, 0x7f} 64
,{0x38, 0x54, 0x54, 0x54, 0x18} 65
,{0x08, 0x7e, 0x09, 0x01, 0x02} 66
,{0x0c, 0x52, 0x52, 0x52, 0x3e} 67
,{0x7f, 0x08, 0x04, 0x04, 0x78} 68
,{0x00, 0x44, 0x7d, 0x40, 0x00} 69
,{0x20, 0x40, 0x44, 0x3d, 0x00} 
,{0x7f, 0x10, 0x28, 0x44, 0x00} 
,{0x00, 0x41, 0x7f, 0x40, 0x00} 
,{0x7c, 0x04, 0x18, 0x04, 0x78} 
,{0x7c, 0x08, 0x04, 0x04, 0x78} 
,{0x38, 0x44, 0x44, 0x44, 0x38} 6f
,{0x7c, 0x14, 0x14, 0x14, 0x08} 70
,{0x08, 0x14, 0x14, 0x18, 0x7c} 71
,{0x7c, 0x08, 0x04, 0x04, 0x08} 72
,{0x48, 0x54, 0x54, 0x54, 0x20} 73
,{0x04, 0x3f, 0x44, 0x40, 0x20} 74
,{0x3c, 0x40, 0x40, 0x20, 0x7c} 75
,{0x1c, 0x20, 0x40, 0x20, 0x1c} 76
,{0x3c, 0x40, 0x30, 0x40, 0x3c} 77
,{0x44, 0x28, 0x10, 0x28, 0x44} 78
,{0x0c, 0x50, 0x50, 0x50, 0x3c} 79
,{0x44, 0x64, 0x54, 0x4c, 0x44} 
,{0x00, 0x08, 0x36, 0x41, 0x00} 
,{0x00, 0x00, 0x7f, 0x00, 0x00} 
,{0x00, 0x41, 0x36, 0x08, 0x00} 
,{0x10, 0x08, 0x08, 0x10, 0x08} 
,{0x78, 0x46, 0x41, 0x46, 0x78} 7f
,{0x7e, 0x11, 0x11, 0x11, 0x7e}0x80
,{0x7f, 0x49, 0x49, 0x49, 0x33}0x81
,{0x7f, 0x49, 0x49, 0x49, 0x36}0x82
,{0x7f, 0x01, 0x01, 0x01, 0x03}0x83
,{0xe0, 0x51, 0x4f, 0x41, 0xff}0x84
,{0x7f, 0x49, 0x49, 0x49, 0x41}0x85
,{0x77, 0x08, 0x7f, 0x08, 0x77}0x86
,{0x41, 0x49, 0x49, 0x49, 0x36}0x87
,{0x7f, 0x10, 0x08, 0x04, 0x7f}0x88
,{0x7c, 0x21, 0x12, 0x09, 0x7c}0x89
,{0x7f, 0x08, 0x14, 0x22, 0x41}0x8A
,{0x20, 0x41, 0x3f, 0x01, 0x7f}0x8B
,{0x7f, 0x02, 0x0c, 0x02, 0x7f}0x8C
,{0x7f, 0x08, 0x08, 0x08, 0x7f}0x8D
,{0x3e, 0x41, 0x41, 0x41, 0x3e}0x8E
,{0x7f, 0x01, 0x01, 0x01, 0x7f}0x8F
,{0x7f, 0x09, 0x09, 0x09, 0x06}0x90
,{0x3e, 0x41, 0x41, 0x41, 0x22}0x91
,{0x01, 0x01, 0x7f, 0x01, 0x01}0x92
,{0x47, 0x28, 0x10, 0x08, 0x07}0x93
,{0x1c, 0x22, 0x7f, 0x22, 0x1c}0x94
,{0x63, 0x14, 0x08, 0x14, 0x63}0x95
,{0x7f, 0x40, 0x40, 0x40, 0xff}0x96
,{0x07, 0x08, 0x08, 0x08, 0x7f}0x97
,{0x7f, 0x40, 0x7f, 0x40, 0x7f}0x98
,{0x7f, 0x40, 0x7f, 0x40, 0xff}0x99
,{0x01, 0x7f, 0x48, 0x48, 0x30}0x9A
,{0x7f, 0x48, 0x30, 0x00, 0x7f}0x9B
,{0x00, 0x7f, 0x48, 0x48, 0x30}0x9C
,{0x22, 0x41, 0x49, 0x49, 0x3e}0x9D
,{0x7f, 0x08, 0x3e, 0x41, 0x3e}0x9E
,{0x46, 0x29, 0x19, 0x09, 0x7f}0x9F
,{0x20, 0x54, 0x54, 0x54, 0x78}0xA0
,{0x3c, 0x4a, 0x4a, 0x49, 0x31}0xA1
,{0x7c, 0x54, 0x54, 0x28, 0x00}0xA2
,{0x7c, 0x04, 0x04, 0x04, 0x0c}0xA3
,{0xe0, 0x54, 0x4c, 0x44, 0xfc}0xA4
,{0x38, 0x54, 0x54, 0x54, 0x18}0xA5
,{0x6c, 0x10, 0x7c, 0x10, 0x6c}0xA6
,{0x44, 0x44, 0x54, 0x54, 0x28}0xA7
,{0x7c, 0x20, 0x10, 0x08, 0x7c}0xA8
,{0x7c, 0x41, 0x22, 0x11, 0x7c}0xA9
,{0x7c, 0x10, 0x28, 0x44, 0x00}0xAA
,{0x20, 0x44, 0x3c, 0x04, 0x7c}0xAB
,{0x7c, 0x08, 0x10, 0x08, 0x7c}0xAC
,{0x7c, 0x10, 0x10, 0x10, 0x7c}0xAD
,{0x38, 0x44, 0x44, 0x44, 0x38}0xAE
,{0x7c, 0x04, 0x04, 0x04, 0x7c}0xAF
,{0x7C, 0x14, 0x14, 0x14, 0x08}0xE0
,{0x38, 0x44, 0x44, 0x44, 0x20}0xE1
,{0x04, 0x04, 0x7c, 0x04, 0x04}0xE2
,{0x0C, 0x50, 0x50, 0x50, 0x3C}0xE3
,{0x30, 0x48, 0xfc, 0x48, 0x30}0xE4
,{0x44, 0x28, 0x10, 0x28, 0x44}0xE5
,{0x7c, 0x40, 0x40, 0x40, 0xfc}0xE6
,{0x0c, 0x10, 0x10, 0x10, 0x7c}0xE7
,{0x7c, 0x40, 0x7c, 0x40, 0x7c}0xE8
,{0x7c, 0x40, 0x7c, 0x40, 0xfc}0xE9
,{0x04, 0x7c, 0x50, 0x50, 0x20}0xEA
,{0x7c, 0x50, 0x50, 0x20, 0x7c}0xEB
,{0x7c, 0x50, 0x50, 0x20, 0x00}0xEC
,{0x28, 0x44, 0x54, 0x54, 0x38}0xED
,{0x7c, 0x10, 0x38, 0x44, 0x38}0xEE
,{0x08, 0x54, 0x34, 0x14, 0x7c}0xEF
};

#endif

Шрифты брал вроде бы на arduino.ru, кто их первоначальный автор, я не знаю.

Ну и теперь, мы можем вывести на экран что-то осмысленное. main.c:

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

#define LEN 72
const unsigned char mystr[LEN] PROGMEM = {"оператор Лапласа это векторный дифференциальный оператор второго порядка"};

int main(void)
{
   pcd8544_init();
   pcd8544_clear();
   char * ptr= (char *)(&mystr);
   uint8_t i; for(i=0;i<LEN;i++)
   {
        pcd8544_send_char(pgm_read_byte(ptr+i));
   }

   for (;;){
      _delay_ms(1000);
   }

   return 0;
}

Результат работы:

Полные исходники к этому примеру можно посмотреть здесь:
https://gitlab.com/flank1er/pcd8544_atmega8/tree/master/07_cp866

8) Добавление фреймбуфера. Программа рисования фрактала.

Фреймбуфер — это буфер в оперативной памяти микроконтроллера, размер которого равен размеру видеопамяти дисплея.

Фреймбуфер нужен для того чтобы нарисовать на экране точку. Т.к. вся видеопамять дисплея pcd8544 упакована в 504 байта, для того чтобы нарисовать точку на экране, нужно определить номер байта к которому относится данная точка, прочитать этот байт, изменить в нем нужный бит относящийся к точке, и записать этот байт обратно. Однако с нашего дисплея ничего читать нельзя, дисплей доступен только для записи. Поэтому нужен фреймбуфер, чтобы поставить простую точку.

Микроконтроллер ATmega8 имеет 1 Kбайт оперативной памяти, и фреймбуфер будет занимать почти половину этой памяти. Но например такие микроконтроллеры как MSP430G2553 с 512 байтами SRAM, оказываются уже не у дел.

Для организации фреймбуфера, в файле pcd8544_soft.c объявим массив:

#define FB_LEN  504
static uint8_t fb[FB_LEN];
uint16_t pos;

Так же пригодиться переменная pos которая будет служить позицией виртуального курсора во фреймбуфере.

Для работы с фреймбуфер ом, понадобятся дополнительные функции для очистки содержимого фреймбуфера:

void pcd8544_clear_fb(void)
{
    for(pos=0;pos<FB_LEN; pos++)
        fb[pos]=0;
    pos=0;
}

и для вывода его содержимого на дисплей:

void pcd8544_display_fb() {
    int i;
    for(i=0;i<FB_LEN; i++)
        pcd8544_send(LCD_D,fb[i]);
}

Ну и само собой, потребуется небольшая работа по переписываю существующих функций для обеспечения поддержки работы с фреймбуфером.

Например в void pcd8544_send_char_fb(uint8_t ch) меняется всего одна строчка:

void pcd8544_send_char_fb(uint8_t ch)
{
    int i;
    char * ptr= (char *)(&ASCII);

    if (ch >= 0x20 && ch <= 0xf0 && pos <= (FB_LEN-7))
    {
        for (i=0; i < 5; i++)
        {
            uint8_t c=(ch<0xe0) ? ch - 0x20 : ch - 0x50;
            c=pgm_read_byte(ptr+c*5+i);
            fb[pos+i]|=c;
        }
        pos+=7;
    }
}

После завершения всей работы хорошо было бы проверить что все работает как надо. К примеру main.c из предыдущего примера у меня получился таким:

#include "avr/io.h"
#include "util/delay.h"
#include "pcd8544_soft.h"

int main(void)
{
   pcd8544_init();
   pcd8544_clear();
   uint8_t i=0;
   for (;;){
      pcd8544_clear_fb();
      pcd8544_print_at_fb(">",3,0,2);
      pcd8544_print_uint8_at_fb(i++,3,3,2);
      pcd8544_display_fb();
      _delay_ms(1000);
   }

   return 0;
}

Теперь для работы с дисплеем нужно сначала очищать содержимое фреймбуфера, а в конце выводить его содержимое на экран функцией pcd8544_display_fb();

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

void pcd8544_set_point(uint8_t x, uint8_t y) {
    if (x < LCD_X && y < LCD_Y)
    {
        uint16_t index = ((y>>3)*LCD_X)+x;
        fb[index]|=(1<<(y&0x07));
    }
}

Выглядит гадко, но это работает.

Ок. Теперь можно что-либо нарисовать. Я адаптировал программу из старой книжки по ZX Spectrum для отрисовки простенького фрактала:

#include "avr/io.h"
#include "util/delay.h"
#include "pcd8544_soft.h"

int main(void)
{
    int8_t x[17];
    int8_t y[17];
    pcd8544_init();
    pcd8544_clear();
    for (;;)
    {
        pcd8544_clear_fb();

        uint8_t i,j,k;
        for(i=1;i<=4;i++)
        {
            for(j=1;j<=4;j++)
            {
                k=4*i+j-4;
                x[k]=j-3;
                y[k]=i-3;
            }
        }

        x[2]=0;   y[2]=-3;
        x[8]=2;   y[8]=0;
        x[9]=-3;  y[9]=-1;
        x[15]=-1; y[15]=2;

        for(i=1;i<=16;i++)
        {
            for(j=1;j<=16;j++)
            {
                for(k=1;k<=16;k++)
                {
                    int8_t xx=(((x[i]<<4)+(x[j]<<2)+x[k])>>1);
                    int8_t yy=(((y[i]<<4)+(y[j]<<2)+y[k])>>1);
                    pcd8544_set_point(50+xx,28+yy);
                }
            }
        }

        pcd8544_display_fb();

        _delay_ms(1000);
   }

   return 0;
}

Результат работы выглядит так:

Полные исходники к этому примеру можно посмотреть здесь:
https://gitlab.com/flank1er/pcd8544_atmega8/tree/master/08_2_fractal

9) Делаем скринсейвер «сквозь звездное небо»

Фрактал штука интересная, но абсолютно бесполезная. Попробуем сделать что-нибудь более полезное. Допустим, что у нашего устройства имеется ждущий режим, во время которого на дисплее будет запускаться простая анимационная заставка.

На мой взгляд самая простая заставка это — «полет сквозь звездное небо».

Наиболее простой алгоритм этой заставки работает так: a) случайным образом формируется звездное небо для первой четверти координатной плоскости; б) картинка из первой четверти зеркалится на остальные четверти; в) при каждой итерации к х и у координатам «звезд» прибавляется по единице; г) при выходе «звезды» за пределы дисплея, случайно генерируется новая «звезда».

В итоге у меня получилась такая программа:

#include "avr/io.h"
#include "util/delay.h"
#include "stdlib.h"
#include "pcd8544_soft.h"

#define NUM 40
#define LCD_X 84
#define LCD_Y 48

uint8_t x[NUM];
uint8_t y[NUM];

int main(void)
{
    pcd8544_init();
    pcd8544_clear();
    uint8_t i,j;
    for(i=0;i<NUM;i++)
    {
        x[i]=rand()%(LCD_X/2);
        y[i]=rand()%(LCD_Y/2);
    }
    for (;;){
        for(i=0;i<NUM;i++)
        {
            if (x[i] == 0 || y[i] == 0)
            {
                x[i]=rand()%(LCD_X/2);
                y[i]=rand()%(LCD_Y/2);
            } else {
                x[i]=x[i]-1;
                y[i]=y[i]-1;
            }

        }

        pcd8544_clear_fb();
        for(i=0;i<4;i++)
        {
            for(j=0;j<NUM;j++)
                pcd8544_set_point(x[j],y[j]);
            for(j=0;j<NUM;j++)
                pcd8544_set_point(LCD_X-x[j],y[j]);
            for(j=0;j<NUM;j++)
                pcd8544_set_point(LCD_X-x[j],LCD_Y-y[j]);
            for(j=0;j<NUM;j++)
                pcd8544_set_point(x[j],LCD_Y-y[j]);

        }
        pcd8544_display_fb();
        _delay_ms(300);
   }

   return 0;
}

Результат:

исходники:
https://gitlab.com/flank1er/pcd8544_atmega8/tree/master/09_1_starsky

На мой взгляд, за счет симметрии выглядит несколько странно.

Второй вариант алгоритма отличается от первого тем, что «звезды» не зеркалятся, а генерируются случайным образом по всей плоскости дисплея.

Программа:

#include "avr/io.h"
#include "util/delay.h"
#include "stdlib.h"
#include "pcd8544_soft.h"

#define NUM 120
#define LCD_X 84
#define LCD_Y 48

uint8_t x[NUM];
uint8_t y[NUM];

int main(void)
{
    pcd8544_init();
    pcd8544_clear();
    uint8_t i,j;
    for(i=0;i<NUM;i++)
    {
        x[i]=rand()%(LCD_X);
        y[i]=rand()%(LCD_Y);
    }
    for (;;)
    {
        for(i=0;i<NUM;i++)
        {
            if (x[i] == 0 || y[i] == 0 || x[i] == LCD_X || y[i] == LCD_Y) 
            {
                x[i]=rand()%(LCD_X);
                y[i]=rand()%(LCD_Y);
            } else if (x[i] < LCD_X/2 && y[i] < LCD_Y/2) {
                x[i]=x[i]-1;
                y[i]=y[i]-1;
            } else if (x[i] < LCD_X/2 && y[i] >= LCD_Y/2) {
                x[i]=x[i]-1;
                y[i]=y[i]+1;
            } else if (x[i] >=  LCD_X/2 && y[i] <LCD_Y/2) {
                x[i]=x[i]+1;
                y[i]=y[i]-1;
            } else if (x[i] >= LCD_X/2 && y[i] >= LCD_Y/2) {
                x[i]=x[i]+1;
                y[i]=y[i]+1;
            }
        }
        pcd8544_clear_fb();

        for(j=0;j<NUM;j++)
            pcd8544_set_point(x[j],y[j]);

        pcd8544_display_fb();
        _delay_ms(200);
   }

   return 0;
}

Результат:

Теперь выглядит получше, но все-равно не так как я ожидал. Звездное небо хорошо смотрится на черном фоне 14-дюймового ЭЛТ монитора, а здесь, не то не сё. Ну да ладно.

исходники:
https://gitlab.com/flank1er/pcd8544_atmega8/tree/master/09_2_starsky

10) Функции рисования прямых линий, и окружностей

Целочисленные алгоритмы рисования прямых линий и окружностей можно скопировать из википедии Реализации алгоритмов/Алгоритм Брезенхэма

Т.о. функция рисования прямой линии получается такой:

void pcd8544_draw_line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) {
    const int deltaX = myabs(x2 - x1);
    const int deltaY = myabs(y2 - y1);
    const int signX = x1 < x2 ? 1 : -1;
    const int signY = y1 < y2 ? 1 : -1;

    int error = deltaX - deltaY;

    pcd8544_set_point(x2,y2);
    while(x1 != x2 || y1 != y2)
    {
        pcd8544_set_point(x1,y1);
        const int error2 = error * 2;

        if(error2 > -deltaY)
        {
            error -= deltaY;
            x1 += signX;
        }
        if(error2 < deltaX)
        {
            error += deltaX;
            y1 += signY;
        }
    }
}

А функция рисования окружности такой:

void pcd8544_draw_circle(uint8_t x0, uint8_t y0, uint8_t radius) {
    int x = 0;
    int y = radius;
    int delta = 1 - 2 * radius;
    int error = 0;
    while(y >= 0)
    {
        pcd8544_set_point(x0 + x, y0 + y);
        pcd8544_set_point(x0 + x, y0 - y);
        pcd8544_set_point(x0 - x, y0 + y);
        pcd8544_set_point(x0 - x, y0 - y);
        error = 2 * (delta + y) - 1;
        if(delta < 0 && error <= 0) {
            ++x;
            delta += 2 * x + 1;
            continue;
        }
        error = 2 * (delta - x) - 1;
        if(delta > 0 && error > 0) {
            --y;
            delta += 1 - 2 * y;
            continue;
        }
        ++x;
        delta += 2 * (x - y);
        --y;
    }
}

Какого-то впечатляющего примера для проверки этих функций я не нашел, поэтому предлагаю проверить их сразу в деле.

11) Интерфейс для метеостанции

Теперь собственно о том, ради чего всё это делалось. Для начала попробуем сделать интерфейс для самодельной метеостанции. Допустим, что у нас имеется уличный датчик DS18B20, и комнатный DHT11. Информация с уличного датчика будет более приоритетна, поэтому она будет выводиться крупным шрифтом, а вся остальная сопутствующая информация — мелким.

Но для начала, чтобы рисовать интерфейсы, нам понадобиться еще одна функция для рисования иконок размером 7х8. Функция для рисования букв нам не подойдёт, т.к. она рисует растр 5×8, т.е. с межбуквенным интервалом по краям. В целях оптимизации иконки будем выводить построчно, т.е. в пределах одного банка.

void pcd8544_draw_icon_fb(char * img, uint8_t x,uint8_t y, uint8_t num) {
    pos=x+y*84;
    uint8_t i;
    for(i=0;i<(num*7);i++)
    {
        uint8_t c=pgm_read_byte(img+i);
        if ((pos+i)<504) fb[pos+i]|=c;
    }
    pos+=num;
}

Здесь y — это номер строки или банка, x — это номер пикселя в пределах от 0 до 83. num — это ширина изображения в знакоместах, т.е. в пикселях ширина будет равна num*7.

В итоге программа для отрисовки интерфейса у меня получилась такой:

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

#define myabs(n) ((n) < 0 ? -(n) : (n))

const uint8_t blob[7] PROGMEM={112,216,134,129,134,216,112};
const uint8_t degree[7] PROGMEM={0,0,6,9,9,6,0};
const uint8_t degree_big[7] PROGMEM={0,14,27,17,27,14,0};
const uint8_t termometer[7] PROGMEM={0,96,158,129,158,96,0};

int main(void)
{
    
    pcd8544_init();
    
    int16_t temp=-117;
    int8_t t1,t2;
    char i=+1;
    
     for (;;){
        pcd8544_clear_fb();
        
        pcd8544_print_at_fb("10:32", FONT_SIZE_2,0,4);
        pcd8544_print_at_fb("07", FONT_SIZE_1,10,5);
        
        t1=temp/10;t2=temp%10;

        if (myabs(t1)>=10) {
            pcd8544_print_uint8_at_fb(myabs(t1),FONT_SIZE_3,4,1);
            if (t1>=0)
                pcd8544_print_at_fb("+", FONT_SIZE_3,1,1);
            else
                pcd8544_print_at_fb("-", FONT_SIZE_3,1,1);
        } else {
            if (t1>=0)
                pcd8544_print_at_fb("+", FONT_SIZE_3,4,1);
            else
                pcd8544_print_at_fb("-", FONT_SIZE_3,4,1);
            pcd8544_print_uint8_at_fb(myabs(t1),FONT_SIZE_3,7,1);
        }
        pcd8544_print_uint8_at_fb(myabs(t2),FONT_SIZE_2,10,2);
        
        pcd8544_set_point(68,27);
        pcd8544_set_point(60,27);
        pcd8544_set_point(70,27);
        pcd8544_set_point(68,28);
        pcd8544_set_point(69,28);
        pcd8544_set_point(70,28);
        pcd8544_set_point(68,29);
        pcd8544_set_point(69,29);
        pcd8544_set_point(70,29);
        
        char * ptr= (char *)(&blob);
        pcd8544_draw_icon_fb(ptr,0,0,1);
        
        ptr= (char *)(&degree);
        pcd8544_draw_icon_fb(ptr,67,0,1);
        ptr= (char *)(&degree_big);
        pcd8544_draw_icon_fb(ptr,67,1,1);
        
        ptr= (char *)(&termometer);
        pcd8544_draw_icon_fb(ptr,48 ,0,1);
        
        pcd8544_print_at_fb("35%", FONT_SIZE_1,1,0);
        pcd8544_print_at_fb("26", FONT_SIZE_1,8,0);

        pcd8544_display_fb();

        if (temp >= 350)
            i=-1;
        else if (temp <= -350)
            i=1;
        temp+=i;

        _delay_ms(1000);
     }

   return 0;
}

Результат:

Полные исходники к этому примеру можно посмотреть здесь:
https://gitlab.com/flank1er/pcd8544_atmega8/tree/master/11_meteo

12) Интерфейс для FM-радиоприемника

Еще одна распространенная задача — дисплей для FM-приемника. Я не стал изобретать велосипед и попытался скопировать интерфейс со своего старенького плеера iRiver ifp-180tc. Там тоже монохромный дисплей, правда не квадратный, а прямоугольный.

В итоге у меня получилась такая программа:

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

const uint8_t pointer[7] PROGMEM={0x2,0x6,0xc,0x18,0xc,0x6,0x2};
const uint8_t stereo[7] PROGMEM={0x3c,0x66,0xc3,0x81,0xc3,0x66,0x3c};
static const uint8_t battery[14] PROGMEM={28,34,65,93,93,65,93, 93,65,93,93,65,127,0};

int main(void) {
    
    pcd8544_init();
    
    uint16_t freq=1017;
    char i=1;
    uint8_t f1,f2;
    uint8_t j;
    
    for(;;)
    {
         pcd8544_clear_fb();
        
        f1=freq/10;f2=freq%10;
        if (f1>=100)
            pcd8544_print_uint8_at_fb(f1,FONT_SIZE_3,0,1);
        else
            pcd8544_print_uint8_at_fb(f1,FONT_SIZE_3,3,1);

        pcd8544_print_uint8_at_fb(f2,FONT_SIZE_2,9,2);

        
        pcd8544_set_point(61,27);
        pcd8544_set_point(62,27);
        pcd8544_set_point(63,27);
        pcd8544_set_point(61,28);
        pcd8544_set_point(62,28);
        pcd8544_set_point(63,28);
        pcd8544_set_point(61,29);
        pcd8544_set_point(62,29);
        pcd8544_set_point(63,29);
        
        pcd8544_print_at_fb("MГц", FONT_SIZE_1,9,1);
        pcd8544_print_at_fb("ПМ", FONT_SIZE_1,3,0);
        pcd8544_print_at_fb("60dB", FONT_SIZE_1,6,0);
        pcd8544_print_at_fb("7-НАШЕ РАДИО", FONT_SIZE_1,0,4);
        
        pcd8544_draw_line(0,46,83,46);
        for(j=0;j<14;j++)
            pcd8544_draw_line(j*6,44,j*6,47);
        pcd8544_draw_line(83,44,83,47);
        char * ptr= (char *)(&pointer);
        uint8_t p=(freq-880)/2-(freq-880)/10;
        pcd8544_draw_icon_fb(ptr,p,5,1);

        ptr= (char *)(&stereo);
        pcd8544_draw_icon_fb(ptr,0,0,1);
        pcd8544_draw_icon_fb(ptr,7,0,1);

        ptr= (char *)(&battery);
        pcd8544_draw_icon_fb(ptr,70,0,2);

        pcd8544_display_fb();

        if (freq >= 1080)
            i=-1;
        else if (freq <=880)
            i=1;
       freq+=i;

         _delay_ms(1000);
     }

   return 0;
}

Результат:

исходники:
https://gitlab.com/flank1er/pcd8544_atmega8/tree/master/12_radio

Когда происходит нажатие на кнопки регулировки громкости, то шкала FM диапазона на пару секунд меняется на шкалу регулировки громкости.

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

const uint8_t pointer[7] PROGMEM={0x2,0x6,0xc,0x18,0xc,0x6,0x2};
const uint8_t stereo[7] PROGMEM={0x3c,0x66,0xc3,0x81,0xc3,0x66,0x3c};
static const uint8_t battery[14] PROGMEM={28,34,65,93,93,65,93, 93,65,93,93,65,127,0};

int main(void) {
    
    pcd8544_init();
    
    char volume=100;
    uint16_t freq=1017;
    char i=1;
    uint8_t f1,f2;
    
    for(;;)
    {
         pcd8544_clear_fb();
        
        f1=freq/10;f2=freq%10;
        if (f1>=100)
            pcd8544_print_uint8_at_fb(f1,FONT_SIZE_3,0,1);
        else
            pcd8544_print_uint8_at_fb(f1,FONT_SIZE_3,3,1);

        pcd8544_print_uint8_at_fb(f2,FONT_SIZE_2,9,2);

        
        pcd8544_set_point(61,27);
        pcd8544_set_point(62,27);
        pcd8544_set_point(63,27);
        pcd8544_set_point(61,28);
        pcd8544_set_point(62,28);
        pcd8544_set_point(63,28);
        pcd8544_set_point(61,29);
        pcd8544_set_point(62,29);
        pcd8544_set_point(63,29);
        
        pcd8544_print_at_fb("MГц", FONT_SIZE_1,9,1);
        pcd8544_print_at_fb("ПМ", FONT_SIZE_1,3,0);
        pcd8544_print_at_fb("60dB", FONT_SIZE_1,6,0);
        pcd8544_print_at_fb("7-НАШЕ РАДИО", FONT_SIZE_1,0,4);
        
        pcd8544_print_at_fb("гр", FONT_SIZE_1,0,5);
        pcd8544_print_uint8_at_fb(volume, FONT_SIZE_1,3,5);
        pcd8544_draw_line(33,45,83,45);
        
        char * ptr= (char *)(&pointer);
        uint8_t p=33+(volume>>1);
        pcd8544_draw_icon_fb(ptr,p,5,1);

        ptr= (char *)(&stereo);
        pcd8544_draw_icon_fb(ptr,0,0,1);
        pcd8544_draw_icon_fb(ptr,7,0,1);

        ptr= (char *)(&battery);
        pcd8544_draw_icon_fb(ptr,70,0,2);

        pcd8544_display_fb();

        if (volume >= 100)
            i=-1;
        else if (volume <= 0)
            i=1;

        volume+=i;

         _delay_ms(1000);
     }

   return 0;
}

Результат:

Здесь можно видеть, что цифры налезают на статусную строку, хотя внизу есть пустое место. В целом, я бы для больших цифр сделал персональные шрифты, примерно как на HD44780.

исходники:
https://gitlab.com/flank1er/pcd8544_atmega8/tree/master/12_radio_volume

13) Финальная версия библиотеки на аппаратном SPI

Ну и в завершение, можно перевести библиотеку на аппаратный SPI. Напомню, что для корректной работы устройства при заливке прошивки через ISP-программатор, дисплей нужно отключать от микроконтроллера.

В библиотечном файле нужно будет задать переменную, в которой будет храниться номер CS пина:

static uint8_t CSpin;

Соответственно функция инициализации дополниться одним входным параметром:

void pcd8544_init(uint8_t cs)
{
   CSpin=cs;
   
   DDR_PCD8544 |= (1<<PIN_RESET) | (1<<PIN_DC);
   PORT_PCD8544&=~(1<<PIN_RESET);
   PORT_PCD8544|=(1<<PIN_RESET);
   pcd8544_send(LCD_C, 0x21 );  
   pcd8544_send(LCD_C, 0xBA );  
   pcd8544_send(LCD_C, 0x04 );  0x04
   pcd8544_send(LCD_C, 0x14 );  148.0x13
   pcd8544_send(LCD_C, 0x20 );  
   pcd8544_send(LCD_C, 0x0C );  
}

Инициализацию SPI я предпочитаю делать в main() функции, или через библиотеку SPI.

Функция void pcd8544_send(uint8_t dc, uint8_t data) примет в таком случае следующий вид:

void pcd8544_send(uint8_t dc, uint8_t data)
{
    if (dc == LCD_D)
        PORT_PCD8544 |= (1<<PIN_DC);
    else
        PORT_PCD8544 &= ~(1<<PIN_DC);

    PORT_PCD8544&=~(1<<CSpin);

    SPDR=data;
    while(!(SPSR & (1<<SPIF)));

    PORT_PCD8544|=(1<<CSpin);
}

И в принципе это все. Все исходники в примерам можно скачать с этого сайта www.count-zero.ru/files/pcd8544_atmega8.zip или c gitlab.com https://gitlab.com/flank1er/pcd8544_atmega8.

  • samsung sgh-c230

  • lcd экран

  • arduino


blbulyandavbulyan

  • Ответить

  • Создать новую тему

Рекомендуемые сообщения

blbulyandavbulyan

Новичок

    • Поделиться

И так имею экран от телефона Samsung SGH-C230 и хочу его подключить к Arduino UNO и чтобы работал, мне нужна схема подключения и прошивка (прошивка должна быть на родном языке Arduino IDE, так как других я не знаю)? Пожалуйста помогите, фотки экрана будут ниже. :mellow:

WIN_20170925_15_13_26_Pro.jpg

WIN_20170925_15_13_30_Pro.jpg

WIN_20170925_15_16_09_Pro.jpg

WIN_20170925_15_10_40_Pro.jpg

  • Цитата

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

TIMIK74

Ветеран

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

Dmitriy-Схемотехник

Стажер

    • Поделиться

14 минуты назад, TIMIK74 сказал:

работа

афигеть такая сложная просьба,что нужно отправлять это в раздел работы.

  • Цитата

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

Новое семейство HRP/N3 от MEAN WELL – ИП с 350% перегрузкой для промышленных приложений

В промышленных устройствах и установках с электроприводом на двигателях постоянного тока в момент пуска требуется обеспечить повышенный ток. Для решения этой задачи MEAN WELL предлагает вместо ИП с повышенной избыточной мощностью, более оптимальное решение — источник питания с необходимой перегрузочной способностью семейства HRP/N3. 

Новое семейство, представленное в Компэл, экономичнее и расширяет уже существующее HRP/N в увеличении кратности перегрузки. Подробнее>>

TIMIK74

Ветеран

    • Поделиться

а программу писать с нуля вы будете?

34 минуты назад, blbulyandavbulyan сказал:

нужна схема подключения и прошивка (прошивка должна быть на родном языке Arduino IDE,

а это уже работа! Так еще надо сопрягать лсд с ардуино!


Изменено 25 сентября, 2017 пользователем TIMIK74

  • Цитата

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

VCB/VCF – новые DC/DC-преобразователи MORNSUN для телекоммуникационных приложений
Линейка изолированных DC/DC-преобразователей VCB и VCF с диапазоном мощности 3…400 Вт предназначена для использования в телекоммуникационной аппаратуре. Эти новые преобразователи третьего поколения (R3) выпускаются в типоразмерах SIP, 1/4 Brick, 1/8 Brick и 1/16 Brick. Данные DC/DC отвечают требованиям стандарта DOSA, имеют диапазон входного напряжения 2:1 (36…75 В), обладают высокой эффективностью (КПД до 93%) и широким температурным диапазоном -40…85ºС. Изоляция «вход-выход» составляет 1500/2250 В. VCB и VCF выпускаются в двух вариантах по логике управления: N (отрицательной) и P (положительной).
Подробнее>>

kt118

Энтузиаст

    • Поделиться

3 минуты назад, Dmitriy-Схемотехник сказал:

афигеть такая сложная просьба,что нужно отправлять это в раздел работы.

:blink:

А почему Вы сами не напишите, а вообще обратились на форум?

  • Цитата

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

Популярные и выгодные LED-драйверы Snappy для светодиодной подсветки в ДКО «Электронщик»

Snappy – ведущий китайский производитель высококачественных драйверов для светодиодов подсветки. Основное преимущество, помимо отличного соотношения «цена/качество» – сверхплоские форм-факторы, что важно для торговой и интерьерной подсветки, а также для световой рекламы.

При этом при разработке изделий в Snappy учитывали, что в ряде случаев размеры приборов являются основным критерием выбора при принятия решения об использовании того или иного драйвера. В обзоре представлены наиболее популярные семейства светодиодных драйверов компании Snappy. Подробнее>>

blbulyandavbulyan

Новичок

  • Автор
    • Поделиться

Ну так будут предложения?


Изменено 25 сентября, 2017 пользователем blbulyandavbulyan

  • Цитата

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

  • Реклама

Rede RED

Ветеран

    • Поделиться

это Вы, уважаемый, — предлагаете … А другие соглашаются или нет. 

  • Цитата

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

vas320

Опытный

Геннадий

Ветеран

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

blbulyandavbulyan

Новичок

  • Автор
    • Поделиться

В 26.09.2017 в 10:28, vas320 сказал:

Естественно не знаю…

  • Цитата

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

vas320

Опытный

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

andryxa

Специалист

    • Поделиться

Распиновку можно и в схеме телефона глянуть, только зачем это  тролю ? Быстренько все собрались и написали прошивку!

  • Цитата

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

  • 3 недели спустя…

blbulyandavbulyan

Новичок

  • Автор
    • Поделиться

В 01.10.2017 в 13:10, andryxa сказал:

Распиновку можно и в схеме телефона глянуть, только зачем это  тролю ? Быстренько все собрались и написали прошивку!

Спасибо конечно за почётное звание: тролля, но я не собирался троллить, да ещё и так толсто. И где мне найти схему телефона? И как вообще узнать как программу писать имея только распиновку?

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

Service Manual SGH-C230.pdf


Изменено 21 октября, 2017 пользователем blbulyandavbulyan

  • Цитата

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

andryxa

Специалист

    • Поделиться

Что вы собрались делать, если в самой элементарной операции разобраться не можете? Форум для общения а не для выполнения работы по осуществлению чужих хотелок.

  • Цитата

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

TUNGSRAM

Наставник

    • Поделиться

Автор, а какая у вас цель вообще?

  • Цитата

Все законы-имитация реальности

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

blbulyandavbulyan

Новичок

  • Автор
    • Поделиться

2 минуты назад, TUNGSRAM сказал:

Автор, а какая у вас цель вообще?

Заставить его работать. Не будет же он валяться без дела?

16 минут назад, andryxa сказал:

Что вы собрались делать, если в самой элементарной операции разобраться не можете? Форум для общения а не для выполнения работы по осуществлению чужих хотелок.

Ну раз она такая «элементарная» по вашему вот и помогите разобраться. Я — чайник.  И да если бы она была бы для меня «элементарной», то я бы сюда не зашёл. Логично?

И да форум не только для общения, а ещё и для помощи людям.

  • Цитата

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

andryxa

Специалист

    • Поделиться

7 минут назад, blbulyandavbulyan сказал:

Я — чайник. 

Ну так займись чем-то по проще для начала и не ленись искать информацию в интернете.

  • Цитата

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

kt118

Энтузиаст

    • Поделиться

16 минут назад, blbulyandavbulyan сказал:

Заставить его работать. Не будет же он валяться без дела?

А давайте представим что вы его заставили работать, собрали на нем устройство, засунули его в корпус, и спустя пару месяцев, а может дней, а может и лет, экран поломался, или его разбили случайно, вам нужно будет искать точно такой-же экран, либо переделывать все то что вы сделали, это я к чему, очень геморно потом искать такой же дисплей, а переделывать, еще геморней, если чисто ради спортивного интереса разобраться в работе, то возможно, но это вам самим нужно разбираться.

  • Цитата

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

blbulyandavbulyan

Новичок

  • Автор
    • Поделиться

Только что, andryxa сказал:

Ну так займись чем-то по проще для начала и не ленись искать информацию в интернете.

Ну так по проще я уже занимался (ну в смысле по проще этого дисплея). Уже подключал простенький LCD дисплей, теперь хочу подключить этот (тот сломался, он был текстовым) а новый покупать — жаба душит. Ну вот и решил попробовать этот. И маркировка на нём не гуглиться, ну в смысле ВООБЩЕ! На одной из сторон написано HWK7966JT-B, на второй B1A5D06. B1A5D06 — гуглиться но к экрану результаты не имеют ни какого отношения.

1 минуту назад, kt118 сказал:

А давайте представим что вы его заставили работать, собрали на нем устройство, засунули его в корпус, и спустя пару месяцев, а может дней, а может и лет, экран поломался, или его разбили случайно, вам нужно будет искать точно такой-же экран, либо переделывать все то что вы сделали, это я к чему, очень геморно потом искать такой же дисплей, а переделывать, еще геморней, если чисто ради спортивного интереса разобраться в работе, то возможно, но это вам самим нужно разбираться.

Логично. Но тогда, куда ж мне его девать? Сам то я разобраться не могу, да и компания Samsung, если я до неё дозвонюсь и попрошу даташит на этот дисплей, скорее всего отправит меня лесом. 

  • Цитата

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

kt118

Энтузиаст

    • Поделиться

5 минут назад, blbulyandavbulyan сказал:

Но тогда, куда ж мне его девать?

Положите пусть лежит, возможно кто-то когда-то такой же как и вы разберется и подключит его, вариант второй, отдать, возможно кому-то нужен на замену в телефон, или сдать в утиль. У самого есть с десяток разных экранов, даже если и разобраться, то подключать не особо возникает желание, так как потом замену не найдешь, как пример есть осцил Neil Scope 3 почитайте на форуме про поиски дисплея.

  • Цитата

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

andryxa

Специалист

    • Поделиться

Тут больше проблема не в распиновке дисплея. Контроллер который находится внутри дисплея не известен, а без этого не получится написать инициализацию дисплея. Забей на этот дисплей, купи какой нибудь китайский с маленькой диагональю, они копейки стоят. Ну или например найди дисплей от Nokia 100, 101, 108, 112, 113, 130 Single SIM, C1-00, C1-01, C1-02, C1-03, C2-00, X1-01 (это все один и тот-же дисплей) по нему очень много информации в сети

  • Цитата

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

blbulyandavbulyan

Новичок

  • Автор
    • Поделиться

Только что, kt118 сказал:

Положите пусть лежит, возможно кто-то когда-то такой же как и вы разберется и подключит его, вариант второй, отдать, возможно кому-то нужен на замену в телефон, или сдать в утиль. У самого есть с десяток разных экранов, даже если и разобраться, то подключать не особо возникает желание, так как потом замену не найдешь, как пример есть осцил Neil Scope 3 почитайте на форуме про поиски дисплея.

Ладно положу пусть лежит. Может когда буду работать в научной лаборатории со спецоборудованием изучу этот дисплей, разберусь что куда и подключу его, хотя это на вряд ли, скорее всего он будет не нужен…

1 минуту назад, andryxa сказал:

Тут больше проблема не в распиновке дисплея. Контроллер который находится внутри дисплея не известен, а без этого не получится написать инициализацию дисплея. Забей на этот дисплей, купи какой нибудь китайский с маленькой диагональю, они копейки стоят. Ну или например найди дисплей от Nokia 100, 101, 108, 112, 113, 130 Single SIM, C1-00, C1-01, C1-02, C1-03, C2-00, X1-01 (это все один и тот-же дисплей) по нему очень много информации в сети

Ладно спасибо!

  • Цитата

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

kt118

Энтузиаст

    • Поделиться

Полностью согласен с andryxa, намного проще купить тот-же дисплей «Nokia 5110» китайский к ардуино, он на али стоит в районе 1 — 2 долларов, и к нему куча что документации, что кругом их продают.

  • Цитата

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


Гость VicAMMON

Гость VicAMMON

    • Поделиться

Здравствуйте.
Сфотографируйте надпись на шлейфе , твашего дисплея так что бы было видно. И по возможности посчитайте сколько pin-ов на шлейфе.

  • Цитата

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

blbulyandavbulyan

Новичок

  • Автор
    • Поделиться

19 часов назад, Гость VicAMMON сказал:

Здравствуйте.
Сфотографируйте надпись на шлейфе , твашего дисплея так что бы было видно. И по возможности посчитайте сколько pin-ов на шлейфе.

Да я уже и подзабил на него…

  • Цитата

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

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

Вы публикуете как гость.

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

Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

  • Последние посетители

      0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу

  • Сообщения

    • OSS

    • DedLogoped

      Автор

      DedLogoped · Опубликовано 1 час назад

      У меня китайский телек (без всяких смартов-шмартов) со вставленным HDMI от приставки ведёт себя точно так же. Приходится шнур питания выдёргивать на несколько секунд.

    • Dr. West

      Автор

      Dr. West · Опубликовано 1 час назад

      Даже не касаясь темы Яндекс там — не Яндекс. Если аппарат сломался через неделю после покупки — нафига в него лезть вообще и пытаться чего-то ремонтировать? Пусть об этом голова болит у магазина — вы за это уже заплатили.

    • Igor84

      Автор

      Igor84 · Опубликовано 1 час назад

      Да

      Да, даже чуть выше — 1,89 mH.

      К 3-му выводу. Немного размотал изоляцию и увидел, что между 1 и 3 есть обмотка в 3 жилы. Также между 2 и 3 есть обмотка в 1 жилу, и между 4 и 5 обмотка в одну жилу.

      Т.е. вот так:

      Т.е. всё правильно, просто с ошибкой нарисованы обмотки на самой схеме.

      @Гость_Григорий_Т., да, там такой сигнал:

      Т.е. видим ту же «волну», что и на базе Q2. Получается, как вы и говорили, это наводка на щуп?

      Заменил 4,7 кОм и 23 кОм на 1 кОм и 4,7 кОм соответственно. К сожалению, ничего не поменялось.

      Потом еще подумал,посмотрел на оригинальную схему этого блока и увидел, что там ШИМ (не TL494) работал на частоте 60 кГц. А при переделке на TL494 я задал частоту 73 кГц. Решил изменить частоту на «родную» для этого БП — 60 кГц (1 нФ + 18 кОм). Заменил резистор и теперь заметил, что изменения есть — при 25 В и чуть выше пляски на 8, 11 выводах ШИМ уже нет, заполнение около 10%, даже чуть меньше.

      А вот при достижении 28 В наблюдается резкий скачок заполнения до 45%, при этом засвечивается и мигает светодиод режима ограничения по току , на выводе 1 ШИМ 4,88 В, на выводе 2 4,96 В. При 29 В светодиод просто светится, заполнение стабильно 45%.

      Но это же не максимум для трансформатора, иначе заполнение было бы близко к 90%! И почему загорается светодиод ограничения по току?Объясните, пожалуйста, почему так происходит?

    • MishaB

      Автор

      MishaB · Опубликовано 2 часа назад

      Ок , реле не работает как я понимаю значит «на реле не поступает сигнал чтобы оно замкнуло». Само реле я проверял(если только не нужен еще один какойто способ проверки. Я дорисовал схему куда идут контакты управления реле — Main это соответственно штекер куда вставляется кабель от платы монитора управления беговой дорожкой. После нажатия кнопки старт померять может напряжение на контактах управления реле[нижние на рисунке)? Или как то вручную может подать напряжение чтобы замкнуть реле и посмотреть заработает ли мотор? 
      послушал еще раз при включении питания  дорожки и вроде как два щелчка слышу буквально за одну секунду: т.е. это наверное тест реле при включении который нормально отрабатывает.

    • Romanchek82

      Автор

      Romanchek82 · Опубликовано 3 часа назад

      Собственно ответ в вопросе. Не по теме. Я, покупая за копейки явную лажу, потом не бегу побираться на сайты, потому что понимаю, я лох, купил говно, зачем мне такая знаменитость? Да и собственно покупая говно я понимаю, что оно говно, и требовать от него зефирку нет смысла. 

       

      Опять не по теме. Я взял яндекс станцию. Прекрасный аппарат, хочу заметить! Удобно шо писец! Но, это понятно, в связке с устройствами «умными». Не реклама, но игрушка здравая. Хоть и писец какая дорогая. Как дополнение к умному дому, + мультимедиа — цены нет. Звук… Ну это не полноценные полочники и прочее, но достойный. Еще раз повторю — это мультимедиа, и оно меня устраивает более чем. Ах да, о чем это я? Зафлудил. Короче. Если на сайте днс почитать отзывы на ящики — можно увидеть, что яндекс ТВ в глубокой жопе. Народ сдуру хватает, а дома только понимает, что купил полную муйню. Короче, купить яндекс ТВ и плакаться на форуме — это как купить норковую шубу из кошек, и тоже плакаться на форуме. 

    • tolerance1

      Автор

      tolerance1 · Опубликовано 3 часа назад

      Нашёл более-менее свежую схему 2017 года от ACER SWIFT 5 SF514-52T, и ещё от ACER SWIFT 1 SF114-31, проверить как динамики разведены. Так там, насколько понял, перед коннектором динамиков, линии правого и левого аудио каналов защищены по одному (или одним) супрессором AZ5125-02S-R7G-GP. Он из себя представляет четыре диода в одном корпусе.

      По аналогии, у меня тоже должны бы стоять TVS-диоды. Значит получается то не варикапы BBY58, просто совпала маркировка, а размеры и исполнение корпуса — не совпали. Только в моем случае, 4 диода отдельно распаяны.

      То есть вариант про супрессоры был более верным, если не полностью.

  • Похожий контент

    • Pajalkeen

    • Vit@lik

      15

      Автор

      Vit@lik
      Started 13 августа, 2022

    • Fordli

      0

      Автор

      Fordli
      Started 2 июля, 2021

    • zazenergy li

    • Aleksii

      18

      Автор

      Aleksii
      Started 27 февраля, 2022

В этом посте мы узнаем, как взаимодействовать с дисплеем Nokia 5110 с микроконтроллером arduino и как отображать текст, мы также будем создавать простые цифровые часы, и, наконец, мы будем изучать графические возможности дисплея Nokia 5110.

Интересный факт: дисплей Nokia 5110 также использовался в модели 3310 и еще некоторых других телефонах Nokia. Теперь давайте посмотрим, как подключить дисплей к ардуино.

Подключить дисплей с помощью Arduino

Дисплей монохромный и имеет 84×48 пикселей, который может отображать текст и даже графику. Дисплей состоит из 8 контактов: Vcc, GND, сброса, выбора микросхемы (CS), выбора команды, выхода последовательных данных, последовательных часов и подсветки. Дисплей рассчитан на работу с напряжением 3,3 В, а применение 5В повредит дисплей, поэтому при его обработке необходимо соблюдать осторожность. Дисплей имеет функцию подсветки, которая обычно имеет белый или синий цвет. 5В для подсветки с резистором ограничения тока на 330 Ом. Штифты 7, 6, 5, 4 и 3 подключены к цифровым выводам дисплея. Не обязательно знать, как ардуино общается с дисплеем, чтобы использовать его; мы добавим соответствующие файлы библиотеки в программное обеспечение arduino, которое позаботится об обмене данными между arduino и дисплеем.

Теперь давайте отобразим некоторый текст.

Перед загрузкой кода вы должны загрузить файлы библиотеки и добавить в свою среду разработки arduino.

• github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library
• github.com/adafruit/Adafruit-GFX-Library

Программа для Hello world:

//------------Program Developed by R.Girish--------//
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);
void setup()
{
display.begin();
display.setContrast(50);
display.clearDisplay();
}
void loop()
{
display.setTextSize(1);
display.setTextColor(BLACK);
display.print("Hello world !");
display.display();
delay(10);
display.clearDisplay();
}
//------------Program Developed by R.Girish--------//

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

Теперь давайте построим цифровые часы.

Схема такая же, как и предыдущая, только разница заключается в том, что два 10K омных понижающих резистора для времени установки подключаются к выводу № 8 и выводу № 9; остальная часть схемы не требует пояснений.

Программа для цифровых часов:

//----------------Program developed by R.Girish-------//
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);
int h=12;
int m;
int s;
int flag;
int TIME;
const int hs=8;
const int ms=9;
int state1;
int state2;
void setup()
{
display.begin();
display.setContrast(50);
display.clearDisplay();
}

void loop()
{
s=s+1;
display.clearDisplay();
display.setTextSize(2);
display.print(h);
display.print(":");
display.print(m);
display.setTextSize(1);
display.print(":");
display.print(s);
display.setTextSize(2);
display.setCursor(0,16);
if(flag<12) display.println("AM");
if(flag==12) display.println("PM");
if(flag>12) display.println("PM");
if(flag==24) flag=0;
display.setTextSize(1);
display.setCursor(0,32);
display.print("Have a nice  day");
display.display();
delay(1000);
if(s==60)
{
s=0;
m=m+1;
}
if(m==60)
{
m=0;
h=h+1;
flag=flag+1;
}
if(h==13)
{
h=1;
}
//-----------Time setting----------//
state1=digitalRead(hs);
if(state1==1)
{
h=h+1;
flag=flag+1;
if(flag<12) display.print(" AM");
if(flag==12) display.print(" PM");
if(flag>12) display.print(" PM");
if(flag==24) flag=0;
if(h==13) h=1;
}
state2=digitalRead(ms);
if(state2==1)
{
s=0;
m=m+1;
}
}
//-------- Program developed by R.GIRISH-------//

Теперь давайте обсудим графические возможности дисплея. Дисплей Nokia 5110 имеет 84×48 пикселей, что может демонстрировать очень ограниченную графику, которая тоже в монохромном режиме. В смартфонах это может быть не так ярко, но очень полезно, если нам нужно отображать логотипы или символы в вашем проекте.

Иллюстрация графики с использованием дисплея Nokia 5110:

Популярное лицо тролля:

Как мы видим, используя монохромный дисплей, мы можем отображать некоторые изображения

В начало обзора

Купить радиодетали для ремонта

Introduction: Tablet/Phone As Arduino Screen, and a $2 Oscilloscope

While one can buy a cheap 320×240 LCD touch screen for an Arduino-based project, it can be more convenient—especially for prototyping and testing a sketch—to use a tablet or phone as both a touch screen and a power source for a project. You can have a much higher resolution and better looking display on your Android device (e.g., all your lines will be anti-aliased).

The Android-based screen could be connected via USB Serial, Bluetooth or WiFi (e.g., ESP8266).

To that end I wrote VectorDisplay (source here), an Android app that pairs with an Arduino library that implements a large subset of the Adafruit GFX interface. You can write code that can then be easily ported to use a standalone screen, or keep using the sketch with an Android-based display. And you can send commands from the Android app to control the Arduino sketch. The Arduino library is largely board-independent: it should work with any board that provides a USB serial port object named Serial or with an ESP8266 over WiFi or with Bluetooth (pair your board first).

As a proof of concept application, I ported the bare-bones STM32-O-Scope project to use VectorDisplay in place of the ILI9341 display. The result is a (rough around the edges) portable, battery-powered 1.7MS/s oscilloscope that requires nothing more than a $2 STM32F103C board (using the libmaple-based Arduino core), two wires, a USB OTG cable and an Android device. Of course, all you get with this is a range from 0 to about 3.3V.

Step 1: Install Software

I assume you have an Arduino IDE set up for your favorite board and that your favorite board has a USB serial interface.

Go to Sketch | Include library | Manage libraries. Put «VectorDisplay» in the search area and click on «Install» once it’s found.

Download the library zip from here.

Unzip into a folder inside your Arduino/libraries folder.

Download VectorDisplay from Google Play and install it on your Android device. You may need to enable installation from unknown sources on your Android device. The Android app uses the UsbSerial library and the starting point was one of the example apps for the library.

Step 2: Demo Sketch

Connect your board (in upload mode if need be) to your computer and go to File | Examples | VectorDisplay | circles in your Arduino IDE. Click on the upload button (right arrow).

Start the VectorDisplay app on your Android device. Plug your board into the Android device via USB OTG cable. (If your board has a USB micro port, make sure your USB OTG host side goes to the Android device). You should now get a permission query for VectorDisplay. Press OK.

If all goes well, VectorDisplay will now show two buttons on the left side of the screen: Circle and Color. Pressing Circle draws a random circle on the screen and Color changes the color to a random color before the next circle.

If you look at the circles sketch in the IDE, you will see that the serial vector display is declared with:

SerialDisplayClass Display;

and then initialized in setup() with:

Display.begin();

Then command buttons are requested with Display.addButton(). Then loop() calls Display.readMessage() to look for commands being sent via the command buttons.

By default, the coordinate system for the display is 240×320. However, lines and text are all drawn using the full resolution of your Android device screen, with antialiasing for good appearance. That’s why the app is called VectorDisplay.

Step 3: API

The API in the library is in the VectorDisplay.h file. You need to first initialize a Display object. For USB use, do that with:

SerialDisplayClass Display;

Initialize the connection with Display.begin().

There are two sets of methods available in the SerialDisplayClass object: one set uses 32-bit color (including alpha) and commands that are pretty close to the USB serial protocol that my VectorDisplay app uses, and the other set is a subset of the standard Adafruit GFX library methods, using 16-bit color. For the most part you can freely mix the two sets of commands, with the exception that if you use the Adafruit compatible methods, you should use the 16-bit color commands whose names end with 565 instead of the 32-bit ones.

You can set the coordinate system with Display.coordinates(width,height). The default is width=240 and height=320. If you want to emulate a display with non-square pixels, you can use Display.pixelAspectRatio(ratio).

A few of the methods, including pixelAspectRatio(), take a FixedPoint32 argument. This is a 32-bit integer representing a floating point number, where 65536 represents 1.0. To convert a floating point number x to FixedPoint32, do: (FixedPoint32)(65536. * x) (or just TO_FP32(x)).

In addition to being able to send commands from Android buttons, screen touch events are also sent to the MCU.

For WiFi use, see the circles_esp8266 example. You’ll need to press the USB button in the app to switch to WiFi mode.

For Bluetooth, you should be able to do:

SerialDisplayClass Display(MyBluetoothSerial);

...
MyBluetoothSerial.begin(115200);
Display.begin();

and then proceed just as in the USB serial case, where MyBluetoothSerial is whatever Stream object (e.g., Serial2) is connected to your Bluetooth adapter.

Step 4: A $2 Oscilloscope

For the quick and dirty oscilloscope, you will need a blue or black (easier to deal with) pill STM32F103C8 board, which you can get on Aliexpress for under $2. I describe how to prepare the board for use with the Arduino environment for it and install sketches here.

Download this sketch on the board, which is a modified version of Pingumacpenguin’s STM32-O-Scope sketch. Edit the #define BOARD_LED line to match your board. I am using a black pill whose LED is PB12. The blue pills (and some black pills that has the same pinout as the blue pill) have the LED at PC13.

Connect one wire—ground probe—to the board’s ground and another wire to the board’s B0 pin. Plug the board into an Android device with VectorDisplay running, and you have a portable, battery powered oscilloscope.

In the photo I have the oscilloscope hooked up to a phototransistor. The trace on the screen is from a TV infrared remote control.

Be the First to Share

Recommendations

Introduction: Tablet/Phone As Arduino Screen, and a $2 Oscilloscope

While one can buy a cheap 320×240 LCD touch screen for an Arduino-based project, it can be more convenient—especially for prototyping and testing a sketch—to use a tablet or phone as both a touch screen and a power source for a project. You can have a much higher resolution and better looking display on your Android device (e.g., all your lines will be anti-aliased).

The Android-based screen could be connected via USB Serial, Bluetooth or WiFi (e.g., ESP8266).

To that end I wrote VectorDisplay (source here), an Android app that pairs with an Arduino library that implements a large subset of the Adafruit GFX interface. You can write code that can then be easily ported to use a standalone screen, or keep using the sketch with an Android-based display. And you can send commands from the Android app to control the Arduino sketch. The Arduino library is largely board-independent: it should work with any board that provides a USB serial port object named Serial or with an ESP8266 over WiFi or with Bluetooth (pair your board first).

As a proof of concept application, I ported the bare-bones STM32-O-Scope project to use VectorDisplay in place of the ILI9341 display. The result is a (rough around the edges) portable, battery-powered 1.7MS/s oscilloscope that requires nothing more than a $2 STM32F103C board (using the libmaple-based Arduino core), two wires, a USB OTG cable and an Android device. Of course, all you get with this is a range from 0 to about 3.3V.

Step 1: Install Software

I assume you have an Arduino IDE set up for your favorite board and that your favorite board has a USB serial interface.

Go to Sketch | Include library | Manage libraries. Put «VectorDisplay» in the search area and click on «Install» once it’s found.

Download the library zip from here.

Unzip into a folder inside your Arduino/libraries folder.

Download VectorDisplay from Google Play and install it on your Android device. You may need to enable installation from unknown sources on your Android device. The Android app uses the UsbSerial library and the starting point was one of the example apps for the library.

Step 2: Demo Sketch

Connect your board (in upload mode if need be) to your computer and go to File | Examples | VectorDisplay | circles in your Arduino IDE. Click on the upload button (right arrow).

Start the VectorDisplay app on your Android device. Plug your board into the Android device via USB OTG cable. (If your board has a USB micro port, make sure your USB OTG host side goes to the Android device). You should now get a permission query for VectorDisplay. Press OK.

If all goes well, VectorDisplay will now show two buttons on the left side of the screen: Circle and Color. Pressing Circle draws a random circle on the screen and Color changes the color to a random color before the next circle.

If you look at the circles sketch in the IDE, you will see that the serial vector display is declared with:

SerialDisplayClass Display;

and then initialized in setup() with:

Display.begin();

Then command buttons are requested with Display.addButton(). Then loop() calls Display.readMessage() to look for commands being sent via the command buttons.

By default, the coordinate system for the display is 240×320. However, lines and text are all drawn using the full resolution of your Android device screen, with antialiasing for good appearance. That’s why the app is called VectorDisplay.

Step 3: API

The API in the library is in the VectorDisplay.h file. You need to first initialize a Display object. For USB use, do that with:

SerialDisplayClass Display;

Initialize the connection with Display.begin().

There are two sets of methods available in the SerialDisplayClass object: one set uses 32-bit color (including alpha) and commands that are pretty close to the USB serial protocol that my VectorDisplay app uses, and the other set is a subset of the standard Adafruit GFX library methods, using 16-bit color. For the most part you can freely mix the two sets of commands, with the exception that if you use the Adafruit compatible methods, you should use the 16-bit color commands whose names end with 565 instead of the 32-bit ones.

You can set the coordinate system with Display.coordinates(width,height). The default is width=240 and height=320. If you want to emulate a display with non-square pixels, you can use Display.pixelAspectRatio(ratio).

A few of the methods, including pixelAspectRatio(), take a FixedPoint32 argument. This is a 32-bit integer representing a floating point number, where 65536 represents 1.0. To convert a floating point number x to FixedPoint32, do: (FixedPoint32)(65536. * x) (or just TO_FP32(x)).

In addition to being able to send commands from Android buttons, screen touch events are also sent to the MCU.

For WiFi use, see the circles_esp8266 example. You’ll need to press the USB button in the app to switch to WiFi mode.

For Bluetooth, you should be able to do:

SerialDisplayClass Display(MyBluetoothSerial);

...
MyBluetoothSerial.begin(115200);
Display.begin();

and then proceed just as in the USB serial case, where MyBluetoothSerial is whatever Stream object (e.g., Serial2) is connected to your Bluetooth adapter.

Step 4: A $2 Oscilloscope

For the quick and dirty oscilloscope, you will need a blue or black (easier to deal with) pill STM32F103C8 board, which you can get on Aliexpress for under $2. I describe how to prepare the board for use with the Arduino environment for it and install sketches here.

Download this sketch on the board, which is a modified version of Pingumacpenguin’s STM32-O-Scope sketch. Edit the #define BOARD_LED line to match your board. I am using a black pill whose LED is PB12. The blue pills (and some black pills that has the same pinout as the blue pill) have the LED at PC13.

Connect one wire—ground probe—to the board’s ground and another wire to the board’s B0 pin. Plug the board into an Android device with VectorDisplay running, and you have a portable, battery powered oscilloscope.

In the photo I have the oscilloscope hooked up to a phototransistor. The trace on the screen is from a TV infrared remote control.

Be the First to Share

Recommendations

  • Дисплей не включается но телефон работает
  • Дисплей на телефоне это экран
  • Дисплей на телефоне не загорается
  • Дисплей на телефон это
  • Дисплей на телефон самсунг а 50