Atmel и LCD от Nokia 1110

Для разработчиков устройств на микропроцессорах эта тема достаточно актуальна. Для меня не исключение 🙂
 Наиболее распространен среди недорогих чёрно белых экранов lcd от Nokia 3310 и о нем есть достаточное кол-во информации, готовые библиотеки для разных языков. Но у этого экрана есть недостатки — нет светодиодной подсветки и сложность физического подключения, так как контакты там напылённые на стекле.
 Экран от Nokia 1110/1110i лишён этих недостатков.  У него есть подсветка и гибкий шлейф с разъёмом на конце.  Контакты мелкие (шаг 0,65 мм), но подпаяться всё таки можно.  Экран 96*66 пикселя.
 Контроллер управления по командам совпадает с PCF8814    (  http://www.nxp.com/acrobat_download2/datasheets/PCF8814_1.pdf  ) 
  Много информации для изучения я почерпнул на форумах monitor.net.ru  (тема pavel-pervomaysk об этом индикаторе) и roboforum.ru (тема dmq). Похоже что экраны бывают с белой(3.3v) и зелёной (3.9 v) подсветкой. Светодиоды (контакты 6 и 7) гальванически развязаны от остального контроллера. Если микропроцессор запитать от 3.3v, то резисторный делитель не нужен. 
Питание контроллера : ножка 10  +1.8v, ножка 9 +2.8v.
  Видеопамять 864 байт  организована следующим способом:  0-й адрес соответствует 8-ми вертикальным пикселя в левом вернем углу. 96 байт заполняют одну 8-ми пиксельную полосу. Всего 8 полных и 1 урезанная полоса.

Вот листинг программы — примера применения этого экрана.

; Экран от Nokia 1110 96*72 пикселей
; Память — первые 96 байт — это верхние 8 линий. Бит 0 соответствует первой линии.
; Следующие 96 байт — следующие 8 линий.
;>> это вариант с использованием 4-х ножек проца.<<   рабочий
; есть процедуры
; clr_lcd    —  очистка экрана
; print_char —  печать ASCI символа 5*7 коды от 32 до 128
; set_lineXY —  установить позицию в любое знакоместо экрана
; set_line   —  установить позицию в начало указанной строки

.include «m32def.inc»
.def tmp    = r19
.def tmp1   = r20
.def loop   = r21

// LCD
.equ   lcd_clk = PB0 // Lcd clock
.equ   lcd_dat = PB1 // Lcd data
.equ   lcd_CS  = PB2 // crystal select 
.equ   lcd_res = PB3 // reset chip

.CSEG ;Code segment

;Interrupt vectors:
.org 0
 rjmp Init    ;reset vector

Init:
      cli                  ;запрет прерывний
      ldi tmp,low(RAMEND)  ;определение начала стека
      out SPL,tmp
      ldi tmp,high(RAMEND) ;определение начала стека
      out SPH,tmp

   ldi tmp,(1<<lcd_clk)|(1<<lcd_dat)|(1<<lcd_CS)|(1<<lcd_res)
   out ddrb,tmp  
   ldi tmp,(1<<lcd_clk)|(1<<lcd_dat)|(1<<lcd_CS)|(1<<lcd_res)
   out portb,tmp 

// Инициализация ЖКИ модуля
 ldi tmp,0xE2 // Internal reset
 rcall lcd_cmd
 ldi tmp,0xEB // температурная компенсация включена
 rcall lcd_cmd
 ldi tmp,0x2F // режим питания
 rcall lcd_cmd
 ldi tmp,0xA1 // направление LSB -> MSB
 rcall lcd_cmd
 ldi tmp,0xA4 // очистить все пиксели жки
 rcall lcd_cmd
 ldi tmp,0xA6 // позитивное изображение
 ;ldi tmp,0xA7 // негативное изображение
 rcall lcd_cmd
 ldi tmp,0xAF // включить дисплей
 rcall lcd_cmd
main:
//****************************************************
ldi   tmp1,0         // ставим указатель на начало экрана
 rcall set_line

 ldi   xl,’0′         // заполняем строку символами
 rcall print_char
 ldi   xl,’1′
 rcall print_char
 ldi   xl,’2′
 rcall print_char
 ldi   xl,’3′
 rcall print_char
 ldi   xl,’4′
 rcall print_char
 ldi   xl,’5′
 rcall print_char
 ldi   xl,’6′
 rcall print_char
 ldi   xl,’7′
 rcall print_char
 ldi   xl,’8′
 rcall print_char
 ldi   xl,’9′
 rcall print_char
 ldi   xl,’A’
 rcall print_char
 ldi   xl,’B’
 rcall print_char
 ldi   xl,’C’
 rcall print_char
 ldi   xl,’D’
 rcall print_char
 ldi   xl,’E’
 rcall print_char
 ldi   xl,’F’
 rcall print_char

    ldi tmp1,1             // выбираем вторую строку жки (один из вариантов)
    ldi    tmp,0xB0
    add    tmp,tmp1
 rcall  lcd_cmd
 ldi    tmp,0x10        // устанавливаем старшие биты горизонтального адреса => 0
 rcall  lcd_cmd         //
 ldi    tmp,0x06        // устанавливаем младшие биты горизонтального адреса => на второе знакоместо
 rcall  lcd_cmd

 ldi   xl,’F’           //
 rcall print_char

 ser    tmp             // рисуем чёрный прямоугольничек
 rcall  out_byte
 ser    tmp             //
 rcall  out_byte
 ser    tmp             //
 rcall  out_byte
 ser    tmp             //
 rcall  out_byte
 ser    tmp             //
 rcall  out_byte
 ser    tmp             //
 rcall  out_byte

    ldi tmp,8              ; ставим указатель на 4-ю строку 8-й столбец
 ldi tmp1,4
 rcall set_lineXY

 ldi   xl,’A’           ; печатаем тут символ
 rcall print_char

zz:
rjmp zz       ; останавливаем программу
//*****************************************************
// устанавливается в уазанную позицию через tmp1(от 0 до 8) строку и в tmp (от 0 до 15) столбец
set_lineXY:               
    ldi   xl,6             // вычисляем позицию в пикселях (N знакоместа * 6 )
    muls  xl,tmp
    mov    tmp,r0
 andi   tmp,0b00001111
    rcall  lcd_cmd         // 4 младшие бита адреса X

    swap   r0
 mov    tmp,r0
 andi   tmp, 0b00000111
 ori    tmp, 0b00010000
 rcall  lcd_cmd         // 3 старшие бита адреса X

    ldi    tmp,0xB0
    add    tmp,tmp1
 rcall  lcd_cmd         // номер строки
ret

// устанавливается в начало предварительно уазанную через tmp1(от 0 до 8) строку
set_line:                 
 ldi    tmp,0x10        // устанавливаем младшие биты горизонтального адреса => 0
 rcall  lcd_cmd         //
 ldi    tmp,0x00        // устанавливаем старшие биты горизонтального адреса => 0
 rcall  lcd_cmd         //
    ldi    tmp,0xB0
    add    tmp,tmp1
 rcall  lcd_cmd
ret

// Send command to LCD
lcd_cmd:              
 cbi    portb,lcd_CS    // select chip
 cbi    portb,lcd_dat    //признак передачи КОМАНДЫ
 sbi    portb,lcd_clk   // CLK -> 1
    rjmp ob
 // Send data to LCD
out_byte:            
 cbi    portb,lcd_CS    // select chip 
 sbi    portb,lcd_dat    // признак передачи ДАННЫХ
 sbi    portb,lcd_clk   // CLK -> 1
 nop                    //
 nop                    //
ob:
 cbi     portb,lcd_clk  // CLK -> 0
lcd_cm:
 ldi     loop,8         //
outs12:                //  
 clc                    //
 rol     tmp            //
 brcc    noc2           //
 sbi     portb,lcd_dat  // DATA=1
 rjmp    drdy2          //
noc2:                  //
 cbi     portb,lcd_dat  // DATA=0
drdy2:                 // 
 nop                    //
 sbi     portb,lcd_clk  // CLK -> 1
 nop                    //
 nop                    //
 cbi     portb,lcd_clk  // CLK -> 0
 dec     loop           //
 brne    outs12         // 
 sbi    portb,lcd_CS    // select chip 
 clc 
ret                    //

// задержка 10мкс
wait_10us:
 ldi tmp,2
wt:
    dec tmp
 brne wt
ret

// очистка экрана
clr_lcd:
 ldi    xl,low (864)    // 
 ldi    xh,high(864)    //
clcd:                  //
 clr    tmp             //
 rcall  out_byte        //
 sbiw   xl,1            // 
 brne   clcd            //
ret                    // 

; очистить теущую полосу (должны быть в начале этой полосы)
clr_line:    
 ldi    tmp1,96
 cline:
 clr    tmp
 rcall  out_byte
 dec    tmp1
 brne   cline
ret
// Print ASCII char to the LCD Nokia 1110i
print_char:          
 clr   xh              // 
 ldi   tmp,5           //
 muls  xl,tmp          //
 mov   xl,r0           //
 mov   xh,r1           //
 ldi   tmp,0xA0        //
 clr   tmp1            //
 sub   xl,tmp          //
 sbc   xh,tmp1         //
 ldi   ZH,high(Code*2) //
 ldi   ZL,low (Code*2) //
 add   ZL,XL           //
 adc   ZH,XH           // 
 lpm   tmp,Z           // Flash addr —> tmp
 rcall out_byte        //
 inc   ZL              // Z + 1
 lpm   tmp,Z           // Flash addr —> tmp
 rcall out_byte        //
 inc   ZL              // Z + 1
 lpm   tmp,Z           // Flash addr —> tmp
 rcall out_byte        //
 inc   ZL              // Z + 1
 lpm   tmp,Z           // Flash addr —> tmp
 rcall out_byte        //
 inc   ZL              // Z + 1
 lpm   tmp,Z           // Flash addr —> tmp
 rcall out_byte        //
 clr   tmp             //
 rcall out_byte        // 
ret                   //
.org  $F08    // символы кодировки 5 х 7 точек.
chartab:
//  ASCII CODE from lcd 5 x 7 pixels
Code:.db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x14,0x7f,0x14,0x7f,0x14,0x24,0x2a,0x7f,0x2a,0x12,0x23,0x13,0x08,0x64,0x62,0x36,0x49,0x55,0x22,0x50,0x00,0x05,0x03,0x00,0x00,0x00,0x1c,0x22,0x41,0x00,0x00,0x41,0x22,0x1c,0x00,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,0x3e,0x51,0x49,0x45,0x3e,0x00,0x42,0x7f,0x40,0x00,0x42,0x61,0x51,0x49,0x46,0x21,0x41,0x45,0x4b,0x31,0x18,0x14,0x12,0x7f,0x10,0x27,0x45,0x45,0x45,0x39,0x3c,0x4a,0x49,0x49,0x30,0x01,0x71,0x09,0x05,0x03,0x36,0x49,0x49,0x49,0x36,0x06,0x49,0x49,0x29,0x1e,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,0x32,0x49,0x79,0x41,0x3e,0x7e,0x11,0x11,0x11,0x7e,0x7f,0x49,0x49,0x49,0x36,0x3e,0x41,0x41,0x41,0x22,0x7f,0x41,0x41,0x22,0x1c,0x7f,0x49,0x49,0x49,0x41,0x7f,0x09,0x09,0x09,0x01,0x3e,0x41,0x49,0x49,0x7a,0x7f,0x08,0x08,0x08,0x7f,0x00,0x41,0x7f,0x41,0x00,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,0x7f,0x09,0x09,0x09,0x06,0x3e,0x41,0x51
     .db 0x21,0x5e,0x7f,0x09,0x19,0x29,0x46,0x46,0x49,0x49,0x49,0x31,0x01,0x01,0x7f,0x01,0x01,0x3f,0x40,0x40,0x40,0x3f,0x1f,0x20,0x40,0x20,0x1f,0x3f,0x40,0x38,0x40,0x3f,0x63,0x14,0x08,0x14,0x63,0x07,0x08,0x70,0x08,0x07,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,0x00,0x01,0x02,0x04,0x00,0x20,0x54,0x54,0x54,0x78,0x7f,0x48,0x44,0x44,0x38,0x38,0x44,0x44,0x44,0x20,0x38,0x44,0x44,0x48,0x7f,0x38,0x54,0x54,0x54,0x18,0x08,0x7e,0x09,0x01,0x02, 0x0c,0x52,0x52,0x52,0x3e,0x7f,0x08,0x04,0x04,0x78,0x00,0x44,0x7d,0x40,0x00,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,0x7c,0x14,0x14,0x14,0x08,0x08,0x14,0x14,0x18,0x7c,0x7c,0x08,0x04,0x04,0x08,0x48,0x54,0x54,0x54,0x20,0x04,0x3f,0x44,0x40,0x20,0x3c,0x40,0x40,0x20,0x7c,0x1c,0x20,0x40,0x20,0x1c,0x3c,0x40,0x30,0x40,0x3c,0x44,0x28,0x10,0x28,0x44,0x0c,0x50,0x50,0x50,0x3c,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

результат работы программы: