NOKIA 3310 n3310_c

  1. * Автор : Xander Gresolio <xugres@gmail.com>
  2.  
  3.  
  4. #include <avr/io.h>
  5. #include <string.h>
  6. #include <avr/pgmspace.h>
  7. #include <avr/interrupt.h>
  8. #include "n3310.h"
  9.  
  10. // Прототипы приватных функций драйвера
  11. static void LcdSend ( byte data, LcdCmdData cd );
  12. static void Delay ( void );
  13.  
  14. // Глобальные переменные
  15.  
  16. // Кэш в ОЗУ 84*48 бит или 504 байта
  17. static byte LcdCache [ LCD_CACHE_SIZE ];
  18.  
  19. // Чтобы не обновлять весь дисплей, а лишь ту часть что изменилась,
  20. // будем отмечать две границы кэша где произошли изменения. Затем
  21. // можно копировать эту часть кэша между границами в ОЗУ дисплея.
  22. static int LoWaterMark; // нижняя граница
  23. static int HiWaterMark; // верхняя граница
  24.  
  25. // Указатель для работы с LcdCache[]
  26. static int LcdCacheIdx;
  27.  
  28. // Флаг изменений кэша
  29. static byte UpdateLcd;
  30.  
  31.  
  32. /*
  33.  * Имя : LcdInit
  34.  * Описание : Производит инициализацию порта и SPI МК, контроллера LCD
  35.  * Аргумент(ы) : Нет
  36.  * Возвращаемое значение : Нет
  37.  */
  38. void LcdInit ( void )
  39. {
  40. // Pull-up на вывод подключенный к reset дисплея
  41. LCD_PORT |= _BV ( LCD_RST_PIN );
  42.  
  43. // Устанавливаем нужные биты порта на выход
  44. LCD_DDR |= _BV( LCD_RST_PIN ) | _BV( LCD_DC_PIN ) | _BV( LCD_CE_PIN ) | _BV( SPI_MOSI_PIN ) | _BV( SPI_CLK_PIN );
  45.  
  46. // Некалиброванная задержка
  47. Delay();
  48.  
  49. // Дергаем reset
  50. LCD_PORT &= ~( _BV( LCD_RST_PIN ) );
  51. Delay();
  52. LCD_PORT |= _BV ( LCD_RST_PIN );
  53.  
  54. // Активируем SPI:
  55. // без прерываний, старший бит первый, режим мастера, CPOL->0, CPHA->0, Clk/4
  56. SPCR = 0x50;
  57.  
  58. // Отключаем LCD контроллер - высокий уровень на SCE
  59. LCD_PORT |= _BV( LCD_CE_PIN );
  60.  
  61. // Отправляем команды дисплею
  62. LcdSend( 0x21, LCD_CMD ); // Включаем расширенный набор команд (LCD Extended Commands)
  63. LcdSend( 0xC8, LCD_CMD ); // Установка контрастности (LCD Vop)
  64. LcdSend( 0x06, LCD_CMD ); // Установка температурного коэффициента (Temp coefficent)
  65. LcdSend( 0x13, LCD_CMD ); // Настройка питания (LCD bias mode 1:48)
  66. LcdSend( 0x20, LCD_CMD ); // Включаем стандартный набор команд и горизонтальную адресацию
  67. //(LCD Standard Commands,Horizontal addressing mode)
  68. LcdSend( 0x0C, LCD_CMD ); // Нормальный режим (LCD in normal mode)
  69.  
  70. // Первичная очистка дисплея
  71. LcdClear();
  72. LcdUpdate();
  73. }
  74.  
  75.  
  76. /*
  77.  * Имя : LcdClear
  78.  * Описание : Очищает дисплей. Далее необходимо выполнить LcdUpdate
  79.  * Аргумент(ы) : Нет
  80.  * Возвращаемое значение : Нет
  81.  */
  82. void LcdClear ( void )
  83. {
  84. // // Очистка кэша дисплея
  85. // int i;
  86. // for ( i = 0; i < LCD_CACHE_SIZE; i++ )
  87. // {
  88. // LcdCache[i] = 0x00;
  89. // }
  90.  
  91. // Оптимизация от Jakub Lasinski (March 14 2009)
  92. memset( LcdCache, 0x00, LCD_CACHE_SIZE );
  93.  
  94. // Сброс указателей границ в максимальное значение
  95. LoWaterMark = 0;
  96. HiWaterMark = LCD_CACHE_SIZE - 1;
  97.  
  98. // Установка флага изменений кэша
  99. UpdateLcd = TRUE;
  100. }
  101.  
  102.  
  103. /*
  104.  * Имя : LcdUpdate
  105.  * Описание : Копирует кэш в ОЗУ дисплея
  106.  * Аргумент(ы) : Нет
  107.  * Возвращаемое значение : Нет
  108.  */
  109. void LcdUpdate (void)
  110. {
  111. int i;
  112.  
  113. if ( LoWaterMark < 0 )
  114. LoWaterMark = 0;
  115. else if ( LoWaterMark >= LCD_CACHE_SIZE )
  116. LoWaterMark = LCD_CACHE_SIZE - 1;
  117.  
  118. if ( HiWaterMark < 0 )
  119. HiWaterMark = 0;
  120. else if ( HiWaterMark >= LCD_CACHE_SIZE )
  121. HiWaterMark = LCD_CACHE_SIZE - 1;
  122.  
  123. #ifdef CHINA_LCD // Алгоритм для китайского ЖК из нестандартным контроллером
  124.  
  125. byte x,y;
  126.  
  127. // 102 x 64 - таково предполагаемое разрешение буфера китайского ЖК, при чем
  128. // память буфера отображается на дисплей со сдвигом вверх на 3 пикселя.
  129. // Поэтому выводим картинку ниже - начиная с второй строки y+1, а потом
  130. // сдвинем вверх (опять таки фича китайца, полезная в данном случае)
  131.  
  132. x = LoWaterMark % LCD_X_RES; // Устанавливаем начальный адрес x
  133. LcdSend( 0x80 | x, LCD_CMD ); // относительно нижней границы LoWaterMark
  134.  
  135. y = LoWaterMark / LCD_X_RES + 1; // Устанавливаем начальный адрес y+1
  136. LcdSend( 0x40 | y, LCD_CMD ); // относительно нижней границы LoWaterMark
  137.  
  138. for ( i = LoWaterMark; i <= HiWaterMark; i++ )
  139. {
  140. // передаем данные в буфер дисплея
  141. LcdSend( LcdCache[i], LCD_DATA );
  142.  
  143. x++; // заодно подсчитываем координату x, чтобы вовремя перейти на новую строку
  144. if (x >= LCD_X_RES) // если вышли за предел, то переходим на следующую строку (x=0; y++)
  145. {
  146. // проще говоря, чтобы верно заполнить нужную часть нестандартного буфера,
  147. // придется явно указывать требуемый адрес, иначе все поплывет :)
  148. x=0;
  149. LcdSend( 0x80, LCD_CMD );
  150. y++;
  151. LcdSend( 0x40 | y, LCD_CMD );
  152. }
  153. }
  154.  
  155. LcdSend( 0x21, LCD_CMD ); // Включаем расширенный набор команд
  156. LcdSend( 0x45, LCD_CMD ); // Сдвигаем картинку на 5 пикселей вверх
  157. //(нестандартная команда китайца, оригинал её игнорирует)
  158. LcdSend( 0x20, LCD_CMD ); // Включаем стандартный набор команд и горизонтальную адресацию
  159.  
  160. #else // Алгоритм для оригинального дисплея
  161.  
  162. // Устанавливаем начальный адрес в соответствии к LoWaterMark
  163. LcdSend( 0x80 | ( LoWaterMark % LCD_X_RES ), LCD_CMD );
  164. LcdSend( 0x40 | ( LoWaterMark / LCD_X_RES ), LCD_CMD );
  165.  
  166. // Обновляем необходимую часть буфера дисплея
  167. for ( i = LoWaterMark; i <= HiWaterMark; i++ )
  168. {
  169. // Для оригинального дисплея не нужно следить за адресом в буфере,
  170. // можно просто последовательно выводить данные
  171. LcdSend( LcdCache[i], LCD_DATA );
  172. }
  173.  
  174. #endif
  175.  
  176. // Сброс указателей границ в пустоту
  177. LoWaterMark = LCD_CACHE_SIZE - 1;
  178. HiWaterMark = 0;
  179.  
  180. // Сброс флага изменений кэша
  181. UpdateLcd = FALSE;
  182. }
  183.  
  184.  
  185. /*
  186.  * Имя : LcdSend
  187.  * Описание : Отправляет данные в контроллер дисплея
  188.  * Аргумент(ы) : data -> данные для отправки
  189.  * cd -> команда или данные (смотри enum в n3310.h)
  190.  * Возвращаемое значение : Нет
  191.  */
  192. static void LcdSend ( byte data, LcdCmdData cd )
  193. {
  194. // Включаем контроллер дисплея (низкий уровень активный)
  195. LCD_PORT &= ~( _BV( LCD_CE_PIN ) );
  196.  
  197. if ( cd == LCD_DATA )
  198. {
  199. LCD_PORT |= _BV( LCD_DC_PIN );
  200. }
  201. else
  202. {
  203. LCD_PORT &= ~( _BV( LCD_DC_PIN ) );
  204. }
  205.  
  206. // Отправка данных в контроллер дисплея
  207. SPDR = data;
  208.  
  209. // Ждем окончания передачи
  210. while ( (SPSR & 0x80) != 0x80 );
  211.  
  212. // Отключаем контроллер дисплея
  213. LCD_PORT |= _BV( LCD_CE_PIN );
  214. }
  215.  
  216.  
  217.  
  218. /*
  219.  * Имя : LcdContrast
  220.  * Описание : Устанавливает контрастность дисплея
  221.  * Аргумент(ы) : контраст -> значение от 0x00 к 0x7F
  222.  * Возвращаемое значение : Нет
  223.  */
  224. void LcdContrast ( byte contrast )
  225. {
  226. LcdSend( 0x21, LCD_CMD ); // Расширенный набор команд
  227. LcdSend( 0x80 | contrast, LCD_CMD ); // Установка уровня контрастности
  228. LcdSend( 0x20, LCD_CMD ); // Стандартный набор команд, горизонтальная адресация
  229. }
  230.  
  231.  
  232. /*
  233.  * Имя : Delay
  234.  * Описание : Некалиброванная задержка для процедуры инициализации LCD
  235.  * Аргумент(ы) : Нет
  236.  * Возвращаемое значение : Нет
  237.  */
  238. static void Delay ( void )
  239. {
  240. int i;
  241.  
  242. for ( i = -32000; i < 32000; i++ );
  243. }
  244.  
  245.  
  246. /*
  247.  * Имя : LcdGotoXYFont
  248.  * Описание : Устанавливает курсор в позицию x,y относительно стандартного размера шрифта
  249.  * Аргумент(ы) : x,y -> координаты новой позиции курсора. Значения: 0,0 .. 13,5
  250.  * Возвращаемое значение : смотри возвращаемое значение в n3310.h
  251.  */
  252. byte LcdGotoXYFont ( byte x, byte y )
  253. {
  254. // Проверка границ
  255. if( x > 13 || y > 5 ) return OUT_OF_BORDER;
  256.  
  257. // Вычисление указателя. Определен как адрес в пределах 504 байт
  258. LcdCacheIdx = x * 6 + y * 84;
  259. return OK;
  260. }
  261.  
  262.  
  263. /*
  264.  * Имя : LcdChr
  265.  * Описание : Выводит символ в текущей позиции курсора, затем инкрементирует положение курсора
  266.  * Аргумент(ы) : size -> размер шрифта. Смотри enum в n3310.h
  267.  * ch -> символ для вывода
  268.  * Возвращаемое значение : смотри возвращаемое значение в n3310lcd.h
  269.  */
  270. byte LcdChr ( LcdFontSize size, byte ch )
  271. {
  272. byte i, c;
  273. byte b1, b2;
  274. int tmpIdx;
  275.  
  276. if ( LcdCacheIdx < LoWaterMark )
  277. {
  278. // Обновляем нижнюю границу
  279. LoWaterMark = LcdCacheIdx;
  280. }
  281.  
  282. if ( (ch >= 0x20) && (ch <= 0x7F) )
  283. {
  284. // Смещение в таблице для символов ASCII[0x20-0x7F]
  285. ch -= 32;
  286. }
  287. else if ( ch >= 0xC0 )
  288. {
  289. // Смещение в таблице для символов CP1251[0xC0-0xFF]
  290. ch -= 96;
  291. }
  292. else
  293. {
  294. // Остальные игнорируем (их просто нет в таблице для экономии памяти)
  295. ch = 85;
  296. }
  297.  
  298. if ( size == FONT_1X )
  299. {
  300. for ( i = 0; i < 5; i++ )
  301. {
  302. // Копируем вид символа из таблицы в кэш
  303. LcdCache[LcdCacheIdx++] = pgm_read_byte( &(FontLookup[ch][i]) ) << 1;
  304. }
  305. }
  306. else if ( size == FONT_2X )
  307. {
  308. tmpIdx = LcdCacheIdx - 84;
  309.  
  310. if ( tmpIdx < LoWaterMark )
  311. {
  312. LoWaterMark = tmpIdx;
  313. }
  314.  
  315. if ( tmpIdx < 0 ) return OUT_OF_BORDER;
  316.  
  317. for ( i = 0; i < 5; i++ )
  318. {
  319. // Копируем вид символа из таблицы у временную переменную
  320. c = pgm_read_byte(&(FontLookup[ch][i])) << 1;
  321. // Увеличиваем картинку
  322. // Первую часть
  323. b1 = (c & 0x01) * 3;
  324. b1 |= (c & 0x02) * 6;
  325. b1 |= (c & 0x04) * 12;
  326. b1 |= (c & 0x08) * 24;
  327.  
  328. c >>= 4;
  329. // Вторую часть
  330. b2 = (c & 0x01) * 3;
  331. b2 |= (c & 0x02) * 6;
  332. b2 |= (c & 0x04) * 12;
  333. b2 |= (c & 0x08) * 24;
  334.  
  335. // Копируем две части в кэш
  336. LcdCache[tmpIdx++] = b1;
  337. LcdCache[tmpIdx++] = b1;
  338. LcdCache[tmpIdx + 82] = b2;
  339. LcdCache[tmpIdx + 83] = b2;
  340. }
  341.  
  342. // Обновляем x координату курсора
  343. LcdCacheIdx = (LcdCacheIdx + 11) % LCD_CACHE_SIZE;
  344. }
  345.  
  346. if ( LcdCacheIdx > HiWaterMark )
  347. {
  348. // Обновляем верхнюю границу
  349. HiWaterMark = LcdCacheIdx;
  350. }
  351.  
  352. // Горизонтальный разрыв между символами
  353. LcdCache[LcdCacheIdx] = 0x00;
  354. // Если достигли позицию указателя LCD_CACHE_SIZE - 1, переходим в начало
  355. if(LcdCacheIdx == (LCD_CACHE_SIZE - 1) )
  356. {
  357. LcdCacheIdx = 0;
  358. return OK_WITH_WRAP;
  359. }
  360. // Иначе просто инкрементируем указатель
  361. LcdCacheIdx++;
  362. return OK;
  363. }
  364.  
  365.  
  366.  
  367. /*
  368.  * Имя : LcdStr
  369.  * Описание : Эта функция предназначена для печати строки которая хранится в RAM
  370.  * Аргумент(ы) : size -> размер шрифта. Смотри enum в n3310.h
  371.  * dataArray -> массив содержащий строку которую нужно напечатать
  372.  * Возвращаемое значение : смотри возвращаемое значение в n3310lcd.h
  373.  */
  374. byte LcdStr ( LcdFontSize size, byte dataArray[] )
  375. {
  376. byte tmpIdx=0;
  377. byte response;
  378. while( dataArray[ tmpIdx ] != '\0' )
  379. {
  380. // Выводим символ
  381. response = LcdChr( size, dataArray[ tmpIdx ] );
  382. // Не стоит волноваться если произойдет OUT_OF_BORDER,
  383. // строка будет печататься дальше из начала дисплея
  384. if( response == OUT_OF_BORDER)
  385. return OUT_OF_BORDER;
  386. // Увеличиваем указатель
  387. tmpIdx++;
  388. }
  389. return OK;
  390. }
  391.  
  392.  
  393. /*
  394.  * Имя : LcdFStr
  395.  * Описание : Эта функция предназначена для печати строки которая хранится в Flash ROM
  396.  * Аргумент(ы) : size -> размер шрифта. Смотри enum в n3310.h
  397.  * dataPtr -> указатель на строку которую нужно напечатать
  398.  * Возвращаемое значение : смотри возвращаемое значение в n3310lcd.h
  399.  * Пример : LcdFStr(FONT_1X, PSTR("Hello World"));
  400.  * LcdFStr(FONT_1X, &name_of_string_as_array);
  401.  */
  402. byte LcdFStr ( LcdFontSize size, const byte *dataPtr )
  403. {
  404. byte c;
  405. byte response;
  406. for ( c = pgm_read_byte( dataPtr ); c; ++dataPtr, c = pgm_read_byte( dataPtr ) )
  407. {
  408. // Выводим символ
  409. response = LcdChr( size, c );
  410. if(response == OUT_OF_BORDER)
  411. return OUT_OF_BORDER;
  412. }
  413.  
  414. return OK;
  415. }
  416.  
  417.  
  418. /*
  419.  * Имя : LcdPixel
  420.  * Описание : Отображает пиксель по абсолютным координатам (x,y)
  421.  * Аргумент(ы) : x,y -> абсолютные координаты пикселя
  422.  * mode -> Off, On или Xor. Смотри enum в n3310.h
  423.  * Возвращаемое значение : смотри возвращаемое значение в n3310lcd.h
  424.  */
  425. byte LcdPixel ( byte x, byte y, LcdPixelMode mode )
  426. {
  427. int index;
  428. byte offset;
  429. byte data;
  430.  
  431. // Защита от выхода за пределы
  432. if ( x >= LCD_X_RES || y >= LCD_Y_RES) return OUT_OF_BORDER;
  433.  
  434. // Пересчет индекса и смещения
  435. index = ( ( y / 8 ) * 84 ) + x;
  436. offset = y - ( ( y / 8 ) * 8 );
  437.  
  438. data = LcdCache[ index ];
  439.  
  440. // Обработка битов
  441.  
  442. // Режим PIXEL_OFF
  443. if ( mode == PIXEL_OFF )
  444. {
  445. data &= ( ~( 0x01 << offset ) );
  446. }
  447. // Режим PIXEL_ON
  448. else if ( mode == PIXEL_ON )
  449. {
  450. data |= ( 0x01 << offset );
  451. }
  452. // Режим PIXEL_XOR
  453. else if ( mode == PIXEL_XOR )
  454. {
  455. data ^= ( 0x01 << offset );
  456. }
  457.  
  458. // Окончательный результат копируем в кэш
  459. LcdCache[ index ] = data;
  460.  
  461. if ( index < LoWaterMark )
  462. {
  463. // Обновляем нижнюю границу
  464. LoWaterMark = index;
  465. }
  466.  
  467. if ( index > HiWaterMark )
  468. {
  469. // Обновляем верхнюю границу
  470. HiWaterMark = index;
  471. }
  472. return OK;
  473. }
  474.  
  475.  
  476. /*
  477.  * Имя : LcdLine
  478.  * Описание : Рисует линию между двумя точками на дисплее (алгоритм Брезенхэма)
  479.  * Аргумент(ы) : x1, y1 -> абсолютные координаты начала линии
  480.  * x2, y2 -> абсолютные координаты конца линии
  481.  * mode -> Off, On или Xor. Смотри enum в n3310.h
  482.  * Возвращаемое значение : смотри возвращаемое значение в n3310lcd.h
  483.  */
  484. byte LcdLine ( byte x1, byte y1, byte x2, byte y2, LcdPixelMode mode )
  485. {
  486. int dx, dy, stepx, stepy, fraction;
  487. byte response;
  488.  
  489. // dy y2 - y1
  490. // -- = -------
  491. // dx x2 - x1
  492.  
  493. dy = y2 - y1;
  494. dx = x2 - x1;
  495.  
  496. // dy отрицательное
  497. if ( dy < 0 )
  498. {
  499. dy = -dy;
  500. stepy = -1;
  501. }
  502. else
  503. {
  504. stepy = 1;
  505. }
  506.  
  507. // dx отрицательное
  508. if ( dx < 0 )
  509. {
  510. dx = -dx;
  511. stepx = -1;
  512. }
  513. else
  514. {
  515. stepx = 1;
  516. }
  517.  
  518. dx <<= 1;
  519. dy <<= 1;
  520.  
  521. // Рисуем начальную точку
  522. response = LcdPixel( x1, y1, mode );
  523. if(response)
  524. return response;
  525.  
  526. // Рисуем следующие точки до конца
  527. if ( dx > dy )
  528. {
  529. fraction = dy - ( dx >> 1);
  530. while ( x1 != x2 )
  531. {
  532. if ( fraction >= 0 )
  533. {
  534. y1 += stepy;
  535. fraction -= dx;
  536. }
  537. x1 += stepx;
  538. fraction += dy;
  539.  
  540. response = LcdPixel( x1, y1, mode );
  541. if(response)
  542. return response;
  543.  
  544. }
  545. }
  546. else
  547. {
  548. fraction = dx - ( dy >> 1);
  549. while ( y1 != y2 )
  550. {
  551. if ( fraction >= 0 )
  552. {
  553. x1 += stepx;
  554. fraction -= dy;
  555. }
  556. y1 += stepy;
  557. fraction += dx;
  558.  
  559. response = LcdPixel( x1, y1, mode );
  560. if(response)
  561. return response;
  562. }
  563. }
  564.  
  565. // Установка флага изменений кэша
  566. UpdateLcd = TRUE;
  567. return OK;
  568. }
  569.  
  570.  
  571. /*
  572.  * Имя : LcdCircle
  573.  * Описание : Рисует окружность (алгоритм Брезенхэма)
  574.  * Аргумент(ы) : x, y -> абсолютные координаты центра
  575.  * radius -> радиус окружности
  576.  * mode -> Off, On или Xor. Смотри enum в n3310.h
  577.  * Возвращаемое значение : смотри возвращаемое значение в n3310lcd.h
  578.  */
  579. byte LcdCircle(byte x, byte y, byte radius, LcdPixelMode mode)
  580. {
  581. signed char xc = 0;
  582. signed char yc = 0;
  583. signed char p = 0;
  584.  
  585. if ( x >= LCD_X_RES || y >= LCD_Y_RES) return OUT_OF_BORDER;
  586.  
  587. yc = radius;
  588. p = 3 - (radius<<1);
  589. while (xc <= yc)
  590. {
  591. LcdPixel(x + xc, y + yc, mode);
  592. LcdPixel(x + xc, y - yc, mode);
  593. LcdPixel(x - xc, y + yc, mode);
  594. LcdPixel(x - xc, y - yc, mode);
  595. LcdPixel(x + yc, y + xc, mode);
  596. LcdPixel(x + yc, y - xc, mode);
  597. LcdPixel(x - yc, y + xc, mode);
  598. LcdPixel(x - yc, y - xc, mode);
  599. if (p < 0) p += (xc++ << 2) + 6;
  600. else p += ((xc++ - yc--)<<2) + 10;
  601. }
  602.  
  603. // Установка флага изменений кэша
  604. UpdateLcd = TRUE;
  605. return OK;
  606. }
  607.  
  608. /*
  609.  * Имя : LcdSingleBar
  610.  * Описание : Рисует один закрашенный прямоугольник
  611.  * Аргумент(ы) : baseX -> абсолютная координата x (нижний левый угол)
  612.  * baseY -> абсолютная координата y (нижний левый угол)
  613.  * height -> высота (в пикселях)
  614.  * width -> ширина (в пикселях)
  615.  * mode -> Off, On или Xor. Смотри enum в n3310.h
  616.  * Возвращаемое значение : смотри возвращаемое значение в n3310lcd.h
  617.  */
  618. byte LcdSingleBar ( byte baseX, byte baseY, byte height, byte width, LcdPixelMode mode )
  619. {
  620. byte tmpIdxX,tmpIdxY,tmp;
  621.  
  622. byte response;
  623.  
  624. // Проверка границ
  625. if ( ( baseX >= LCD_X_RES) || ( baseY >= LCD_Y_RES) ) return OUT_OF_BORDER;
  626.  
  627. if ( height > baseY )
  628. tmp = 0;
  629. else
  630. tmp = baseY - height + 1;
  631.  
  632. // Рисование линий
  633. for ( tmpIdxY = tmp; tmpIdxY <= baseY; tmpIdxY++ )
  634. {
  635. for ( tmpIdxX = baseX; tmpIdxX < (baseX + width); tmpIdxX++ )
  636. {
  637. response = LcdPixel( tmpIdxX, tmpIdxY, mode );
  638. if(response)
  639. return response;
  640. }
  641. }
  642.  
  643. // Установка флага изменений кэша
  644. UpdateLcd = TRUE;
  645. return OK;
  646. }
  647.  
  648. /*
  649.  * Имя : LcdBars
  650.  * Описание : Рисует группу закрашенных прямоугольников (в режиме PIXEL_ON)
  651.  * Аргумент(ы) : data[] -> данные которые нужно отобразить
  652.  * numbBars -> количество прямоугольников
  653.  * width -> ширина (в пикселях)
  654.  * multiplier -> множитель для высоты
  655.  * Возвращаемое значение : смотри возвращаемое значение в n3310lcd.h
  656.  * Примечание : Пожалуйста проверьте значения EMPTY_SPACE_BARS, BAR_X, BAR_Y в n3310.h
  657.  * Пример : byte example[5] = {1, 2, 3, 4, 5};
  658.  * LcdBars(example, 5, 3, 2);
  659.  */
  660. byte LcdBars ( byte data[], byte numbBars, byte width, byte multiplier )
  661. {
  662. byte b;
  663. byte tmpIdx = 0;
  664. byte response;
  665.  
  666. for ( b = 0; b < numbBars ; b++ )
  667. {
  668. // Защита от выхода за пределы
  669. if ( tmpIdx > LCD_X_RES - 1 ) return OUT_OF_BORDER;
  670.  
  671. // Расчет значения x
  672. tmpIdx = ((width + EMPTY_SPACE_BARS) * b) + BAR_X;
  673.  
  674. // Рисуем один прямоугольник
  675. response = LcdSingleBar( tmpIdx, BAR_Y, data[b] * multiplier, width, PIXEL_ON);
  676. if(response == OUT_OF_BORDER)
  677. return response;
  678. }
  679.  
  680. // Установка флага изменений кэша
  681. UpdateLcd = TRUE;
  682. return OK;
  683.  
  684. }
  685.  
  686. /*
  687.  * Имя : LcdRect
  688.  * Описание : Рисует незакрашенный прямоугольник
  689.  * Аргумент(ы) : x1 -> абсолютная координата x левого верхнего угла
  690.  * y1 -> абсолютная координата y левого верхнего угла
  691.  * x2 -> абсолютная координата x правого нижнего угла
  692.  * y2 -> абсолютная координата y правого нижнего угла
  693.  * mode -> Off, On или Xor. Смотри enum в n3310.h
  694.  * Возвращаемое значение : смотри возвращаемое значение в n3310lcd.h
  695.  */
  696. byte LcdRect ( byte x1, byte y1, byte x2, byte y2, LcdPixelMode mode )
  697. {
  698. byte tmpIdx;
  699.  
  700. // Проверка границ
  701. if ( ( x1 >= LCD_X_RES) || ( x2 >= LCD_X_RES) || ( y1 >= LCD_Y_RES) || ( y2 >= LCD_Y_RES) )
  702. return OUT_OF_BORDER;
  703.  
  704. if ( ( x2 > x1 ) && ( y2 > y1 ) )
  705. {
  706. // Рисуем горизонтальные линии
  707. for ( tmpIdx = x1; tmpIdx <= x2; tmpIdx++ )
  708. {
  709. LcdPixel( tmpIdx, y1, mode );
  710. LcdPixel( tmpIdx, y2, mode );
  711. }
  712.  
  713. // Рисуем вертикальные линии
  714. for ( tmpIdx = y1; tmpIdx <= y2; tmpIdx++ )
  715. {
  716. LcdPixel( x1, tmpIdx, mode );
  717. LcdPixel( x2, tmpIdx, mode );
  718. }
  719.  
  720. // Установка флага изменений кэша
  721. UpdateLcd = TRUE;
  722. }
  723. return OK;
  724. }
  725.  
  726. /*
  727.  * Имя : LcdImage
  728.  * Описание : Рисует картинку из массива сохраненного в Flash ROM
  729.  * Аргумент(ы) : Указатель на массив картинки
  730.  * Возвращаемое значение : Нет
  731.  */
  732. void LcdImage ( const byte *imageData )
  733. {
  734. // // Инициализация указателя кэша
  735. // LcdCacheIdx = 0;
  736. // // В пределах кэша
  737. //for ( LcdCacheIdx = 0; LcdCacheIdx < LCD_CACHE_SIZE; LcdCacheIdx++ )
  738. // {
  739. // // Копируем данные из массива в кэш
  740. // LcdCache[LcdCacheIdx] = pgm_read_byte( imageData++ );
  741. // }
  742.  
  743. // Оптимизация от Jakub Lasinski (March 14 2009)
  744. memcpy_P( LcdCache, imageData, LCD_CACHE_SIZE );
  745. // Тоже самое что и выше, но занимает меньше памяти и быстрее выполняется
  746.  
  747. // Сброс указателей границ в максимальное значение
  748. LoWaterMark = 0;
  749. HiWaterMark = LCD_CACHE_SIZE - 1;
  750.  
  751. // Установка флага изменений кэша
  752. UpdateLcd = TRUE;
  753. }