библиотека PCD8544 для дисплея Nokia 5110
- Войдите на сайт для отправки комментариев
Здравствуйте. Имеется дисплей Nokia 5110 и arduino uno. С сайта http://www.count-zero.ru/tags/pcd8544/ взял реализацию библиотеки для таких дисплеев, подключил как расписано к библиотеке, загрузил несколько примеров с выводом чисел и символов, строк, графики, все работало. Не скажу что Adafruit меня не устраивает, но эта мне проще и понятнее.
Возникло затруднение, когда понадобилось выводить линию функцией void pcd8544_draw_line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);
ПС
#include "avr/io.h" #include "util/delay.h" #include "pcd8544_soft.h" uint8_t i=0; void setup() { pcd8544_init(); pcd8544_clear(); } void loop() { pcd8544_draw_line(0,24,0,24); }
Скетч компилируется, но на экране ничего не отображается
Графическая емкость дисплея равна 48 х 84, значит по идее должно что нибудь бы отобразиться, но не понимаю ошибку
Заголовочный файл 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); extern void pcd8544_clear_fb(void); extern void pcd8544_display_fb(); extern void pcd8544_send_char_fb(uint8_t ch); extern void pcd8544_set_point(uint8_t x, uint8_t y); extern void pcd8544_draw_line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2); #endif
Файл с кодом pcd8544_soft.cpp
#include "ascii.h" #include "pcd8544_soft.h" #include <stdio.h> #include <stdlib.h> #define FB_LEN 504 static uint8_t fb[FB_LEN]; uint16_t pos; void pcd8544_init(void) { // GPIO Setup 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 ); // LCD Extended Commands. pcd8544_send(LCD_C, 0xBA ); // Set LCD Vop (Contrast). pcd8544_send(LCD_C, 0x04 ); // Set Temp coefficent. //0x04 pcd8544_send(LCD_C, 0x14 ); // LCD bias mode 1:48. //0x13 pcd8544_send(LCD_C, 0x20 ); // LCD Basic Commands pcd8544_send(LCD_C, 0x0C ); // LCD in normal mode. } 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]; // source uint8_t r[20]; // result uint8_t i,j; // get littera 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); } } // scale 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; } // print 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]; // source uint8_t r[45]; // result uint8_t i; // get littera 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); } } // scale 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; } // print 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; // space 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++; } } } 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) { 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; } } 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)); } } void pcd8544_draw_line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) { const int deltaX = abs(x2 - x1); const int deltaY = abs(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; } } }
Не уточнил, это функция рисования прямой линии. Построена на основе функции рисования точки pcd8544_set_point по несложному алгоритму.
На сайте об этой функции так и сказано
"Какого-то впечатляющего примера для проверки этих функций я не нашел, поэтому предлагаю проверить их сразу в деле."
Не уточнил, это функция рисования прямой линии. Построена на основе функции рисования точки pcd8544_set_point по несложному алгоритму.
На сайте об этой функции так и сказано
"Какого-то впечатляющего примера для проверки этих функций я не нашел, поэтому предлагаю проверить их сразу в деле."
Пару-тройку вопросов:
1. А какие-либо другие функции отображения Вы пробовали?
2. Есть ли к библиотеке примеры, и пробовали ли Вы их?
3. Среди заголовков есть что-то, оканчивающееся на _fb, а в тексте библиотеки массив fb равный по размеру экрану, который по смыслу может быть фреймбуфером. Вы не пытались понять, как это либо использовать, либо отключить?
andriano, спасибо, отвечу вначале на первый вопрос. Да пробывал к примеру отображение символа и целого числа
Добавление фреймбуфера. Программа рисования фрактала.
2 Примеры показаны на сайте http://www.count-zero.ru/2017/pcd8544/. Там же сказано и про фреймбуфер дисплей, который равен 504 байта.
Если я правильно вас понимаю, то фреймбуфер это область видеопамяти дисплея, куда складываются значения в виде набора байт. То есть обращаясь к определенному байту мы покажем выделенную ячейку на дисплее.
Алгоритм понял
1 Очистить фреймбуфер
2 Записать туда значения
3 Вывод содержимого на дисплей
4 Возврат к п. 1
Тогда разберусь
--------------------------
Спасибо все работает. Отображаются точки на дисплее, теперь и с линией разберусь
Если я правильно вас понимаю, то фреймбуфер это область видеопамяти дисплея, куда складываются значения в виде набора байт. То есть обращаясь к определенному байту мы покажем выделенную ячейку на дисплее.
Я не совсем понял, какое отношение лично я имею к фреймбуферу вообще, и к тому, как Вы понрмаете его работу, но понимаете ее Вы, похоже не совсем правильно.
Одна точка на экране соответствует одному биту. Минимально адресуемая единица информации - один байт. На экране он соответствует восьми стоящим рядом точкам. Просто так невозможно изменить один бит в байте, т.к. у него нет адреса. Приходится читать байт целиком, править в нем нужный бит и записывать байт целиком обратно. Если просто записать байт с установленным нужным битом, то попрртятся остальные 7 битов, т.е. на экране в 7 смежных пикселях будет мусор.
Но проблема в том, что записать на экран байт можно всегда, а вот прочесть из него - нет. Поэтому приходится хранить в оперативной памяфти копию экрана (тот самый фреймбуфер), время от времени переправляя ее на экран либо целиком, либо по частям.
Благодарю, понятно разъяснили)