Современные информационные технологии/Компьютерная инженерия

 

Мясищев А.А.

Хмельницкий национальный университет, Украина

Вариант организации дозвона по телефонной линии с помощью микроконтроллеров 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