Современные информационные
технологии/Компьютерная инженерия
Мясищев А.А.
Хмельницкий национальный
университет, Украина
Вариант организации
дозвона по телефонной линии с помощью микроконтроллеров AVR(1)
В
настоящее время при построении информационно - охранных систем широко
используют микроконтроллеры. Обычно к микроконтроллерам подключают датчики и
после анализа их показаний, по каналам связи выполняется информирование
пользователя о конкретных ситуаций на объекте.
Рассмотрим
практическую реализацию следующего информационного устройства. Предположим, для
организации является критичным пропадание напряжения осветительной сети в
каком-то подразделении, которое работает в автоматическом режиме. Если
напряжение падает, цифровое устройство подключенное, к телефонной линии связи,
используя импульсный способ набора номера должно два раза подряд
дозваниваться на мобильный телефон
абонента. Это цифровое устройство также раз в сутки должно одним звонком
информировать абонента, что оно в рабочем состоянии и, следовательно, никаких
серьезных происшествий в подразделении не произошло. Устройство также должно
просто расширяться путем добавления дополнительных датчиков, работающих на
замыкание, которые инициируют дозвон на мобильный телефон при открывании,
например дверей, окон и т.д. Для построения такого устройства в работе
используется микроконтроллер ATmega16. Его программирование выполнено
на ассемблере с использованием распространяемой бесплатно фирмой Atmel программной среды “AVR Studio”.
Для
программирования микроконтроллера в режиме работы дозвона необходимо
представление, как осуществляется импульсный дозвон по телефонной линии. На
рис.1 представлена схема простого телефонного аппарата. Когда трубка
лежит, к телефонной линии через
конденсатор подключен звонок. При поднятии трубки к линии подключаются последовательно телефон,
угольный микрофон и номеронабиратель.
Рис.1
При наборе номера,
например, ноля, номеронабиратель должен сделать десять размыканий продолжительностью примерно 50мс на 1
размыкание. Длительность замыкания также примерно равна 50мс. Перед набором
следующего номера должна быть выдержана пауза 0.8-1.0с и далее набор номера может быть продолжен.
Аналогично, при наборе цифры шесть делается шесть размыканий. В соответствии с
этим алгоритмом должен быть запрограммирован микроконтроллер. В схеме
устройства вместо телефона и микрофона установлен резистор 50…100ом, а в
качестве номеронабирателя и размыкателя поднятия-опускания трубки – два
независимых реле, которые управляются микроконтроллером через транзисторные
ключи. После окончательного набора номера в программе должна быть предусмотрена
пауза (здесь примерно15с) перед опусканием трубки для того, чтобы абонент
получил на мобильный телефон несколько сигналов вызова.
На
рис. 2 представлена схема устройства. Здесь используется микроконтроллер фирмы Atmel ATmega16. На устройство подаются напряжения от двух независимых источников
постоянного напряжения 9…12В, чтобы исключить сбои микроконтроллера при импульсной работе реле во время дозвона.
Для вывода времени,
установки времени используется четыехсекционный семисегментный индикатор,
который подключен порту B микроконтроллера. Знакоместо выбирается с порта D разрядами 2,3,4,5. В схеме
применен динамический способ индикации,
т.е. в каждый момент времени
отображается только один разряд индикатора. Частота регенерации выбирается
программно не меньше 50 герц, иначе будет заметно мигание индикатора. С помощью
кнопки Кн1 устанавливаются минуты, а Кн2 – часы. Выключатель K1.1 используется в качестве датчика
отсутствия или наличия напряжения в осветительной сети. Если напряжение есть,
выключатель K1.1 должен находиться в разомкнутом состоянии, при отсутствии –
замкнутом. На рис. 3 представлен вариант такого датчика. Источником питания
может служить обычный универсальный источник постоянного напряжения на 9-12В, в
качестве реле – любое маломощное реле,
рассчитанное на напряжение срабатывания 12В (например,
NT73CS10DC12).
Рис.3
Ниже с подробными
комментариями представлена программа, по которой работает спроектированное
устройство.
1 .include
"m16def.inc" ;Присоединение
файла описаний
2 .def temp = r16 ;Присвоить регистру
r16 имя temp
3 .def loop1 = r17
4 .def loop2 = r18
5 .def loop3 = r4
6 .def rab1 = r2
7 .def rab2 = r3
8 .def s = r22 ; Присвоить r22
имя s(Секунды)
9 .def m = r23 ; Присвоить r23 имя m(Минуты)
10 .def
h = r24 ; Присвоить
r24 имя h(Часы)
11 .def reg0 = r25
12 .def reg1 = r19
13 .def reg2 = r20
14 .def reg3 = r21
15 .def temp3 = r1
16 .def zn = r26
17 .equ kdel = 7199 ;Присвоить константе 7199 имя kdel
18 .equ s60 = 60
19 .equ m60 = 60 ;Присвоить
константе 60 имя m60
20 .equ h24 = 24
21 .equ reg10= 10
;--- Резервирование ячеек памяти
22 .dseg ;Выбираем сегмент ОЗУ
23 .org 0x60 ;Устанавливаем
адрес сегмента
;---Резервирование памяти для хранения значений
24 buf0: .byte 1 ; Один байт для хранения значения по
метке buf0
25 buf1: .byte 1 ; Аналогично
26 buf2: .byte 1
27 buf3: .byte 1
28 buf4: .byte 1
29 buf5: .byte 1
30 buf6: .byte 1
31 buf7: .byte 1
32 buf8: .byte 1
33 buf9: .byte 1
34 buf10:
.byte 1
35 bufs:
.byte 1
36 bufm:
.byte 1
37 bufh:
.byte 1
38 bufr0:
.byte 1
39 bufr1: .byte 1
40 bufr2: .byte 1
41 bufr3:
.byte 1
42 bufl3:
.byte 1
;--- Начало программного кода
43 .cseg
; Выбор сегмента программного
кода
44 .org
$000 ;
Установка адреса вектора ; прерывания инициализации
45 rjmp init ;
Переход на начало кода программы ; (на адрес $000)
46 .org
$00C ; Установка адреса вектора ; прерывания (Таймер 1,
совпадение, канал A)
47 rjmp prtim1 ; Переход к подпрограмме
;
обработки этого прерывания
48 .org
$30 ; Установка адреса начала
программы, с которого
;
начинается программный код.
49 init:
50 ldi s,0 ; Запись в регистр s 0
51 ldi m,0
52 ldi h,0
53 ldi reg0,0
54 ldi reg1,0
55 ldi reg2,0
56 ldi reg3,0
57 sts bufs,s ;Запись содержимого s в
ОЗУ по метке bufs
58 sts bufm,m
59 sts bufh,h
60 sts bufr0,reg0
61 sts bufr1,reg1
62 sts bufr2,reg2
63 sts bufr3,reg3
64 ldi temp,255
65 sts bufl3,temp
;
---
Инициализация стека
66 ldi temp,high(RAMEND);Запись старшего
;полубайта
вершины стека в temp
67 out SPH,temp ;Запись его в регистр стека
68 ldi temp,low(RAMEND);Запись
младшего
;полубайта
вершины стека в temp
69 out SPL,temp ;Запись его в регистр стека
;--- Инициализация портов ВВ.
70 ldi temp,0b00000000 ;Записываем 0 в temp
71 out DDRA, temp ;Устанавливаем порт A на ввод
72 ldi temp, 0xFF ;Записываем число $FF в temp
73 out DDRC, temp ;Записываем temp в DDRC (порт
;PC на
вывод)
74 out DDRB, temp ;Записываем это число
; в DDRB
(порт PB на вывод)
75 out PORTA, temp ; Включаем внутренние резисторы
76 out PORTB, temp ;
Записываем то же число в PORTB
;
(потушить светодиод)
77 ldi temp,0b11111001 ;PC1-трубка опущена(0),
;
PC2-прерыватель замкнут(0)
78 out PORTC, temp ; Записываем это в порт C
79 ldi temp,0b01111100 ;
Устанавливаем разряды
;
D2,D3,D4,D5 на вывод,
80 out
DDRD,temp ; а разряды D0,D1 - на ввод
81 ldi temp,0b01000011 ; Выключаем индикацию на
82 out PORTD,temp ; семисегментном индикаторе
;--- Инициализация таймера T1
83 ldi temp, 0x0D ; Выбор режима таймера
84 out TCCR1B, temp
85 ldi temp, high(kdel) ; Старший полубайт кода совпадения
86 out OCR1AH, temp ; Запись в регистр совпадения старш.
87 ldi temp, low(kdel) ; Младший полубайт кода совпадения
88 out OCR1AL, temp ; Запись в регистр совпадения младш.
;--- Запись в регистр маски
89 ldi
temp, 0x10 ; Разрешаем прерывание от таймера
90 out TIMSK,
temp
;--- Инициализация компаратора
91 ldi
temp, 0x80 ; Выключение компаратора
92 out ACSR, temp
;--- Начало основной программы
93 main:
94 ldi
temp, 63 ; Запись начального значения 63 в temp
95 sts buf0, temp ; Запись 63 в buf0 (отображать 0)
96 ldi temp,
6 ; Запись начального значения 6 в
temp
97 sts buf1, temp ; Запись 6 в buf1 (отображать 1)
98 ldi
temp, 91 ; Запись начального значения 91 в temp
99 sts buf2, temp ; Запись 91 в buf2 (отображать 2)
100 ldi
temp, 79 ; Запись значения 79 в temp
101 sts buf3, temp ; Запись 79 в buf3 (отображать 3)
102 ldi
temp, 102 ; Запись начального значения 102 в temp
103 sts buf4, temp ; Запись 102 в buf4 (отображать 4)
104 ldi
temp, 109 ; Запись начального значения 109 в temp
105 sts buf5, temp ; Запись 109 в buf5 (отображать 5)
106 ldi
temp, 125 ; Запись начального значения 125 в temp
107 sts buf6, temp ; Запись 125 в buf6 (отображать 6)
108 ldi
temp, 7 ; Запись начального значения 7 в temp
109 sts buf7, temp ; Запись 7 в buf7 (отображать 7)
110 ldi
temp, 127 ; Запись начального значения 127 в temp
111 sts buf8, temp ; Запись 127 в buf8 (отображать 8)
112 ldi
temp, 111 ; Запись начального значения 111 в temp
113 sts buf9, temp ; Запись 111 в buf8 (отображать 9)
114 sei ; Разрешение
прерываний
115 m11:
; Дозвон по времени (12:00:00)
116 lds s, bufs ;Читаем из bufs в s
117 cpi s,0 ;Сравниваем s с 0
118 brne g1 ;Если
не 0, идти к g1
119 lds m, bufm ;Читаем из bufm в m
120 cpi m,0 ;Сравниваем m с 0
121 brne g1 ;Если
не 0, идти к g1
122 lds h, bufh ;Читаем из bufh в h
123 cpi h,12 ;Сравниваем h с 12
124 brne g1 ;Если
не 12, идти к g1
125 ldi temp,1 ;Если 12 часов
126 add s,temp ;добавляем 1 сек чтобы часы не отставали
127 sts bufs, s ;Записываем s в буфер
128 rcall zvon ;Звоним
129 g1:
;--- Дозвон по событию
130 clr rab2 ; обнуляем rab2
131 in rab2,PINA ; Проверяем 4-й разряд.
132 sbrs rab2,4 ; Если 4-й разряд равен 1, вып. rjmp a2
133 rjmp a1 ;
Если 4-й разряд равен 0, идем к a1
134 rjmp a2 ; Переходим к a2
135 a1: rcall zvon ; Звоним 1-й раз
136 rcall zvon ; Звоним 2-й раз
137 clr rab2 ; Обнуляем rab2
138 in rab2,PINA ; Проверяем 4-й разряд.
139 sbrs rab2,4 ; Если 4-й разряд равен 0, то
140 rcall loopu ; выполняем подпрограмму loopu
141 a2:
;--- Вывод на индикатор
;--- Минуты
142 lds reg0,bufr0 ; Читаем из bufr0 в reg0
143 sts buf10, reg0 ; Пишем в buf10 содержимое reg0
144 ldi temp, 0b01100011 ;Включаем 5-й
145 out PORTD,temp ;разряд индикатора(минуты)
146 rcall print ;Переход к подпрограмме индикации разряда
147 rcall wait1 ;Делаем задержку для просмотра индикации
148 ldi temp, 0b01000011 ;Выключаем
149 out PORTD,temp ;5-й разряд
150 lds reg1,bufr1 ; Читаем из bufr1
в reg1
151 sts buf10, reg1 ; Пишем в buf10 содержимое reg1
152 ldi temp, 0b01010011 ;Включаем 4-й
153 out PORTD,temp ;разряд индикатора(минуты)
154 rcall print ;Переход к подпрограмме индикации разряда
155 rcall wait1 ;Делаем задержку для просмотра индикации
156 ldi temp, 0b01000011 ;Выключаем
157 out PORTD,temp ;4-й разряд
; ---Часы
158 lds reg2,bufr2 ; Читаем из bufr2
в reg2
159 sts buf10, reg2 ; Пишем в buf10 содержимое reg2
160 ldi temp, 0b01001011 ;Включаем 3-й
161 out PORTD,temp ;разряд индикатора(часы)
162 ldi temp,0b10000000 ;Выводим
163 out PORTB,temp ;точку
164 rcall wait1 ;Делаем задержку при распечатке точки
165 rcall print ;Переход к подпрограмме индикации разряда
166 rcall wait1 ;Делаем задержку для просмотра индикации
167 ldi temp, 0b01000011 ;Выключаем
168 out PORTD,temp ;3-й разряд
169 lds reg3,bufr3 ; Читатем из bufr3 в reg3
170 sts buf10, reg3 ; Пишем в buf10 содержимое reg3
171 ldi temp, 0b01000111 ;Включаем 2-й
172 out PORTD,temp ;разряд индикатора (часы)
173 rcall print ;Переход к подпрограмме индикации разряда
174 rcall wait1 ;Делаем задержку для просмотра индикации
175 ldi temp, 0b01000011 ;Выключаем
176 out PORTD,temp ;2-й разряд
177 rjmp m11 ;Бесконечный
цикл индикации разрядов
;--- Подпрограмма задержка
178 wait1:
179 ldi loop1,2 ; Помещаем в loop1 константу задержки
180 wt1: dec loop1 ; Уменьшаем значение регистра loop на 1
181 breq wt4 ; Если loop1=0, идти к wt4
182 ldi loop2,5 ; Помещаем в loop2 константу задержки
183 wt2: dec loop2 ; Уменьшаем значение регистра loop2
184 breq wt1 ; Если loop1=0,
идти к wt1
185 lds loop3,bufl3 ; Помещаем в loop3 константу задержки
186 wt3: dec loop3 ; Уменьшаем значение регистра loop3
187 brne wt3 ; Если не ноль, идти к wt3
188 rjmp wt2 ; идти к wt2
189 wt4: ret ;
Выход из подпрограммы
;--- Подпрограмма индикации разряда
190 print: lds rab1,buf10 ; читаем из buf10 в rab1
191 ldi temp,0 ; записываем 0 в temp
192 cp temp,rab1 ; сравниваем регистры
193 brne m2 ;
если rab1 не равен 0 идти к m2
194 lds temp, buf0 ; если rab1=0 считываем в temp buf0(ноль)
195 out PORTB, temp; и выводим его на
индикатор
196 rjmp mm ;
Переходим в конец подпрограммы
197 m2: ldi temp,1 ; записываем 1 в temp
198 cp temp,rab1 ; сравниваем регистры
199 brne m3 ;
если rab1 не равно 1 идти к m3
200 lds temp, buf1 ; если rab1 равно 1 считываем в temp
;
buf1(единицу)
201 out PORTB, temp; и выводим её на
индикатор
202 rjmp mm ;
Переходим в конец подпрограммы
203 m3: ldi temp,2 ; записываем 2 в temp
204 cp temp,rab1 ; сравниваем регистры
205 brne m4 ;
если rab1 не равно 2 идти к m4
206 lds temp, buf2 ; если rab1 равно 2 считываем в temp
;
buf2(двойку)
207 out PORTB, temp; и выводим её на
индикатор
208 rjmp mm ;
Переходим в конец подпрограммы
209 m4: ldi temp,3 ; записываем 3 в temp
210 cp temp,rab1 ; сравниваем регистры
211 brne m5 ;
если rab1 не равно 3 идти к m5
212 lds temp,
buf3 ; если rab1 равно 3 считываем в
temp
;
buf3(тройку)
213 out PORTB, temp; и выводим её на
индикатор
214 rjmp mm ;
Переходим в конец подпрограммы
215 m5: ldi temp,4 ; записываем 4 в temp
216 cp temp,rab1 ; сравниваем регистры
217 brne m6 ;
если rab1 не равно 4 идти к m6
218 lds temp, buf4 ; если rab1 равно 4 считываем в temp
;
buf4(четверку)
219 out PORTB, temp; и выводим её на
индикатор
220 rjmp mm ;
Переходим в конец подпрограммы
221 m6: ldi temp,5 ; записываем 5 в temp
222 cp
temp,rab1 ; сравниваем регистры
223 brne m7 ;
если rab1 не равно 5 идти к m7
224 lds temp, buf5 ; если rab1 равно 5 считываем в temp
;
buf5(пятерку)
225 out PORTB, temp; и выводим её на
индикатор
226 rjmp mm ;
Переходим в конец подпрограммы
227 m7: ldi temp,6 ; записываем 6 в temp
228 cp temp,rab1 ; сравниваем регистры
229 brne m8 ;
если rab1 не равно 6 идти к m8
230 lds temp, buf6 ; если rab1 равно 6 считываем в temp
;
buf6(шестерку)
231 out PORTB, temp; и выводим её на
индикатор
232 rjmp mm ;
Переходим в конец подпрограммы
233 m8: ldi temp,7 ; записываем 7 в temp
234 cp temp,rab1 ; сравниваем регистры
235 brne m9 ;
если rab1 не равно 7 идти к m9
236 lds temp, buf7 ; если rab1 равно 7 считываем в temp
;
buf7(семерку)
237 out PORTB, temp; и выводим её на
индикатор
238 rjmp mm ;
Переходим в конец подпрограммы
239 m9: ldi temp,8 ; записываем 8 в temp
240 cp temp,rab1 ; сравниваем регистры
241 brne m10 ;
если rab1 не равно 8 идти к m10
242 lds temp, buf8 ; если rab1 равно 8 считываем в temp
;
buf8(восьмерку)
243 out PORTB, temp; и выводим её на
индикатор
244 rjmp mm ;
Переходим в конец подпрограммы
245 m10: ldi temp,9 ; записываем 9 в temp
246 cp temp,rab1 ; сравниваем регистры
247 brne mm ;
если rab1 не равно 9 идти к mm
248 lds temp, buf9 ; если rab1 равно 9 считываем в temp
;
buf9(девятку)
249 out PORTB, temp ; и выводим её на
индикатор
250 mm: ret
;---Подпрограмма обработки прерываний
251 prtim1:
;Формирование 60-и секундной задержки перед
выводом на индикатор m и h
252 lds s, bufs ;Читаем из bufs секунды в регистр s
253 inc s ;Увеличиваем
s на 1
254 cpi s,60 ;Сравниваем s с 60
255 brne mmm1 ;Если
s не равно 60 идти к mmm1
256 ldi s,0 ;Если s равно 60, то обнуляем s
;Формируем значения reg0 и reg1 для их вывода на
индикатор
; (для
отображения минут)
257 lds reg0,bufr0 ;Читаем из bufr0 значение счетчика в reg0
258 lds reg1,bufr1 ;Читаем из bufr1 значение счетчика в reg1
259 inc reg0 ;Увеличиваем reg0 на 1
260 cpi reg0,reg10 ;Сравниваем reg0 с числом 10
261 brne mm2 ;Если
reg0 не равен 10 идти к mm2
262 ldi reg0,0 ;Если reg0 равен 10, то обнуляем его
263 inc reg1 ;Увеличиваем reg1 на единицу
264 mm2: cpi reg1,reg10 ;Сравниваем reg1 с числом 10
265 brne mm3 ;Если
reg1 не равно 10 идти к mm3
266 ldi reg1,0 ;Если reg1 равен 10, то обнуляем его
267 mm3: sts bufr0,reg0 ;Запоминаем reg0 в bufr0
268 sts bufr1,reg1 ;Запоминаем reg1 в bufr1
;Формирование минут
269 lds m, bufm ;Читаем содержимое m из bufm
270 lds h, bufh ;Читаем содержимое h из bufh
271 inc m ;Увеличиваем
m на 1
272 cpi
m,m60 ;Сравниваем m с числом 60
273 brne mm1 ;Если
m не равно 60 идти к mm1
274 ldi m,0 ;Если m равно 60 обнуляем минуты
275 ldi s,0 ;Обнуляем секунды
276 ldi reg0,0 ;Обнуляем также reg0
277 ldi reg1,0 ;и reg1
278 sts bufr0,reg0 ;Запоминаем reg0 в bufr0
279 sts bufr1,reg1 ;Запоминаем reg1 в bufr1
;Формируем значения reg2 и reg3 для их вывода на
индикатор
; (для отображения часов)
280 kk1: lds reg2,bufr2 ;Читаем из bufr2 значение счетчика в reg2
281 lds reg3,bufr3 ;Читаем из bufr3 значение счетчика в reg3
282 inc reg2 ;Увеличиваем reg2 на 1
283 cpi reg2,reg10 ;Сравниваем reg2 с числом 10
284 brne mk2 ;Если
reg2 не равно 10 идти к mk2
285 ldi reg2,0 ;Если reg2 равно 10, то обнуляем его
286 inc reg3 ;Увеличиваем reg3 на 1
287 mk2: cpi reg3,reg10 ;Сравниваем reg3 с числом 10
288 brne mk3 ;Если
reg3 не равно 10 идти к mk3
289 ldi reg3,0 ;Если reg3 равно 10, то обнуляем его
290 mk3: sts bufr2,reg2 ;Запоминаем reg2 в bufr2
291 sts bufr3,reg3 ;Запоминаем reg3 в bufr3
292 rjmp ii ;безусловный
переход на ii если s=60
293 mmm1: ;Переход
сюда, если s не равно 60
294 in temp3,PIND;Читаем с порта D
295 sbrs temp3,0 ;0-й разряд. Если он равен 0
296 rcall input ;вызываем подпрограмму ввода
;и
отображения на индикаторе минут
297 in temp3,PIND;Читаем с порта D
298 sbrs temp3,1 ;1-й разряд. Если он равен 0
299 rcall input1 ;вызываем подпрограмму ввода
;и
отображения на индикаторе часов
300 rjmp mmm2 ;Безусловный
переход для запоминания s
301 ii: inc h ;Увеличиваем h на 1
302 cpi
h,h24 ;Сравниваем h с числом 24
303 brne mm1 ;Если
h не равно 24 идти к mm1
304 ldi m,0 ;Если h равно 24 обнуляем минуты
305 ldi h,0 ;обнуляем часы
306 ldi s,0 ;обнуляем секунды
307 ldi reg0,0 ;обнуляем reg0
308 ldi reg1,0 ;обнуляем reg1
309 ldi reg2,0 ;обнуляем reg2
310 ldi reg3,0 ;обнуляем reg3
311 sts bufr0,reg0 ;и запоминаем их в bufr0
312 sts bufr1,reg1 ;в bufr1
313 sts bufr2,reg2 ;в bufr2
314 sts bufr3,reg3 ;в bufr3
315 mm1:
sts bufm,
m ; Запись минут m в bufm
316 sts bufh, h ;и запись часов h в bufh
317 mmm2:
sts bufs,
s ; Запись
секунд s в bufs
318 reti ; Завершить подпрограмму обработки
прерывания
;---Подпрограмма кнопочного ввода минут
319 input: lds reg0,bufr0 ;Читаем из bufr0 значение счетчика в reg0
320 lds reg1,bufr1 ;Читаем из bufr1 значение счетчика в reg1
321 inc reg0 ;Увеличиваем reg0 на 1
322 cpi reg0,reg10 ;Сравниваем reg0 с числом 10
323 brne mmp2 ;Если
reg0 не равнщ 10 идти к mmp2
324 ldi reg0,0 ;Если reg0 равно 10, то обнуляем его
325 inc reg1 ;Увеличиваем reg1 на 1
326 mmp2:
cpi reg1,reg10 ;Сравниваем reg1 с числом 10
327 brne mmp3 ;Если
reg1 не равно 10 идти к mmp3
328 ldi reg1,0 ;Если reg1 равно 10, то обнуляем его
329 mmp3:
sts bufr0,reg0 ;Запоминаем reg0 в bufr0
330 sts bufr1,reg1 ;Запоминаем reg1 в bufr1
;С увеличением счетчиков, которые отображаются
на индикаторе,
;увеличиваем минуты
331 lds m, bufm ;Читаем содержимое m из
bufm
332 inc m ;Увеличиваем
m на 1
333 cpi m,m60 ;Сравниваем m с числом 60
334 brne mmp1 ;Если
m не равно 60 идти к mmp1
335 ldi m,0 ;Если m равно 60 обнуляем минуты
336 ldi reg0,0 ;Обнуляем также reg0
337 ldi reg1,0 ;и reg1
338 sts bufr0,reg0 ;Запоминаем reg0 в bufr0
339 sts bufr1,reg1 ;Запоминаем reg1 в bufr1
340 mmp1:
sts bufm, m ;Записываем минуты m в bufm
341 ret ;Выход
из подпрограммы
;---Подпрограмма кнопочного ввода часов
342 input1:
343 lds reg2,bufr2 ;Читаем из bufr2 значение счетчика в reg2
344 lds reg3,bufr3 ;Читаем из bufr3 значение счетчика в reg3
345 inc reg2 ;Увеличиваем reg2 на 1
346 cpi reg2,reg10 ;Сравниваем reg2 с числом 10
347 brne mmn2 ;Если
reg2 не равно 10 идти к mmn2
348 ldi reg2,0 ;Если reg2 равно 10, то обнуляем его
349 inc reg3 ;Увеличиваем reg3 на 1
350 mmn2:
cpi reg3,reg10 ;Сравниваем reg3 с числом 10
351 brne mmn3 ;Если
reg3 не равно 10 идти к mmn3
352 ldi reg3,0 ;Если reg3 равно 10, то обнуляем его
353 mmn3:
sts bufr2,reg2 ;Запоминаем reg2 в bufr2
354 sts bufr3,reg3 ;Запоминаем reg3 в bufr3
; С увеличением счетчиков, которые отображаются
на индикаторе,
; увеличиваем часы
355 lds h, bufh ;Читаем содержимое h из bufh
356 inc h ;Увеличиваем
h на 1
357 cpi h,h24 ;Сравниваем h с числом 24
358 brne mmpn1 ;Если h не равно 24 идти к mmpn1
359 ldi h,0 ;Если h равно 24 обнуляем часы
360 ldi reg2,0 ;Обнуляем также reg2
361 ldi reg3,0 ;и reg1
362 sts bufr2,reg2 ;Запоминаем reg2 в bufr2
363 sts bufr3,reg3 ;Запоминаем reg3 в bufr3
364 mmpn1:
sts bufh, h ;Записываем часы h в bufh
365 ret ;Выход
из подпрограммы
;--- Подпрограмма задержки wait2
366 wait2: ldi loop1,
6 ; Помещаем в loop1 константу
задержки
367 wtt1: dec loop1 ; Уменьшаем значение регистра loop
368 breq wtt4 ; Если loop1=0,
идти к wtt4
369 ldi loop2, 100 ; Помещаем в loop2 константу задержки
370 wtt2: dec loop2 ; Уменьшаем значение регистра loop2
371 breq wtt1 ; Если loop1=0,
идти к wtt1
372 lds loop3,bufl3 ; Помещаем в loop3 константу задержки
373 wtt3: dec loop3 ; Уменьшаем значение регистра loop3
374 brne wtt3 ;
Если не ноль, идти к wtt3
375 rjmp wtt2 ; идти к wtt2
376 wtt4: ret ;
Выход из подпрограммы
;--- Подпрограмма задержки wait3
377 wait3: ldi loop1,
50 ; Помещаем в loop1 константу
задержки
378 wttt1: dec loop1 ; Уменьшаем значение регистра loop
379 breq wttt4 ; Если loop1=0, идти к wttt4
380 ldi loop2, 200 ; Помещаем в loop2 константу задержки
381 wttt2: dec loop2 ; Уменьшаем значение регистра loop2
382 breq wttt1 ; Если loop1=0, идти к wttt1
383 lds loop3,bufl3 ; Помещаем в loop3 константу задержки
384 wttt3: dec loop3 ; Уменьшаем значение регистра loop3
385 brne wttt3 ; Если не ноль, идти к wttt3
386 rjmp wttt2 ; идти
к wttt2
387 wttt4: ret ;
Выход из подпрограммы
;--- Подпрограмма дозвонки по номеру 0679735581
388 zvon:
; Поднять трубку
389 ldi temp,0b11111011 ;Устанавливаем 1 на PC1 для
; поднятия
трубки
390 out PORTC,temp ;Посылаем это значение на порт C
391 rcall wait3 ;Ожидаем
392 rcall wait3 ;гарантированно гудок
; Опустить трубку
393 ldi temp,0b11111001 ;Устанавливаем 0 на PC1 для
;опускания
трубки
394 out PORTC,temp ;Посылаем это значение на порт C
395 rcall wait3 ;Ожидаем
396 rcall wait3 ;гарантированно гудок
; Поднять трубку. (Повторяем для того, чтобы
исключить невозможность
; дозвона, если кто-то в момент поднятия трубки
дозванивался
; по телефону к нашему устройству)
397 ldi temp,0b11111011
398 out PORTC,temp
399 rcall wait3
400 rcall wait3
; Звоним 0. Для этого с помощью подпрограммы
zvon1 и zvonn десять раз
; размыкаем телефонную линию.
401 ldi zn,10 ;Загружаем 10 в регтстр zn
; (10
размыканий - набор 0)
402 rcall zvonn ;Звоним
403 ldi zn,6 ;Загружаем 6 в регтстр zn
; (6
размыканий - набор 6)
404 rcall zvonn ;Звоним
405 ldi zn,7 ;Аналогично для набора 7
406 rcall zvonn
407 ldi zn,9 ;Аналогично для набора 9
408 rcall zvonn
409 ldi zn,7 ;
…
410 rcall zvonn
411 ldi zn,3
412 rcall zvonn
413 ldi zn,5
414 rcall zvonn
415 ldi zn,5
416 rcall zvonn
417 ldi zn,8
418 rcall zvonn
419 ldi zn,1
420 rcall zvonn
;
Пауза
перед
опусканием
трубки (даем
возможность
телефонной
станции
;сделать несколько гудков абоненту, затем кладем
трубку)
421 ldi
temp,11 ;Загружаем 11 в регтстр temp
422 mw0: rcall wait3 ;Вызываем подпрограмму задержки
423 dec temp ;На 1 уменьшаем temp
424 brne mw0 ;Если
temp не 0, нереходим к mw0
; Опустить трубку
425 ldi temp,0b11111001
426 out PORTC,temp
427 rcall wait3
428 ret ; Выход из
подпрограммы
;--- Подпрограмма одиночного размыкания
набирателя номера
429 zvon1:
430 ldi temp,0b11111111 ;При поднятой трубке
;
устанавливаем 1 на PC2
431 out PORTC,temp ;Посылаем это значение
;для
размыкания линии
432 rcall wait2 ;Делаем выдержку примерно 50 мс в
;соответствии с характеристиками работы станции
433 ldi temp,0b11111011 ;Замыкаем
434 out PORTC,temp ;телефонную линию
435 rcall wait2 ;Делаем выдержку примерно 50 мс в
;соответствии с характеристиками работы станции
436 ret ;
Выход из подпрограммы
;--- Подпрограмма цикла, если напряжение в
осветительной сети не появилось
loopu:
437 do: clr rab2 ;Обнуление rab2
438 in
rab2,PINA ;Проверяем 4-й разряд.
439 Sbrs rab2,4 ;Если он равен 0,
440 Rjmp do ;то
бесконечный цикл.
441 ret ;Если
1, возвратиться в основную программу
;--- Подпрограмма для многократного размыкания
набирателя номера
442 zvonn:
443 mz0: rcall zvon1 ;Вызов подпрограммы одиночного
;размыкания
линии
444 dec zn ;Уменьшаем
на 1 регистр zn
445 brne mz0 ;Если
zn не 0 переходим к метке mz0
446 rcall wait3 ;По характеристикам телефонной
станции
;необходима пауза примерно 1 секунда после
набора номера
447 ret ; Выход из подпрограммы
Компиляция
программы в код микроконтроллера выполнена с помощью пакета программ AVR Studio 4. Запись программного кода в
память микроконтроллера проведена с помощью программатора PonyProg2000.
Недостатком
данного устройства является то, что номер мобильного телефона, по которому
производится дозвон, а также время дозвона не могут быть введены, например, с
клавиатуры устройства. Они вшиты в программный код, и при их изменении
необходимо делать изменения в программе, после чего заново перепрограммировать
микроконтроллер.
Литература.
1.Белов А.В. Самоучитель
разработчика устройств на микроконтроллерах AVR. – СПб.: Наука и Техника, 2008. –
544 с.: ил. + CD.
2.Основные понятия о работе
телефонных станций и абонентских устройств. – http://library.espec.ws/books/phones/CHAPTER1/1.htm