-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathPCF8814_light.cpp
243 lines (217 loc) · 9.57 KB
/
PCF8814_light.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
//***************************************************************************
// File........: PCF8814.h
// Author(s)...: Chiper
// Porting.....: Igorok107
// URL(s)......: http://digitalchip.ru
// Description.: Драйвер LCD-контроллера от Nokia1100 без графических функций
// Data........: 07.11.13
// Version.....: 2.2.0
//***************************************************************************
#include "PCF8814_light.h"
#include "PCF8814_font.h" // Подключаем шрифт (будет размещен в программной памяти)
// Порты к которым подключен дисплей в нумерации Arduino
volatile uint8_t LCD_SCLK, LCD_SDA, LCD_CS, LCD_RST;
#ifndef SOFT_SPI
const uint8_t SPI_DELAY[] = {1,2,5,10,1,1,2}; //Задержка для первого бита
#endif
PCF8814::PCF8814(uint8_t _LCD_SCLK, uint8_t _LCD_SDA, uint8_t _LCD_CS, uint8_t _LCD_RST)
{
// Инициализируем пины на вывод для работы с LCD-контроллером
pinMode(_LCD_RST,OUTPUT);
LCD_RST = _LCD_RST;
#ifdef SOFT_SPI
pinMode(_LCD_SCLK,OUTPUT);
pinMode(_LCD_SDA,OUTPUT);
pinMode(_LCD_CS,OUTPUT);
LCD_SCLK = _LCD_SCLK;
LCD_SDA = _LCD_SDA;
LCD_CS = _LCD_CS;
#else // Инициализация аппаратного SPI
pinMode(SCK, OUTPUT);
pinMode(MOSI, OUTPUT);
pinMode(SS, OUTPUT);
SPCR = 0x10; //Определяем как MASTER.
SPCR = (SPCR & ~0x03) | (SPI_CLOCK_DIV & 0x03); //Делитель частоты
SPSR = (SPSR & ~1) | ((SPI_CLOCK_DIV >> 2) & 1);
#endif
CS_LCD_SET;
}
uint8_t PCF8814::SPI_write(uint8_t cData) {
SPDR = cData;
while(!(SPSR & _BV(SPIF)));
return SPDR;
}
//******************************************************************************
// Передача байта (команды или данных) на LCD-контроллер
// mode: CMD_LCD_MODE - передаем команду
// DATA_LCD_MODE - передаем данные
// c: значение передаваемого байта
void PCF8814::SendByte(char mode,unsigned char c)
{
#ifndef SOFT_SPI
SPCR &= ~_BV(SPIE);
#endif
CS_LCD_RESET;
(mode) ? SDA_LCD_SET : SDA_LCD_RESET;
SCLK_LCD_SET;
#ifndef SOFT_SPI
delayMicroseconds(SPI_DELAY[SPI_CLOCK_DIV]);
#else
delayMicroseconds(LCD_MIN_DELAY/2);
#endif
SCLK_LCD_RESET;
#ifdef SOFT_SPI
uint8_t i;
for(i=0;i<8;i++)
{
delayMicroseconds(LCD_MIN_DELAY/2);
SCLK_LCD_RESET;
if(c & 0x80) SDA_LCD_SET;
else SDA_LCD_RESET;
delayMicroseconds(LCD_MIN_DELAY/2);
SCLK_LCD_SET;
c <<= 1;
}
SCLK_LCD_RESET;
#else
SPCR |= _BV(SPE);
SPI_write(c);
SPCR &= ~_BV(SPE);
#endif
CS_LCD_SET;
SDA_LCD_RESET;
}
//******************************************************************************
// Инициализация контроллера
void PCF8814::Init(void)
{
SCLK_LCD_RESET;
SDA_LCD_RESET;
CS_LCD_RESET;
RST_LCD_RESET;
delay(10); // выжидем не менее 5мс для установки генератора(менее 5 мс может неработать)
RST_LCD_SET;
CS_LCD_SET;
SendByte(CMD_LCD_MODE,0xE2); // *** SOFTWARE RESET
SendByte(CMD_LCD_MODE,0x3A); // *** Use internal oscillator
SendByte(CMD_LCD_MODE,0xEF); // *** FRAME FREQUENCY:
SendByte(CMD_LCD_MODE,0x04); // *** 80Hz
SendByte(CMD_LCD_MODE,0xD0); // *** 1:65 divider
SendByte(CMD_LCD_MODE,0xEB); // Включить температурную компенсацию
SendByte(CMD_LCD_MODE,0x20); // Запись в регистр Vop
SendByte(CMD_LCD_MODE,0x85); // Определяет контрастность
SendByte(CMD_LCD_MODE,0xA4); // all on/normal display
SendByte(CMD_LCD_MODE,0x2F); // Power control set(charge pump on/off)
SendByte(CMD_LCD_MODE,0x40); // set start row address = 0
SendByte(CMD_LCD_MODE,0xB0); // установить Y-адрес = 0
SendByte(CMD_LCD_MODE,0x10); // установить X-адрес, старшие 3 бита
SendByte(CMD_LCD_MODE,0x00); // установить X-адрес, младшие 4 бита
//SendByte(CMD_LCD_MODE,0xC8); // mirror Y axis (about X axis)
SendByte(CMD_LCD_MODE,0xA1); // Инвертировать экран по горизонтали
SendByte(CMD_LCD_MODE,0xAC); // set initial row (R0) of the display
SendByte(CMD_LCD_MODE,0x07);
SendByte(CMD_LCD_MODE,0xAF); // экран вкл/выкл
Clear(); // clear LCD
}
//******************************************************************************
// Очистка экрана
void PCF8814::Clear(void)
{
SendByte(CMD_LCD_MODE,0x40); // Y = 0
SendByte(CMD_LCD_MODE,0xB0);
SendByte(CMD_LCD_MODE,0x10); // X = 0
SendByte(CMD_LCD_MODE,0x00);
SendByte(CMD_LCD_MODE,0xAE); // disable display;
unsigned int i;
for(i=0;i<864;i++) SendByte(DATA_LCD_MODE,0x00);
SendByte(CMD_LCD_MODE,0xAF); // enable display;
}
//******************************************************************************
// Зеркалирование LCD-экрана по оси x и y соответственно.
// ON: Отразить
// OFF: Не отражатьж
void PCF8814::Mirror(uint8_t x, uint8_t y)
{
SendByte(CMD_LCD_MODE,0xA0 | x);
SendByte(CMD_LCD_MODE,0xC0 | y<<3);
}
//******************************************************************************
// Контрасиность LCD-экрана.
// с: принимает значения от 0 до 31.
void PCF8814::Contrast(uint8_t c)
{
if (c >= 0x20) c = 0x1F;
SendByte(CMD_LCD_MODE,0x20);
SendByte(CMD_LCD_MODE,0x80+c); // Определяет контрастность [0x80-0x9F]
}
//******************************************************************************
// Вывод символа на LCD-экран в текущее место
// c: код символа
void PCF8814::Putc(unsigned char c)
{
if (c < 208){
uint8_t i;
for ( i = 0; i < 5; i++ )
SendByte(DATA_LCD_MODE,pgm_read_byte(&(lcd_Font[c-32][i])));
SendByte(DATA_LCD_MODE,0x00); // Зазор между символами по горизонтали в 1 пиксель
}
}
//******************************************************************************
// Вывод широкого символа на LCD-экран в текущее место
// c: код символа
void PCF8814::PutcWide(unsigned char c)
{
if (c < 208){ // Урезаем первый байт в кодировке UTF8
uint8_t i;
for ( i = 0; i < 5; i++ )
{
unsigned char glyph = pgm_read_byte(&(lcd_Font[c-32][i]));
SendByte(DATA_LCD_MODE,glyph);
SendByte(DATA_LCD_MODE,glyph);
}
SendByte(DATA_LCD_MODE,0x00); // Зазор между символами по горизонтали в 1 пиксель
// SendByte(DATA_LCD_MODE,0x00); // Можно сделать две линии
}
}
//******************************************************************************
// Вывод строки символов на LCD-экран в текущее место. Если строка выходит
// за экран в текущей строке, то остаток переносится на следующую строку.
// message: указатель на строку символов. 0x00 - признак конца строки.
void PCF8814::Print(const char * message)
{
while (*message) Putc(*message++); // Конец строки обозначен нулем
}
//******************************************************************************
// Вывод строки символов двойной ширины на LCD-экран в текущее место
// из оперативной памяти. Если строка выходит за экран в текущей строке, то остаток
// переносится на следующую строку.
// message: указатель на строку символов в оперативной памяти. 0x00 - признак конца строки.
void PCF8814::PrintWide(char * message)
{
while (*message) PutcWide(*message++); // Конец строки обозначен нулем
}
//******************************************************************************
// Вывод строки символов на LCD-экран NOKIA 1100 в текущее место из программной памяти.
// Если строка выходит за экран в текущей строке, то остаток переносится на следующую строку.
// message: указатель на строку символов в программной памяти. 0x00 - признак конца строки.
void PCF8814::PrintF(char * message)
{
uint8_t data;
while (data=pgm_read_byte(message), data)
{
Putc(data);
message++;
}
}
//******************************************************************************
// Устанавливает курсор в необходимое положение. Отсчет начинается в верхнем
// левом углу. По горизонтали 16 знакомест, по вертикали - 8
// x: 0..15
// y: 0..7
void PCF8814::GotoXY(uint8_t x,uint8_t y)
{
x=x*6; // Переходим от координаты в знакоместах к координатам в пикселях
SendByte(CMD_LCD_MODE,(0xB0|(y&0x0F))); // установка адреса по Y: 0100 yyyy
SendByte(CMD_LCD_MODE,(0x00|(x&0x0F))); // установка адреса по X: 0000 xxxx - биты (x3 x2 x1 x0)
SendByte(CMD_LCD_MODE,(0x10|((x>>4)&0x07))); // установка адреса по X: 0010 0xxx - биты (x6 x5 x4)
}