-
Notifications
You must be signed in to change notification settings - Fork 0
/
LCD4.asm
166 lines (124 loc) · 5.75 KB
/
LCD4.asm
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
;=========== LCD Define ==================================================================
.equ DATA_PORT = PORTA ; LCD Data Port
.equ DATA_PIN = PINA
.equ DATA_DDR = DDRA
.equ CMD_PORT = PORTB ; LCD Control Port
.equ CMD_PIN = PINB
.equ CMD_DDR = DDRB
.equ E = 2
.equ RW = 1
.equ RS = 0
.equ SPEED = 13 ; 14 для XTAL=16MHz, 10 для XTAL=8MHz,
; 6 для XTAL=4MHz, 5 для XTAL<4MHz
;=========================================================================================
;=========== LCD Proc ====================================================================
InitHW: CBI CMD_PORT,RS ; Выставляем нужные уровни на управляющих выводах
CBI CMD_PORT,RW ; Порты на выход
CBI CMD_PORT,E ; И сразу же выставляются на 1
SBI CMD_DDR,RS
SBI CMD_DDR,RW
SBI CMD_DDR,E
RCALL PortIn ; Порт данных на вход
RET
;=========================================================================================
BusyWait: CLI ; Ожидание флага занятости контроллера дисплея
RCALL PortIn ; Порты на вход
CBI CMD_PORT,RS ; Идет Команда!
SBI CMD_PORT,RW ; Чтение!
BusyLoop: SBI CMD_PORT,E ; Поднять строб
RCALL LCD_Delay ; Подождать
IN R16,DATA_PIN ; Считать байт
PUSH R16 ; Сохранить его в стек. Дело в том, что у нас R16 убивается в LCD_Delay
CBI CMD_PORT,E ; Бросить строб - первый цикл (старший полубайт)
RCALL LCD_Delay ; Подождем маленько
SBI CMD_PORT,E ; Поднимем строб
RCALL LCD_Delay ; Подождем
CBI CMD_PORT,E ; Опустим строб - нужно для пропуска второго полубайта
RCALL LCD_Delay ; Задержка снова
POP R16 ; А теперь достаем сныканый байт - в нем наш флаг. Может быть.
ANDI R16,0x80 ; Продавливаем по маске. Есть флаг?
BRNE BusyLoop ; Если нет, то переход
BusyNo: SEI ; Разрешаем прерывания.
RET
;=========================================================================================
; Запись команды в дисплей. Код команды в R17
CMD_WR: CLI ; Запрет прерываний
RCALL BusyWait ; Ждем готовности
CBI CMD_PORT,RS ; Идет команда!
RJMP WR_END ; Переход на запись
;-----------------------------------------------------------------------------------------
; Запись данных в дисплей. Код данных в R17
DATA_WR: CLI ; Запрет прерываний
RCALL BusyWait ; Ждем готовности
SBI CMD_PORT,RS ; Идут данные!
WR_END: CBI CMD_PORT,RW ; Запись!
SBI CMD_PORT,E ; Поднять строб
RCALL PortOut ; Порт настроить на выход!
PUSH R17 ; Сохраним данные которые будем выводить в стеке
ANDI R17,0xF0 ; Отдавим по маске данным младшую тетраду.
IN R16,DATA_PORT ; Возьмем из порта данных старое значение
ANDI R16,0x0F ; Отдавим ему старшую тетраду
PUSH R16 ; Сохраним результа в стеке. Пригодится
OR R16,R17 ; Склеим младшую тетраду из порта со старшей тетрадой данных
OUT DATA_PORT,R16 ; Выдадим этого мутанта в порт.
RCALL LCD_Delay ; Подождем
CBI CMD_PORT,E ; Бросим строб вниз - данные ушли в индикатор
RCALL LCD_Delay ; Подождем
SBI CMD_PORT,E ; Поднимем строб
POP R16 ; Достанем из стека младшую тетраду из порта
POP R17 ; И данные которые мы выводим
SWAP R17 ; Поменяем тетрады местами у байта данных
ANDI R17,0xF0 ; Отдавим младшую тетраду
OR R16,R17 ; Склеим младшую тетраду из порта с старшей тетрадой данных (бывшая младшая)
OUT DATA_PORT,R16 ; Выдадим в порт
RCALL LCD_Delay ; Подождем
CBI CMD_Port,E ; Бросим строб
RCALL PortIn ; Порт вернем в прежнее состояние - на вход
SEI ; Разрешим прерывания
RET ; Возврат
;=========================================================================================
; Чтение команды из дисплея. Результат в R17
CMD_RD: CLI ; Запрет прерываний
RCALL BusyWait ; Ждем контроллер
CBI CMD_PORT,RS ; Команда!
RJMP RD_END ; Идем на чтение
;-----------------------------------------------------------------------------------------
; Чтение команды из дисплея. Результат в R17
DATA_RD: CLI ; Запрет прерываний
RCALL BusyWait ; Ждем контроллер
SBI CMD_PORT,RS ; Данные!
RD_END: SBI CMD_PORT,RW ; Чтение!
SBI CMD_PORT,E ; Поднимаем строб
RCALL LCD_Delay ; Ждем
IN R17,DATA_PIN ; Читаем из порта байт
CBI CMD_PORT,E ; Бросем строб вниз
ANDI R17,0xF0 ; Отдавливаем ему младшую тетраду
SWAP R17 ; Обмениваем тетрады местами
RCALL LCD_Delay ; Ждем
SBI CMD_PORT,E ; Поднимаем строб
MOV R16,R17 ; Прячем старшую тетраду в R16
IN R17,DATA_PIN ; Берем еще один байт
CBI CMD_PORT,E ; Бросаем строб
ANDI R17,0xF0 ; Отдавливаем младшую тетраду
OR R17,R16 ; Склеиваем результат с старшим байтом
SWAP R17 ; Разорваичаем байт. Т.к. первой выходила старшая тетрада
SEI ; разрешаем прерывания
RET ; Возврат.
;=========================================================================================
PortIn: IN R16,DATA_DDR ; Данные из DDR в регистр
ANDI R16,0x0F ; Отдавливаем старшую тетраду - нам нужно сохранить младшую и обнулить старшую
OUT DATA_DDR,R16 ; Выдаем результат в порт.
IN R16,DATA_PORT ; Берем данные из порта
ORI R16,0xF0 ; Выставляем все биты старшей тетрады, не трогая младшую
OUT DATA_PORT,R16 ; Выдаем в порт
RET
;=========================================================================================
PortOut: IN R16,DATA_DDR ; Данные из ДДР в регистр
ORI R16,0xF0 ; Выставляем все биты старшей тетрады, не трогая младшую
OUT DATA_DDR,R16 ; Выдаем данные в порт
RET
;=========================================================================================
LCD_Delay: LDI R16,SPEED ; Задержка на несколько тактов. Для того чтобы дисплей
L_loop: DEC R16 ; Успевал обрабатывать данные
BRNE L_loop
RET