1204 lines
45 KiB
Markdown
1204 lines
45 KiB
Markdown
---
|
||
title: "Подключение дисплея от Siemens C55/A55/A52 к AVR"
|
||
categories: ["mcu", "archive"]
|
||
date: 2016-02-19T00:00:00+03:00
|
||
draft: false
|
||
featured_image: miniature.jpg
|
||
---
|
||
|
||
|
||
Вот на днях решил порыться в своих запасах запчастей от мобильных телефонах. И заметил дисплей с маркировкой LPH8694-3. Погуглив, я выяснил что это дисплей от телефонов Siemens C55/A55/A52. Ну что ж добру пропадать, будем подключать.
|
||
|
||
<!--more-->
|
||
|
||
> :hint: Статья не закончена.
|
||
> Когда-нибудь она будет доработана.
|
||
|
||
![Маркировка экрана|400](lcd.jpg)
|
||
|
||
Экран имеет весьма странное разрешение экрана – 101 на 64 точки (в [даташите](PCF8812.pdf) вообще написано, что 102x64). Это намного больше, чем у дисплея, которым я обычно пользуюсь (у nokia 5110 – 64 на 48 точек).
|
||
|
||
За основу я решил использовать [библиотеку](https://github.com/gresolio/N3310Lib) уважаемого товарища [gresolio](https://github.com/gresolio). Дисплеи очень похожи, но немного отличается инициализация. Да и доработать библиотеку под новое разрешение экрана тоже нужно.
|
||
|
||
![Распиновка дисплея (вид со стороны контактов)|338](lph8684.png)
|
||
|
||
Главное отличие в инициализации, без чего дисплей не запустится вообще – способ питания.
|
||
|
||
Нужно найти вот эту строку в **LcdInit**:
|
||
|
||
``` c
|
||
LcdSend( 0x13, LCD_CMD ); // Настройка питания (LCD bias mode 1:48)
|
||
```
|
||
|
||
И заменить на:
|
||
|
||
```c
|
||
LcdSend( 0x16, LCD_CMD );
|
||
```
|
||
|
||
**LcdGotoXYFont**, до:
|
||
|
||
```c
|
||
byte LcdGotoXYFont ( byte x, byte y )
|
||
{
|
||
// Проверка границ
|
||
if( x > 13 || y > 5 ) return OUT_OF_BORDER;
|
||
|
||
// Вычисление указателя. Определен как адрес в пределах 504 байт
|
||
LcdCacheIdx = x * 6 + y * 84;
|
||
return OK;
|
||
}
|
||
```
|
||
|
||
После:
|
||
|
||
```c
|
||
byte LcdGotoXYFont ( byte x, byte y )
|
||
{
|
||
// Проверка границ
|
||
if( x > LCD_COLS || y > LCD_LINES ) return OUT_OF_BORDER;
|
||
|
||
// Вычисление указателя. Определен как адрес в пределах 504 байт
|
||
LcdCacheIdx = x * LCD_LINES + y * LCD_X_RES;
|
||
return OK;
|
||
}
|
||
```
|
||
|
||
**LcdChr**, до:
|
||
|
||
```c
|
||
else if ( size == FONT_2X )
|
||
{
|
||
tmpIdx = LcdCacheIdx - 84;
|
||
```
|
||
|
||
После:
|
||
|
||
```c
|
||
else if ( size == FONT_2X )
|
||
{
|
||
tmpIdx = LcdCacheIdx - LCD_X_RES;
|
||
```
|
||
|
||
До:
|
||
|
||
```c
|
||
// Копируем две части в кэш
|
||
LcdCache[tmpIdx++] = b1;
|
||
LcdCache[tmpIdx++] = b1;
|
||
LcdCache[tmpIdx + 82] = b2;
|
||
LcdCache[tmpIdx + 83] = b2;
|
||
```
|
||
|
||
После:
|
||
|
||
```c
|
||
LcdCache[tmpIdx++] = b1;
|
||
LcdCache[tmpIdx++] = b1;
|
||
LcdCache[tmpIdx + LCD_X_RES - 2] = b2;
|
||
LcdCache[tmpIdx + LCD_X_RES - 1] = b2;
|
||
```
|
||
|
||
**LcdPixel**, до:
|
||
|
||
```c
|
||
// Пересчет индекса и смещения
|
||
index = ( ( y / 8 ) * 84 ) + x;
|
||
offset = y - ( ( y / 8 ) * 8 );
|
||
```
|
||
|
||
После
|
||
|
||
```c
|
||
// Пересчет индекса и смещения
|
||
index = ( ( y / LCD_LINES ) * LCD_X_RES ) + x;
|
||
offset = y - ( ( y / 8) * LCD_LINES );
|
||
```
|
||
|
||
|
||
**n3310.h**, до:
|
||
|
||
```c
|
||
// Разрешение дисплея в пикселях
|
||
#define LCD_X_RES 84 // разрешение по горизонтали
|
||
#define LCD_Y_RES 48 // разрешение по вертикали
|
||
```
|
||
|
||
После:
|
||
|
||
```c
|
||
// Разрешение дисплея в пикселях
|
||
#define LCD_X_RES 102 // разрешение по горизонтали
|
||
#define LCD_Y_RES 65 // разрешение по вертикали
|
||
#define LCD_LINES (LCD_Y_RES / 8) // количество строк
|
||
#define LCD_COLS (LCD_X_RES / 5) // количество столбцов
|
||
```
|
||
|
||
Возможно, это не всё.
|
||
|
||
Вот то, что получилось:
|
||
|
||
sc55.h:
|
||
```c
|
||
/*
|
||
* Имя : n3310.h
|
||
*
|
||
* Описание : Это заголовочный файл для драйвера графического LCD от Nokia 3310, а также его китайских клонов.
|
||
* Базируется на коде библиотек написанных Sylvain Bissonnette и Fandi Gunawan:
|
||
* http://www.microsyl.com/index.php/2010/03/24/nokia-lcd-library/
|
||
* http://fandigunawan.wordpress.com/2008/06/18/lcd-nokia-3310-pcd8544-driver-in-winavravr-gcc/
|
||
* Основные отличия между оригиналом и клоном хорошо описаны в статье от Aheir:
|
||
* http://radiokot.ru/articles/29/
|
||
*
|
||
* Автор : Xander Gresolio <xugres@gmail.com>
|
||
* Веб-страница : http://we.easyelectronics.ru/profile/XANDER/
|
||
*
|
||
* Лицензия : GPL v3.0
|
||
*
|
||
* Компилятор : WinAVR, GCC for AVR platform
|
||
*/
|
||
|
||
#ifndef _SC55_H_
|
||
#define _SC55_H_
|
||
|
||
#include <avr/pgmspace.h>
|
||
|
||
// Порт к которому подключен LCD (здесь пример распиновки для ATmega8)
|
||
#define LCD_PORT PORTB
|
||
#define LCD_DDR DDRB
|
||
|
||
// Распиновка порта
|
||
#define LCD_DC_PIN PB1
|
||
#define LCD_CE_PIN PB2
|
||
#define LCD_DATA_PIN PB3
|
||
#define LCD_RST_PIN PB4
|
||
#define LCD_CLK_PIN PB5
|
||
|
||
// Разрешение дисплея в пикселях
|
||
#define LCD_X_RES 102 // разрешение по горизонтали
|
||
#define LCD_Y_RES 65 // разрешение по вертикали
|
||
#define LCD_LINES (LCD_Y_RES / 8) // количество строк
|
||
#define LCD_COLS (LCD_X_RES / 5) // количество столбцов
|
||
|
||
// Настройки для рисования группы прямоугольников функцией LcdBars ( byte data[], byte numbBars, byte width, byte multiplier )
|
||
#define EMPTY_SPACE_BARS 2 // расстояние между прямоугольниками
|
||
#define BAR_X 30 // координата x
|
||
#define BAR_Y 47 // координата y
|
||
|
||
// Размер кэша ( 84 * 48 ) / 8 = 504 байта
|
||
#define LCD_CACHE_SIZE ( ( LCD_X_RES * LCD_Y_RES ) / 8 )
|
||
|
||
#define FALSE 0
|
||
#define TRUE 1
|
||
|
||
// Для возвращаемых значений
|
||
#define OK 0 // Безошибочная отрисовка
|
||
#define OUT_OF_BORDER 1 // Выход за границы дисплея
|
||
#define OK_WITH_WRAP 2 // Переход на начало (ситуация автоинкремента указателя курсора при выводе длинного текста)
|
||
|
||
typedef unsigned char byte;
|
||
|
||
// Перечисления
|
||
typedef enum
|
||
{
|
||
LCD_CMD = 0, // Команда
|
||
LCD_DATA = 1 // Данные
|
||
|
||
} LcdCmdData;
|
||
|
||
typedef enum
|
||
{
|
||
PIXEL_OFF = 0, // Погасить пиксели дисплея
|
||
PIXEL_ON = 1, // Включить пиксели дисплея
|
||
PIXEL_XOR = 2 // Инвертировать пиксели
|
||
|
||
} LcdPixelMode;
|
||
|
||
typedef enum
|
||
{
|
||
FONT_1X = 1, // Обычный размер шрифта 5x7
|
||
FONT_2X = 2 // Увеличенный размер шрифта
|
||
|
||
} LcdFontSize;
|
||
|
||
// Прототипы функций, детальную информацию смотрим внутри n3310lcd.c
|
||
void LcdInit ( void ); // Инициализация
|
||
void LcdClear ( void ); // Очистка буфера
|
||
void LcdUpdate ( void ); // Копирование буфера в ОЗУ дисплея
|
||
void LcdImage ( const byte *imageData ); // Рисование картинки из массива в Flash ROM
|
||
void LcdContrast ( byte contrast ); // Установка контрастности дисплея
|
||
byte LcdGotoXYFont ( byte x, byte y ); // Установка курсора в позицию x,y
|
||
byte LcdChr ( LcdFontSize size, byte ch ); // Вывод символа в текущей позиции
|
||
byte LcdStr ( LcdFontSize size, byte dataArray[] ); // Вывод строки сохраненной в RAM
|
||
byte LcdFStr ( LcdFontSize size, const byte *dataPtr ); // Вывод строки сохраненной в Flash ROM
|
||
byte LcdPixel ( byte x, byte y, LcdPixelMode mode ); // Точка
|
||
byte LcdLine ( byte x1, byte y1, byte x2, byte y2, LcdPixelMode mode ); // Линия
|
||
byte LcdCircle ( byte x, byte y, byte radius, LcdPixelMode mode); // Окружность
|
||
byte LcdRect ( byte x1, byte y1, byte x2, byte y2, LcdPixelMode mode ); // Прямоугольник
|
||
byte LcdSingleBar ( byte baseX, byte baseY, byte height, byte width, LcdPixelMode mode ); // Один
|
||
byte LcdBars ( byte data[], byte numbBars, byte width, byte multiplier ); // Несколько
|
||
|
||
|
||
|
||
/*
|
||
* Таблица для отображения символов (ASCII[0x20-0x7F] + CP1251[0xC0-0xFF] = всего 160 символов)
|
||
*/
|
||
static const byte FontLookup [][5] PROGMEM=
|
||
{
|
||
{ 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x20 32
|
||
{ 0x00, 0x00, 0x5F, 0x00, 0x00 }, // ! 0x21 33
|
||
{ 0x00, 0x07, 0x00, 0x07, 0x00 }, // " 0x22 34
|
||
{ 0x14, 0x7F, 0x14, 0x7F, 0x14 }, // # 0x23 35
|
||
{ 0x24, 0x2A, 0x7F, 0x2A, 0x12 }, // $ 0x24 36
|
||
{ 0x4C, 0x2C, 0x10, 0x68, 0x64 }, // % 0x25 37
|
||
{ 0x36, 0x49, 0x55, 0x22, 0x50 }, // & 0x26 38
|
||
{ 0x00, 0x05, 0x03, 0x00, 0x00 }, // ' 0x27 39
|
||
{ 0x00, 0x1C, 0x22, 0x41, 0x00 }, // ( 0x28 40
|
||
{ 0x00, 0x41, 0x22, 0x1C, 0x00 }, // ) 0x29 41
|
||
{ 0x14, 0x08, 0x3E, 0x08, 0x14 }, // * 0x2A 42
|
||
{ 0x08, 0x08, 0x3E, 0x08, 0x08 }, // + 0x2B 43
|
||
{ 0x00, 0x00, 0x50, 0x30, 0x00 }, // , 0x2C 44
|
||
{ 0x10, 0x10, 0x10, 0x10, 0x10 }, // - 0x2D 45
|
||
{ 0x00, 0x60, 0x60, 0x00, 0x00 }, // . 0x2E 46
|
||
{ 0x20, 0x10, 0x08, 0x04, 0x02 }, // / 0x2F 47
|
||
{ 0x3E, 0x51, 0x49, 0x45, 0x3E }, // 0 0x30 48
|
||
{ 0x00, 0x42, 0x7F, 0x40, 0x00 }, // 1 0x31 49
|
||
{ 0x42, 0x61, 0x51, 0x49, 0x46 }, // 2 0x32 50
|
||
{ 0x21, 0x41, 0x45, 0x4B, 0x31 }, // 3 0x33 51
|
||
{ 0x18, 0x14, 0x12, 0x7F, 0x10 }, // 4 0x34 52
|
||
{ 0x27, 0x45, 0x45, 0x45, 0x39 }, // 5 0x35 53
|
||
{ 0x3C, 0x4A, 0x49, 0x49, 0x30 }, // 6 0x36 54
|
||
{ 0x01, 0x71, 0x09, 0x05, 0x03 }, // 7 0x37 55
|
||
{ 0x36, 0x49, 0x49, 0x49, 0x36 }, // 8 0x38 56
|
||
{ 0x06, 0x49, 0x49, 0x29, 0x1E }, // 9 0x39 57
|
||
{ 0x00, 0x36, 0x36, 0x00, 0x00 }, // : 0x3A 58
|
||
{ 0x00, 0x56, 0x36, 0x00, 0x00 }, // ; 0x3B 59
|
||
{ 0x08, 0x14, 0x22, 0x41, 0x00 }, // < 0x3C 60
|
||
{ 0x14, 0x14, 0x14, 0x14, 0x14 }, // = 0x3D 61
|
||
{ 0x00, 0x41, 0x22, 0x14, 0x08 }, // > 0x3E 62
|
||
{ 0x02, 0x01, 0x51, 0x09, 0x06 }, // ? 0x3F 63
|
||
{ 0x32, 0x49, 0x79, 0x41, 0x3E }, // @ 0x40 64
|
||
{ 0x7E, 0x11, 0x11, 0x11, 0x7E }, // A 0x41 65
|
||
{ 0x7F, 0x49, 0x49, 0x49, 0x36 }, // B 0x42 66
|
||
{ 0x3E, 0x41, 0x41, 0x41, 0x22 }, // C 0x43 67
|
||
{ 0x7F, 0x41, 0x41, 0x22, 0x1C }, // D 0x44 68
|
||
{ 0x7F, 0x49, 0x49, 0x49, 0x41 }, // E 0x45 69
|
||
{ 0x7F, 0x09, 0x09, 0x09, 0x01 }, // F 0x46 70
|
||
{ 0x3E, 0x41, 0x49, 0x49, 0x7A }, // G 0x47 71
|
||
{ 0x7F, 0x08, 0x08, 0x08, 0x7F }, // H 0x48 72
|
||
{ 0x00, 0x41, 0x7F, 0x41, 0x00 }, // I 0x49 73
|
||
{ 0x20, 0x40, 0x41, 0x3F, 0x01 }, // J 0x4A 74
|
||
{ 0x7F, 0x08, 0x14, 0x22, 0x41 }, // K 0x4B 75
|
||
{ 0x7F, 0x40, 0x40, 0x40, 0x40 }, // L 0x4C 76
|
||
{ 0x7F, 0x02, 0x0C, 0x02, 0x7F }, // M 0x4D 77
|
||
{ 0x7F, 0x04, 0x08, 0x10, 0x7F }, // N 0x4E 78
|
||
{ 0x3E, 0x41, 0x41, 0x41, 0x3E }, // O 0x4F 79
|
||
{ 0x7F, 0x09, 0x09, 0x09, 0x06 }, // P 0x50 80
|
||
{ 0x3E, 0x41, 0x51, 0x21, 0x5E }, // Q 0x51 81
|
||
{ 0x7F, 0x09, 0x19, 0x29, 0x46 }, // R 0x52 82
|
||
{ 0x46, 0x49, 0x49, 0x49, 0x31 }, // S 0x53 83
|
||
{ 0x01, 0x01, 0x7F, 0x01, 0x01 }, // T 0x54 84
|
||
{ 0x3F, 0x40, 0x40, 0x40, 0x3F }, // U 0x55 85
|
||
{ 0x1F, 0x20, 0x40, 0x20, 0x1F }, // V 0x56 86
|
||
{ 0x3F, 0x40, 0x38, 0x40, 0x3F }, // W 0x57 87
|
||
{ 0x63, 0x14, 0x08, 0x14, 0x63 }, // X 0x58 88
|
||
{ 0x07, 0x08, 0x70, 0x08, 0x07 }, // Y 0x59 89
|
||
{ 0x61, 0x51, 0x49, 0x45, 0x43 }, // Z 0x5A 90
|
||
{ 0x00, 0x7F, 0x41, 0x41, 0x00 }, // [ 0x5B 91
|
||
{ 0x02, 0x04, 0x08, 0x10, 0x20 }, // \ 0x5C 92
|
||
{ 0x00, 0x41, 0x41, 0x7F, 0x00 }, // ] 0x5D 93
|
||
{ 0x04, 0x02, 0x01, 0x02, 0x04 }, // ^ 0x5E 94
|
||
{ 0x40, 0x40, 0x40, 0x40, 0x40 }, // _ 0x5F 95
|
||
{ 0x00, 0x01, 0x02, 0x04, 0x00 }, // ` 0x60 96
|
||
{ 0x20, 0x54, 0x54, 0x54, 0x78 }, // a 0x61 97
|
||
{ 0x7F, 0x48, 0x44, 0x44, 0x38 }, // b 0x62 98
|
||
{ 0x38, 0x44, 0x44, 0x44, 0x20 }, // c 0x63 99
|
||
{ 0x38, 0x44, 0x44, 0x48, 0x7F }, // d 0x64 100
|
||
{ 0x38, 0x54, 0x54, 0x54, 0x18 }, // e 0x65 101
|
||
{ 0x08, 0x7E, 0x09, 0x01, 0x02 }, // f 0x66 102
|
||
{ 0x0C, 0x52, 0x52, 0x52, 0x3E }, // g 0x67 103
|
||
{ 0x7F, 0x08, 0x04, 0x04, 0x78 }, // h 0x68 104
|
||
{ 0x00, 0x44, 0x7D, 0x40, 0x00 }, // i 0x69 105
|
||
{ 0x20, 0x40, 0x44, 0x3D, 0x00 }, // j 0x6A 106
|
||
{ 0x7F, 0x10, 0x28, 0x44, 0x00 }, // k 0x6B 107
|
||
{ 0x00, 0x41, 0x7F, 0x40, 0x00 }, // l 0x6C 108
|
||
{ 0x7C, 0x04, 0x18, 0x04, 0x78 }, // m 0x6D 109
|
||
{ 0x7C, 0x08, 0x04, 0x04, 0x78 }, // n 0x6E 110
|
||
{ 0x38, 0x44, 0x44, 0x44, 0x38 }, // o 0x6F 111
|
||
{ 0x7C, 0x14, 0x14, 0x14, 0x08 }, // p 0x70 112
|
||
{ 0x08, 0x14, 0x14, 0x18, 0x7C }, // q 0x71 113
|
||
{ 0x7C, 0x08, 0x04, 0x04, 0x08 }, // r 0x72 114
|
||
{ 0x48, 0x54, 0x54, 0x54, 0x20 }, // s 0x73 115
|
||
{ 0x04, 0x3F, 0x44, 0x40, 0x20 }, // t 0x74 116
|
||
{ 0x3C, 0x40, 0x40, 0x20, 0x7C }, // u 0x75 117
|
||
{ 0x1C, 0x20, 0x40, 0x20, 0x1C }, // v 0x76 118
|
||
{ 0x3C, 0x40, 0x30, 0x40, 0x3C }, // w 0x77 119
|
||
{ 0x44, 0x28, 0x10, 0x28, 0x44 }, // x 0x78 120
|
||
{ 0x0C, 0x50, 0x50, 0x50, 0x3C }, // y 0x79 121
|
||
{ 0x44, 0x64, 0x54, 0x4C, 0x44 }, // z 0x7A 122
|
||
{ 0x00, 0x08, 0x36, 0x41, 0x00 }, // { 0x7B 123
|
||
{ 0x00, 0x00, 0x7F, 0x00, 0x00 }, // | 0x7C 124
|
||
{ 0x00, 0x41, 0x36, 0x08, 0x00 }, // } 0x7D 125
|
||
{ 0x08, 0x04, 0x08, 0x10, 0x08 }, // ~ 0x7E 126
|
||
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, // 0x7F 127
|
||
|
||
{ 0x7C, 0x12, 0x11, 0x12, 0x7C }, // А 0xC0 192
|
||
{ 0x7F, 0x49, 0x49, 0x49, 0x31 }, // Б 0xC1 193
|
||
{ 0x7F, 0x49, 0x49, 0x49, 0x36 }, // В 0xC2 194
|
||
{ 0x7F, 0x01, 0x01, 0x01, 0x01 }, // Г 0xC3 195
|
||
{ 0x60, 0x3F, 0x21, 0x3F, 0x60 }, // Д 0xC4 196
|
||
{ 0x7F, 0x49, 0x49, 0x49, 0x41 }, // Е 0xC5 197
|
||
{ 0x77, 0x08, 0x7F, 0x08, 0x77 }, // Ж 0xC6 198
|
||
{ 0x22, 0x41, 0x49, 0x49, 0x36 }, // З 0xC7 199
|
||
{ 0x7F, 0x10, 0x08, 0x04, 0x7F }, // И 0xC8 200
|
||
{ 0x7E, 0x10, 0x09, 0x04, 0x7E }, // Й 0xC9 201
|
||
{ 0x7F, 0x08, 0x14, 0x22, 0x41 }, // К 0xCA 202
|
||
{ 0x40, 0x3E, 0x01, 0x01, 0x7F }, // Л 0xCB 203
|
||
{ 0x7F, 0x02, 0x0C, 0x02, 0x7F }, // М 0xCC 204
|
||
{ 0x7F, 0x08, 0x08, 0x08, 0x7F }, // Н 0xCD 205
|
||
{ 0x3E, 0x41, 0x41, 0x41, 0x3E }, // О 0xCE 206
|
||
{ 0x7F, 0x01, 0x01, 0x01, 0x7F }, // П 0xCF 207
|
||
{ 0x7F, 0x09, 0x09, 0x09, 0x06 }, // Р 0xD0 208
|
||
{ 0x3E, 0x41, 0x41, 0x41, 0x22 }, // С 0xD1 209
|
||
{ 0x01, 0x01, 0x7F, 0x01, 0x01 }, // Т 0xD2 210
|
||
{ 0x07, 0x48, 0x48, 0x48, 0x3F }, // У 0xD3 211
|
||
{ 0x0E, 0x11, 0x7F, 0x11, 0x0E }, // Ф 0xD4 212
|
||
{ 0x63, 0x14, 0x08, 0x14, 0x63 }, // Х 0xD5 213
|
||
{ 0x3F, 0x20, 0x20, 0x3F, 0x60 }, // Ц 0xD6 214
|
||
{ 0x07, 0x08, 0x08, 0x08, 0x7F }, // Ч 0xD7 215
|
||
{ 0x7F, 0x40, 0x7E, 0x40, 0x7F }, // Ш 0xD8 216
|
||
{ 0x3F, 0x20, 0x3F, 0x20, 0x7F }, // Щ 0xD9 217
|
||
{ 0x01, 0x7F, 0x48, 0x48, 0x30 }, // Ъ 0xDA 218
|
||
{ 0x7F, 0x48, 0x30, 0x00, 0x7F }, // Ы 0xDB 219
|
||
{ 0x00, 0x7F, 0x48, 0x48, 0x30 }, // Ь 0xDC 220
|
||
{ 0x22, 0x41, 0x49, 0x49, 0x3E }, // Э 0xDD 221
|
||
{ 0x7F, 0x08, 0x3E, 0x41, 0x3E }, // Ю 0xDE 222
|
||
{ 0x46, 0x29, 0x19, 0x09, 0x7F }, // Я 0xDF 223
|
||
{ 0x20, 0x54, 0x54, 0x54, 0x78 }, // а 0xE0 224
|
||
{ 0x3C, 0x4A, 0x4A, 0x4A, 0x31 }, // б 0xE1 225
|
||
{ 0x7C, 0x54, 0x54, 0x28, 0x00 }, // в 0xE2 226
|
||
{ 0x7C, 0x04, 0x04, 0x0C, 0x00 }, // г 0xE3 227
|
||
{ 0x60, 0x3C, 0x24, 0x3C, 0x60 }, // д 0xE4 228
|
||
{ 0x38, 0x54, 0x54, 0x54, 0x18 }, // е 0xE5 229
|
||
{ 0x6C, 0x10, 0x7C, 0x10, 0x6C }, // ж 0xE6 230
|
||
{ 0x00, 0x44, 0x54, 0x54, 0x28 }, // з 0xE7 231
|
||
{ 0x7C, 0x20, 0x10, 0x08, 0x7C }, // и 0xE8 232
|
||
{ 0x7C, 0x21, 0x12, 0x09, 0x7C }, // й 0xE9 233
|
||
{ 0x7C, 0x10, 0x28, 0x44, 0x00 }, // к 0xEA 234
|
||
{ 0x40, 0x38, 0x04, 0x04, 0x7C }, // л 0xEB 235
|
||
{ 0x7C, 0x08, 0x10, 0x08, 0x7C }, // м 0xEC 236
|
||
{ 0x7C, 0x10, 0x10, 0x10, 0x7C }, // н 0xED 237
|
||
{ 0x38, 0x44, 0x44, 0x44, 0x38 }, // о 0xEE 238
|
||
{ 0x7C, 0x04, 0x04, 0x04, 0x7C }, // п 0xEF 239
|
||
{ 0x7C, 0x14, 0x14, 0x14, 0x08 }, // р 0xF0 240
|
||
{ 0x38, 0x44, 0x44, 0x44, 0x00 }, // с 0xF1 241
|
||
{ 0x04, 0x04, 0x7C, 0x04, 0x04 }, // т 0xF2 242
|
||
{ 0x0C, 0x50, 0x50, 0x50, 0x3C }, // у 0xF3 243
|
||
{ 0x08, 0x14, 0x7C, 0x14, 0x08 }, // ф 0xF4 244
|
||
{ 0x44, 0x28, 0x10, 0x28, 0x44 }, // х 0xF5 245
|
||
{ 0x3C, 0x20, 0x20, 0x3C, 0x60 }, // ц 0xF6 246
|
||
{ 0x0C, 0x10, 0x10, 0x10, 0x7C }, // ч 0xF7 247
|
||
{ 0x7C, 0x40, 0x7C, 0x40, 0x7C }, // ш 0xF8 248
|
||
{ 0x3C, 0x20, 0x3C, 0x20, 0x7C }, // щ 0xF9 249
|
||
{ 0x04, 0x7C, 0x50, 0x50, 0x20 }, // ъ 0xFA 250
|
||
{ 0x7C, 0x50, 0x20, 0x00, 0x7C }, // ы 0xFB 251
|
||
{ 0x00, 0x7C, 0x50, 0x50, 0x20 }, // ь 0xFC 252
|
||
{ 0x28, 0x44, 0x54, 0x54, 0x38 }, // э 0xFD 253
|
||
{ 0x7C, 0x10, 0x38, 0x44, 0x38 }, // ю 0xFE 254
|
||
{ 0x48, 0x54, 0x34, 0x14, 0x7C } // я 0xFF 255
|
||
};
|
||
|
||
#endif /* _N3310_H_ */
|
||
```
|
||
|
||
sc55.c:
|
||
```c
|
||
/*
|
||
* Имя : n3310.c
|
||
*
|
||
* Описание : Это драйвер для графического LCD от Nokia 3310, а также его китайских клонов.
|
||
* Базируется на коде библиотек написанных Sylvain Bissonnette и Fandi Gunawan:
|
||
* http://www.microsyl.com/index.php/2010/03/24/nokia-lcd-library/
|
||
* http://fandigunawan.wordpress.com/2008/06/18/lcd-nokia-3310-pcd8544-driver-in-winavravr-gcc/
|
||
* Основные отличия между оригиналом и клоном хорошо описаны в статье от Aheir:
|
||
* http://radiokot.ru/articles/29/
|
||
*
|
||
* Автор : Xander Gresolio <xugres@gmail.com>
|
||
* Веб-страница : http://we.easyelectronics.ru/profile/XANDER/
|
||
*
|
||
* Лицензия : GPL v3.0
|
||
*
|
||
* Компилятор : WinAVR, GCC for AVR platform
|
||
*
|
||
* История :
|
||
* Версия 1.0 (06.08.2011)
|
||
* + Первая версия
|
||
* + Добавлена поддержка китайских клонов LCD Nokia 3310
|
||
* + Полный перевод комментариев к исходному коду драйвера
|
||
* + Таблица символов драйвера дополнена кириллицей (упрощенная Windows-1251)
|
||
* + Добавлена функция рисования окружностей LcdCircle
|
||
* - Исправлены ошибки в проверке корректности координат при вызове функций рисования
|
||
* - Исправлена ошибка в функции LcdSingleBar (неверная отрисовка по y)
|
||
*/
|
||
|
||
#include <avr/io.h>
|
||
#include <string.h>
|
||
#include "sc55.h"
|
||
|
||
// Прототипы приватных функций драйвера
|
||
|
||
static void LcdSend ( byte data, LcdCmdData cd );
|
||
static void Delay ( void );
|
||
|
||
// Глобальные переменные
|
||
|
||
// Кэш в ОЗУ 84*48 бит или 504 байта
|
||
static byte LcdCache [ LCD_CACHE_SIZE ];
|
||
|
||
// Чтобы не обновлять весь дисплей, а лишь ту часть что изменилась,
|
||
// будем отмечать две границы кэша где произошли изменения. Затем
|
||
// можно копировать эту часть кэша между границами в ОЗУ дисплея.
|
||
static int LoWaterMark; // нижняя граница
|
||
static int HiWaterMark; // верхняя граница
|
||
|
||
// Указатель для работы с LcdCache[]
|
||
static int LcdCacheIdx;
|
||
|
||
// Флаг изменений кэша
|
||
static byte UpdateLcd;
|
||
|
||
|
||
|
||
/*
|
||
* Имя : LcdInit
|
||
* Описание : Производит инициализацию порта МК и контроллера LCD
|
||
* Аргумент(ы) : Нет
|
||
* Возвращаемое значение : Нет
|
||
*/
|
||
void LcdInit ( void )
|
||
{
|
||
// Pull-up на вывод подключенный к reset дисплея
|
||
LCD_PORT |= _BV ( LCD_RST_PIN );
|
||
|
||
// Устанавливаем нужные биты порта на выход
|
||
LCD_DDR |= _BV( LCD_RST_PIN ) | _BV( LCD_DC_PIN ) | _BV( LCD_CE_PIN ) | _BV(LCD_DATA_PIN) | _BV(LCD_CLK_PIN);
|
||
|
||
// Некалиброванная задержка
|
||
Delay();
|
||
|
||
// Дергаем reset
|
||
LCD_PORT &= ~( _BV( LCD_RST_PIN ) );
|
||
Delay();
|
||
LCD_PORT |= _BV ( LCD_RST_PIN );
|
||
|
||
// Отключаем LCD контроллер - высокий уровень на SCE
|
||
LCD_PORT |= _BV( LCD_CE_PIN );
|
||
|
||
// Отправляем команды дисплею
|
||
LcdSend( 0x21, LCD_CMD ); // Включаем расширенный набор команд (LCD Extended Commands)
|
||
LcdSend( 0xC8, LCD_CMD ); // Установка контрастности (LCD Vop)
|
||
LcdSend( 0x06, LCD_CMD ); // Установка температурного коэффициента (Temp coefficent)
|
||
LcdSend( 0x16, LCD_CMD ); // Настройка питания (Bias n=2), siemens
|
||
LcdSend( 0x20, LCD_CMD ); // Включаем стандартный набор команд и горизонтальную адресацию (LCD Standard Commands,Horizontal addressing mode)
|
||
LcdSend( 0x0C, LCD_CMD ); // Нормальный режим (LCD in normal mode)
|
||
|
||
// Первичная очистка дисплея
|
||
LcdClear();
|
||
LcdUpdate();
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Имя : LcdClear
|
||
* Описание : Очищает дисплей. Далее необходимо выполнить LcdUpdate
|
||
* Аргумент(ы) : Нет
|
||
* Возвращаемое значение : Нет
|
||
*/
|
||
void LcdClear ( void )
|
||
{
|
||
// // Очистка кэша дисплея
|
||
// int i;
|
||
// for ( i = 0; i < LCD_CACHE_SIZE; i++ )
|
||
// {
|
||
// LcdCache[i] = 0x00;
|
||
// }
|
||
|
||
// Оптимизация от Jakub Lasinski (March 14 2009)
|
||
memset( LcdCache, 0x00, LCD_CACHE_SIZE );
|
||
|
||
// Сброс указателей границ в максимальное значение
|
||
LoWaterMark = 0;
|
||
HiWaterMark = LCD_CACHE_SIZE - 1;
|
||
|
||
// Установка флага изменений кэша
|
||
UpdateLcd = TRUE;
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Имя : LcdUpdate
|
||
* Описание : Копирует кэш в ОЗУ дисплея
|
||
* Аргумент(ы) : Нет
|
||
* Возвращаемое значение : Нет
|
||
*/
|
||
void LcdUpdate (void)
|
||
{
|
||
int i;
|
||
|
||
if ( LoWaterMark < 0 )
|
||
LoWaterMark = 0;
|
||
else if ( LoWaterMark >= LCD_CACHE_SIZE )
|
||
LoWaterMark = LCD_CACHE_SIZE - 1;
|
||
|
||
if ( HiWaterMark < 0 )
|
||
HiWaterMark = 0;
|
||
else if ( HiWaterMark >= LCD_CACHE_SIZE )
|
||
HiWaterMark = LCD_CACHE_SIZE - 1;
|
||
|
||
// Устанавливаем начальный адрес в соответствии к LoWaterMark
|
||
LcdSend( 0x80 | ( LoWaterMark % LCD_X_RES ), LCD_CMD );
|
||
LcdSend( 0x40 | ( LoWaterMark / LCD_X_RES ), LCD_CMD );
|
||
|
||
// Обновляем необходимую часть буфера дисплея
|
||
for ( i = LoWaterMark; i <= HiWaterMark; i++ )
|
||
{
|
||
// Для оригинального дисплея не нужно следить за адресом в буфере,
|
||
// можно просто последовательно выводить данные
|
||
LcdSend( LcdCache[i], LCD_DATA );
|
||
}
|
||
|
||
// Сброс указателей границ в пустоту
|
||
LoWaterMark = LCD_CACHE_SIZE - 1;
|
||
HiWaterMark = 0;
|
||
|
||
// Сброс флага изменений кэша
|
||
UpdateLcd = FALSE;
|
||
}
|
||
|
||
|
||
/*
|
||
* Имя : LcdSend
|
||
* Описание : Отправляет данные в контроллер дисплея
|
||
* Аргумент(ы) : data -> данные для отправки
|
||
* cd -> команда или данные (смотри enum в n3310.h)
|
||
* Возвращаемое значение : Нет
|
||
*/
|
||
static void LcdSend ( byte data, LcdCmdData cd )
|
||
{
|
||
// Включаем контроллер дисплея (низкий уровень активный)
|
||
LCD_PORT &= ~( _BV( LCD_CE_PIN ) );
|
||
|
||
byte i;
|
||
|
||
if (cd == LCD_DATA)
|
||
LCD_PORT |= _BV(LCD_DC_PIN);
|
||
else
|
||
LCD_PORT &= ~_BV(LCD_DC_PIN);
|
||
|
||
for (i = 0; i < 8; i++) {
|
||
|
||
if ((data >> (7 - i)) & 1) {
|
||
LCD_PORT |= _BV(LCD_DATA_PIN);
|
||
} else {
|
||
LCD_PORT &= ~_BV(LCD_DATA_PIN);
|
||
}
|
||
|
||
LCD_PORT |= _BV(LCD_CLK_PIN);
|
||
LCD_PORT &= ~_BV(LCD_CLK_PIN);
|
||
|
||
}
|
||
LCD_PORT |= _BV(LCD_DATA_PIN);
|
||
LCD_PORT |= _BV(LCD_DC_PIN);
|
||
|
||
// Отключаем контроллер дисплея
|
||
LCD_PORT |= _BV( LCD_CE_PIN );
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Имя : LcdContrast
|
||
* Описание : Устанавливает контрастность дисплея
|
||
* Аргумент(ы) : контраст -> значение от 0x00 к 0x7F
|
||
* Возвращаемое значение : Нет
|
||
*/
|
||
void LcdContrast ( byte contrast )
|
||
{
|
||
LcdSend( 0x21, LCD_CMD ); // Расширенный набор команд
|
||
LcdSend( 0x80 | contrast, LCD_CMD ); // Установка уровня контрастности
|
||
LcdSend( 0x20, LCD_CMD ); // Стандартный набор команд, горизонтальная адресация
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Имя : Delay
|
||
* Описание : Некалиброванная задержка для процедуры инициализации LCD
|
||
* Аргумент(ы) : Нет
|
||
* Возвращаемое значение : Нет
|
||
*/
|
||
static void Delay ( void )
|
||
{
|
||
int i;
|
||
|
||
for ( i = -32000; i < 32000; i++ );
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Имя : LcdGotoXYFont
|
||
* Описание : Устанавливает курсор в позицию x,y относительно стандартного размера шрифта
|
||
* Аргумент(ы) : x,y -> координаты новой позиции курсора. Значения: 0,0 .. 13,5
|
||
* Возвращаемое значение : смотри возвращаемое значение в n3310.h
|
||
*/
|
||
byte LcdGotoXYFont ( byte x, byte y )
|
||
{
|
||
// Проверка границ
|
||
if( x > LCD_COLS || y > LCD_LINES ) return OUT_OF_BORDER;
|
||
|
||
// Вычисление указателя. Определен как адрес в пределах 504 байт
|
||
LcdCacheIdx = x * LCD_LINES + y * LCD_X_RES;
|
||
return OK;
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Имя : LcdChr
|
||
* Описание : Выводит символ в текущей позиции курсора, затем инкрементирует положение курсора
|
||
* Аргумент(ы) : size -> размер шрифта. Смотри enum в n3310.h
|
||
* ch -> символ для вывода
|
||
* Возвращаемое значение : смотри возвращаемое значение в n3310lcd.h
|
||
*/
|
||
byte LcdChr ( LcdFontSize size, byte ch )
|
||
{
|
||
byte i, c;
|
||
byte b1, b2;
|
||
int tmpIdx;
|
||
|
||
if ( LcdCacheIdx < LoWaterMark )
|
||
{
|
||
// Обновляем нижнюю границу
|
||
LoWaterMark = LcdCacheIdx;
|
||
}
|
||
|
||
if ( (ch >= 0x20) && (ch <= 0x7F) )
|
||
{
|
||
// Смещение в таблице для символов ASCII[0x20-0x7F]
|
||
ch -= 32;
|
||
}
|
||
else if ( ch >= 0xC0 )
|
||
{
|
||
// Смещение в таблице для символов CP1251[0xC0-0xFF]
|
||
ch -= 96;
|
||
}
|
||
else
|
||
{
|
||
// Остальные игнорируем (их просто нет в таблице для экономии памяти)
|
||
ch = 95;
|
||
}
|
||
|
||
if ( size == FONT_1X )
|
||
{
|
||
for ( i = 0; i < 5; i++ )
|
||
{
|
||
// Копируем вид символа из таблицы в кэш
|
||
LcdCache[LcdCacheIdx++] = pgm_read_byte( &(FontLookup[ch][i]) ) << 1;
|
||
}
|
||
}
|
||
else if ( size == FONT_2X )
|
||
{
|
||
tmpIdx = LcdCacheIdx - LCD_X_RES;
|
||
|
||
if ( tmpIdx < LoWaterMark )
|
||
{
|
||
LoWaterMark = tmpIdx;
|
||
}
|
||
|
||
if ( tmpIdx < 0 ) return OUT_OF_BORDER;
|
||
|
||
for ( i = 0; i < 5; i++ )
|
||
{
|
||
// Копируем вид символа из таблицы у временную переменную
|
||
c = pgm_read_byte(&(FontLookup[ch][i])) << 1;
|
||
// Увеличиваем картинку
|
||
// Первую часть
|
||
b1 = (c & 0x01) * 3;
|
||
b1 |= (c & 0x02) * 6;
|
||
b1 |= (c & 0x04) * 12;
|
||
b1 |= (c & 0x08) * 24;
|
||
|
||
c >>= 4;
|
||
// Вторую часть
|
||
b2 = (c & 0x01) * 3;
|
||
b2 |= (c & 0x02) * 6;
|
||
b2 |= (c & 0x04) * 12;
|
||
b2 |= (c & 0x08) * 24;
|
||
|
||
// Копируем две части в кэш
|
||
LcdCache[tmpIdx++] = b1;
|
||
LcdCache[tmpIdx++] = b1;
|
||
LcdCache[tmpIdx + LCD_X_RES - 2] = b2;
|
||
LcdCache[tmpIdx + LCD_X_RES - 1] = b2;
|
||
}
|
||
|
||
// Обновляем x координату курсора
|
||
LcdCacheIdx = (LcdCacheIdx + 11) % LCD_CACHE_SIZE;
|
||
}
|
||
|
||
if ( LcdCacheIdx > HiWaterMark )
|
||
{
|
||
// Обновляем верхнюю границу
|
||
HiWaterMark = LcdCacheIdx;
|
||
}
|
||
|
||
// Горизонтальный разрыв между символами
|
||
LcdCache[LcdCacheIdx] = 0x00;
|
||
// Если достигли позицию указателя LCD_CACHE_SIZE - 1, переходим в начало
|
||
if(LcdCacheIdx == (LCD_CACHE_SIZE - 1) )
|
||
{
|
||
LcdCacheIdx = 0;
|
||
return OK_WITH_WRAP;
|
||
}
|
||
// Иначе просто инкрементируем указатель
|
||
LcdCacheIdx++;
|
||
return OK;
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Имя : LcdStr
|
||
* Описание : Эта функция предназначена для печати строки которая хранится в RAM
|
||
* Аргумент(ы) : size -> размер шрифта. Смотри enum в n3310.h
|
||
* dataArray -> массив содержащий строку которую нужно напечатать
|
||
* Возвращаемое значение : смотри возвращаемое значение в n3310lcd.h
|
||
*/
|
||
byte LcdStr ( LcdFontSize size, byte dataArray[] )
|
||
{
|
||
byte tmpIdx=0;
|
||
byte response;
|
||
while( dataArray[ tmpIdx ] != '\0' )
|
||
{
|
||
// Выводим символ
|
||
response = LcdChr( size, dataArray[ tmpIdx ] );
|
||
// Не стоит волноваться если произойдет OUT_OF_BORDER,
|
||
// строка будет печататься дальше из начала дисплея
|
||
if( response == OUT_OF_BORDER)
|
||
return OUT_OF_BORDER;
|
||
// Увеличиваем указатель
|
||
tmpIdx++;
|
||
}
|
||
return OK;
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Имя : LcdFStr
|
||
* Описание : Эта функция предназначена для печати строки которая хранится в Flash ROM
|
||
* Аргумент(ы) : size -> размер шрифта. Смотри enum в n3310.h
|
||
* dataPtr -> указатель на строку которую нужно напечатать
|
||
* Возвращаемое значение : смотри возвращаемое значение в n3310lcd.h
|
||
* Пример : LcdFStr(FONT_1X, PSTR("Hello World"));
|
||
* LcdFStr(FONT_1X, &name_of_string_as_array);
|
||
*/
|
||
byte LcdFStr ( LcdFontSize size, const byte *dataPtr )
|
||
{
|
||
byte c;
|
||
byte response;
|
||
for ( c = pgm_read_byte( dataPtr ); c; ++dataPtr, c = pgm_read_byte( dataPtr ) )
|
||
{
|
||
// Выводим символ
|
||
response = LcdChr( size, c );
|
||
if(response == OUT_OF_BORDER)
|
||
return OUT_OF_BORDER;
|
||
}
|
||
|
||
return OK;
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Имя : LcdPixel
|
||
* Описание : Отображает пиксель по абсолютным координатам (x,y)
|
||
* Аргумент(ы) : x,y -> абсолютные координаты пикселя
|
||
* mode -> Off, On или Xor. Смотри enum в n3310.h
|
||
* Возвращаемое значение : смотри возвращаемое значение в n3310lcd.h
|
||
*/
|
||
byte LcdPixel ( byte x, byte y, LcdPixelMode mode )
|
||
{
|
||
int index;
|
||
byte offset;
|
||
byte data;
|
||
|
||
// Защита от выхода за пределы
|
||
if ( x >= LCD_X_RES || y >= LCD_Y_RES) return OUT_OF_BORDER;
|
||
|
||
// Пересчет индекса и смещения
|
||
index = ( ( y / LCD_LINES ) * LCD_X_RES ) + x;
|
||
offset = y - ( ( y / 8) * LCD_LINES );
|
||
|
||
data = LcdCache[ index ];
|
||
|
||
// Обработка битов
|
||
|
||
// Режим PIXEL_OFF
|
||
if ( mode == PIXEL_OFF )
|
||
{
|
||
data &= ( ~( 0x01 << offset ) );
|
||
}
|
||
// Режим PIXEL_ON
|
||
else if ( mode == PIXEL_ON )
|
||
{
|
||
data |= ( 0x01 << offset );
|
||
}
|
||
// Режим PIXEL_XOR
|
||
else if ( mode == PIXEL_XOR )
|
||
{
|
||
data ^= ( 0x01 << offset );
|
||
}
|
||
|
||
// Окончательный результат копируем в кэш
|
||
LcdCache[ index ] = data;
|
||
|
||
if ( index < LoWaterMark )
|
||
{
|
||
// Обновляем нижнюю границу
|
||
LoWaterMark = index;
|
||
}
|
||
|
||
if ( index > HiWaterMark )
|
||
{
|
||
// Обновляем верхнюю границу
|
||
HiWaterMark = index;
|
||
}
|
||
return OK;
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Имя : LcdLine
|
||
* Описание : Рисует линию между двумя точками на дисплее (алгоритм Брезенхэма)
|
||
* Аргумент(ы) : x1, y1 -> абсолютные координаты начала линии
|
||
* x2, y2 -> абсолютные координаты конца линии
|
||
* mode -> Off, On или Xor. Смотри enum в n3310.h
|
||
* Возвращаемое значение : смотри возвращаемое значение в n3310lcd.h
|
||
*/
|
||
byte LcdLine ( byte x1, byte y1, byte x2, byte y2, LcdPixelMode mode )
|
||
{
|
||
int dx, dy, stepx, stepy, fraction;
|
||
byte response;
|
||
|
||
// dy y2 - y1
|
||
// -- = -------
|
||
// dx x2 - x1
|
||
|
||
dy = y2 - y1;
|
||
dx = x2 - x1;
|
||
|
||
// dy отрицательное
|
||
if ( dy < 0 )
|
||
{
|
||
dy = -dy;
|
||
stepy = -1;
|
||
}
|
||
else
|
||
{
|
||
stepy = 1;
|
||
}
|
||
|
||
// dx отрицательное
|
||
if ( dx < 0 )
|
||
{
|
||
dx = -dx;
|
||
stepx = -1;
|
||
}
|
||
else
|
||
{
|
||
stepx = 1;
|
||
}
|
||
|
||
dx <<= 1;
|
||
dy <<= 1;
|
||
|
||
// Рисуем начальную точку
|
||
response = LcdPixel( x1, y1, mode );
|
||
if(response)
|
||
return response;
|
||
|
||
// Рисуем следующие точки до конца
|
||
if ( dx > dy )
|
||
{
|
||
fraction = dy - ( dx >> 1);
|
||
while ( x1 != x2 )
|
||
{
|
||
if ( fraction >= 0 )
|
||
{
|
||
y1 += stepy;
|
||
fraction -= dx;
|
||
}
|
||
x1 += stepx;
|
||
fraction += dy;
|
||
|
||
response = LcdPixel( x1, y1, mode );
|
||
if(response)
|
||
return response;
|
||
|
||
}
|
||
}
|
||
else
|
||
{
|
||
fraction = dx - ( dy >> 1);
|
||
while ( y1 != y2 )
|
||
{
|
||
if ( fraction >= 0 )
|
||
{
|
||
x1 += stepx;
|
||
fraction -= dy;
|
||
}
|
||
y1 += stepy;
|
||
fraction += dx;
|
||
|
||
response = LcdPixel( x1, y1, mode );
|
||
if(response)
|
||
return response;
|
||
}
|
||
}
|
||
|
||
// Установка флага изменений кэша
|
||
UpdateLcd = TRUE;
|
||
return OK;
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Имя : LcdCircle
|
||
* Описание : Рисует окружность (алгоритм Брезенхэма)
|
||
* Аргумент(ы) : x, y -> абсолютные координаты центра
|
||
* radius -> радиус окружности
|
||
* mode -> Off, On или Xor. Смотри enum в n3310.h
|
||
* Возвращаемое значение : смотри возвращаемое значение в n3310lcd.h
|
||
*/
|
||
byte LcdCircle(byte x, byte y, byte radius, LcdPixelMode mode)
|
||
{
|
||
signed char xc = 0;
|
||
signed char yc = 0;
|
||
signed char p = 0;
|
||
|
||
if ( x >= LCD_X_RES || y >= LCD_Y_RES) return OUT_OF_BORDER;
|
||
|
||
yc = radius;
|
||
p = 3 - (radius<<1);
|
||
while (xc <= yc)
|
||
{
|
||
LcdPixel(x + xc, y + yc, mode);
|
||
LcdPixel(x + xc, y - yc, mode);
|
||
LcdPixel(x - xc, y + yc, mode);
|
||
LcdPixel(x - xc, y - yc, mode);
|
||
LcdPixel(x + yc, y + xc, mode);
|
||
LcdPixel(x + yc, y - xc, mode);
|
||
LcdPixel(x - yc, y + xc, mode);
|
||
LcdPixel(x - yc, y - xc, mode);
|
||
if (p < 0) p += (xc++ << 2) + 6;
|
||
else p += ((xc++ - yc--)<<2) + 10;
|
||
}
|
||
|
||
// Установка флага изменений кэша
|
||
UpdateLcd = TRUE;
|
||
return OK;
|
||
}
|
||
|
||
|
||
/*
|
||
* Имя : LcdSingleBar
|
||
* Описание : Рисует один закрашенный прямоугольник
|
||
* Аргумент(ы) : baseX -> абсолютная координата x (нижний левый угол)
|
||
* baseY -> абсолютная координата y (нижний левый угол)
|
||
* height -> высота (в пикселях)
|
||
* width -> ширина (в пикселях)
|
||
* mode -> Off, On или Xor. Смотри enum в n3310.h
|
||
* Возвращаемое значение : смотри возвращаемое значение в n3310lcd.h
|
||
*/
|
||
byte LcdSingleBar ( byte baseX, byte baseY, byte height, byte width, LcdPixelMode mode )
|
||
{
|
||
byte tmpIdxX,tmpIdxY,tmp;
|
||
|
||
byte response;
|
||
|
||
// Проверка границ
|
||
if ( ( baseX >= LCD_X_RES) || ( baseY >= LCD_Y_RES) ) return OUT_OF_BORDER;
|
||
|
||
if ( height > baseY )
|
||
tmp = 0;
|
||
else
|
||
tmp = baseY - height + 1;
|
||
|
||
// Рисование линий
|
||
for ( tmpIdxY = tmp; tmpIdxY <= baseY; tmpIdxY++ )
|
||
{
|
||
for ( tmpIdxX = baseX; tmpIdxX < (baseX + width); tmpIdxX++ )
|
||
{
|
||
response = LcdPixel( tmpIdxX, tmpIdxY, mode );
|
||
if(response)
|
||
return response;
|
||
|
||
}
|
||
}
|
||
|
||
// Установка флага изменений кэша
|
||
UpdateLcd = TRUE;
|
||
return OK;
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Имя : LcdBars
|
||
* Описание : Рисует группу закрашенных прямоугольников (в режиме PIXEL_ON)
|
||
* Аргумент(ы) : data[] -> данные которые нужно отобразить
|
||
* numbBars -> количество прямоугольников
|
||
* width -> ширина (в пикселях)
|
||
* multiplier -> множитель для высоты
|
||
* Возвращаемое значение : смотри возвращаемое значение в n3310lcd.h
|
||
* Примечание : Пожалуйста проверьте значения EMPTY_SPACE_BARS, BAR_X, BAR_Y в n3310.h
|
||
* Пример : byte example[5] = {1, 2, 3, 4, 5};
|
||
* LcdBars(example, 5, 3, 2);
|
||
*/
|
||
byte LcdBars ( byte data[], byte numbBars, byte width, byte multiplier )
|
||
{
|
||
byte b;
|
||
byte tmpIdx = 0;
|
||
byte response;
|
||
|
||
for ( b = 0; b < numbBars ; b++ )
|
||
{
|
||
// Защита от выхода за пределы
|
||
if ( tmpIdx > LCD_X_RES - 1 ) return OUT_OF_BORDER;
|
||
|
||
// Расчет значения x
|
||
tmpIdx = ((width + EMPTY_SPACE_BARS) * b) + BAR_X;
|
||
|
||
// Рисуем один прямоугольник
|
||
response = LcdSingleBar( tmpIdx, BAR_Y, data[b] * multiplier, width, PIXEL_ON);
|
||
if(response == OUT_OF_BORDER)
|
||
return response;
|
||
}
|
||
|
||
// Установка флага изменений кэша
|
||
UpdateLcd = TRUE;
|
||
return OK;
|
||
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Имя : LcdRect
|
||
* Описание : Рисует незакрашенный прямоугольник
|
||
* Аргумент(ы) : x1 -> абсолютная координата x левого верхнего угла
|
||
* y1 -> абсолютная координата y левого верхнего угла
|
||
* x2 -> абсолютная координата x правого нижнего угла
|
||
* y2 -> абсолютная координата y правого нижнего угла
|
||
* mode -> Off, On или Xor. Смотри enum в n3310.h
|
||
* Возвращаемое значение : смотри возвращаемое значение в n3310lcd.h
|
||
*/
|
||
byte LcdRect ( byte x1, byte y1, byte x2, byte y2, LcdPixelMode mode )
|
||
{
|
||
byte tmpIdx;
|
||
|
||
// Проверка границ
|
||
if ( ( x1 >= LCD_X_RES) || ( x2 >= LCD_X_RES) || ( y1 >= LCD_Y_RES) || ( y2 >= LCD_Y_RES) )
|
||
return OUT_OF_BORDER;
|
||
|
||
if ( ( x2 > x1 ) && ( y2 > y1 ) )
|
||
{
|
||
// Рисуем горизонтальные линии
|
||
for ( tmpIdx = x1; tmpIdx <= x2; tmpIdx++ )
|
||
{
|
||
LcdPixel( tmpIdx, y1, mode );
|
||
LcdPixel( tmpIdx, y2, mode );
|
||
}
|
||
|
||
// Рисуем вертикальные линии
|
||
for ( tmpIdx = y1; tmpIdx <= y2; tmpIdx++ )
|
||
{
|
||
LcdPixel( x1, tmpIdx, mode );
|
||
LcdPixel( x2, tmpIdx, mode );
|
||
}
|
||
|
||
// Установка флага изменений кэша
|
||
UpdateLcd = TRUE;
|
||
}
|
||
return OK;
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Имя : LcdImage
|
||
* Описание : Рисует картинку из массива сохраненного в Flash ROM
|
||
* Аргумент(ы) : Указатель на массив картинки
|
||
* Возвращаемое значение : Нет
|
||
*/
|
||
void LcdImage ( const byte *imageData )
|
||
{
|
||
// // Инициализация указателя кэша
|
||
// LcdCacheIdx = 0;
|
||
// // В пределах кэша
|
||
// for ( LcdCacheIdx = 0; LcdCacheIdx < LCD_CACHE_SIZE; LcdCacheIdx++ )
|
||
// {
|
||
// // Копируем данные из массива в кэш
|
||
// LcdCache[LcdCacheIdx] = pgm_read_byte( imageData++ );
|
||
// }
|
||
|
||
// Оптимизация от Jakub Lasinski (March 14 2009)
|
||
memcpy_P( LcdCache, imageData, LCD_CACHE_SIZE ); // Тоже самое что и выше, но занимает меньше памяти и быстрее выполняется
|
||
|
||
// Сброс указателей границ в максимальное значение
|
||
LoWaterMark = 0;
|
||
HiWaterMark = LCD_CACHE_SIZE - 1;
|
||
|
||
// Установка флага изменений кэша
|
||
UpdateLcd = TRUE;
|
||
}
|
||
```
|
||
|
||
main.c:
|
||
```c
|
||
#include <util/delay.h>
|
||
#include "sc55.h"
|
||
|
||
|
||
int main() {
|
||
LcdInit();
|
||
LcdContrast(0x45);
|
||
while (1) {
|
||
LcdClear();
|
||
LcdRect(0, 0, LCD_X_RES - 2, LCD_Y_RES - 2, PIXEL_ON);
|
||
LcdLine(0, 0, LCD_X_RES - 2, LCD_Y_RES - 2, PIXEL_ON);
|
||
LcdLine(0, LCD_Y_RES - 2, LCD_X_RES - 2, 0, PIXEL_ON);
|
||
LcdUpdate();
|
||
_delay_ms(1000);
|
||
|
||
LcdClear();
|
||
LcdGotoXYFont(0, 2);
|
||
LcdStr(FONT_2X, "Привет,");
|
||
LcdGotoXYFont(0, 4);
|
||
LcdStr(FONT_2X, "мир!");
|
||
LcdUpdate();
|
||
_delay_ms(1000);
|
||
}
|
||
|
||
}
|
||
```
|
||
|
||
![helloworld](helloworld.jpg)
|
||
|
||
![lines](lines.jpg) |