Радиомикрофоны
December 3

Исходник GSM «жучка» на PIC16F648A v1.0

Реверс инжиниринг демо-прошивки радиомикрофона на PIC16F648A/PIC16F628A и древнем GSM модуле SIM300DZ.

Также см. исходники GSM радиомикрофонов на других модулях: SIM800C (PIC12F1822, очень глючная), SIM900 (PIC24FJ64GA004, очень глючная).

В отличие от «Трешки», ножек контроллера хватит и для дистанционного управления по SMS, а программа кажется гораздо более вменяемой.

Исходники GSM радиомикрофона на PIC16F648A, SIM300D

Антенну GSM используйте заводускую, а не такую, как у автора, а то Ротхаммель будет вертеться в гробу, как волчок. Помните о противовесе.

Печатная плата «Трешки» является причиной страшных глюков. В этом GSM радиомикрофоне плата получше, особенно если светодиод с длинными выводами заменить бескорпусным, а микрофон применить от гарнитуры, как советует Eddy71.

Я не анализировал эту прошивку так подробно, как «Трешку», поэтому за надежность не ручаюсь. Но идея хранить номер на SIM карте и проверять по имени гарантирует отсутствие ложных срабатываний и глюков от наводок, от чего так страдает «Трешка», судя по обсуждению на VRTP.

Ни «Трешку», ни эту схему я не собирал, поэтому неприятные неожиданности возможны.

Вместо халтурных проверок ответов SIM300 по одному-двум символам нужно сделать полноценные сравнения, как с "+CMT" (см. not_a_ring).

Авторская прошивка является демонстрационной и содержит ограничения на длительность и количество звонков. Интересные места прокомментированы.

Если вдруг окажется, что микропрограмма качественная, я советую связаться с автором и купить полную версию с управлением по SMS.

Комментарии автора:

Полная прошивка распространяется уже прошитая в микроконтроллер – спрашивайте у автора.
Если у Вас нету опыта и Вы собрали программатор самостоятельно, то не рискуйте, прошивая внутрисхемно. Вы можете потерять сотовый модуль.
Устройство отвечает только хозяину. Чтобы прописать его номер в международном формате (+7905……….) Вам надо записать на сим-карту его номер под имеем Ph1. Обязательно отмените ввод пин-кода. Программирование осуществляется с помощью мобильника. Будьте внимательны – некоторые телефоны дописывают индексы к имени, это приведет к сбою работы. Например, так делают Sony Ericson.
За полной прошивкой обращайтесь к автору по ICQ: 288449055 или пишите на мыло device@open.by. Автор принимает заказы на разработку устройств с применением контроллеров, GSM и GPS технологий.

Оригинальная прошивка без исходников (говносайт «Паяльник» удалил все мои комментарии):

https://web.archive.org/web/20240512090900/https://cxem.net/radiomic/radiomic123.php

Страница с обсуждением на форуме cxem net:

https://web.archive.org/web/20251203165751/https://forum.cxem.net/topic/50702-%D0%BF%D1%80%D0%BE%D1%81%D1%82%D0%BE%D0%B9-gsm-%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D1%84%D0%BE%D0%BD-%D0%BD%D0%B0-sim300d/

Руководство по работе с GSM/GPRS модемом SIM300 на русском языке:

https://www.macrogroup.ru/content/data/store/images/f_158_213_1.pdf

Правильная работа с UART от Microchip (AN774):

https://ww1.microchip.com/downloads/en/appnotes/00774a.pdf

https://github.com/trygvis/pic16/blob/master/application-notes/an774-Asynchronous%20Communications%20with%20the%20PICmicro%20USART/Appendix%20A%20for%20PIC16/p16_tiri.asm

Блок-схема авторского обработчика прерывания

Довольно сильно отличается от рекомендованного Microchip:

Блок-схема примененного в прошивке алгоритма работы с SIM300

Красный — ошибки.

Оранжевый — опрос кнопки и сенсора зарядки.

Желтый — ограничения демонстрационной версии.

Зеленый — переход в спящий режим.

Синий — отправка AT-команд модулю SIM300.

Темно-синий — управление кнопкной включения SIM300.

Фиолетовый — анализ ответов GSM модуля.

Блок-схема алгоритма применения GSM модуля SIM300 в качестве радиомикрофона на PIC16F648A

Исходный код прошивки

        processor p16f648a
        radix dec

        include p16f648a.inc

; The recognition of labels and registers is not always good, therefore
; be treated cautiously the results.

        CONFIG  WDTE  = ON
        CONFIG  PWRTE = OFF
        CONFIG  FOSC  = INTOSCIO
        CONFIG  MCLRE = OFF
        CONFIG  BOREN = OFF
        CONFIG  LVP   = OFF
        CONFIG  CPD   = OFF
        CONFIG  CP    = ON

#define MAX_CALLS 10
#define MAX_TIME 114
#define BUFSZ 49
#define TRUE 1
#define FALSE 0
#define BAUD 9600
#define F_OSC 4000000

;===============================================================================
; DATA address definitions

#define EEPROM_CALLS_COUNTER 0x64

STATUS_TEMP     equ     0x21
FSR_TEMP        equ     0x22
PCLATH_TEMP     equ     0x28
bufptr          equ     0x29
buffer          equ     0x2a
after_buffer    equ     0x5b                                ; first byte after buffer
state           equ     0x5c                                ; finite state machine
#define STATE_OFF 0
#define STATE_READY 1
#define STATE_RESET 3

calls_counter   equ     0x5d
time_counter    equ     0x5e

flags           equ     0x5f
#define FLAG_CALL 0

commaptr        equ     0x63                                ; позиция ',' в буфере с СМС
regcnt          equ     0x63                                ; network registration
a               equ     0x63
i               equ     0x63

slotptr         equ     0x64                                ; sms slot offset
c               equ     0x64
blink_arg       equ     0x64
quotes          equ     0x64
namepos         equ     0x64

sms_slot        equ     0x65                                ; sms slot value
d               equ     0x65

dtr_arg         equ     0x66
tmp4            equ     0x66
cmgd_arg1       equ     0x66

delay_arg       equ     0x67
cmgd_arg2       equ     0x67

itoabuf0        equ     0x68
itoabuf1        equ     0x69
itoabuf2        equ     0x6a
itoabuf3        equ     0x6b

arg1            equ     0x6c
arg2            equ     0x6d
j               equ     0x6e

Common_RAM      equ     0x0070                              ; size: 16 bytes
k               equ     (Common_RAM + 7)
INTCON_TEMP     equ     (Common_RAM + 7)
result          equ     (Common_RAM + 8)
button_state    equ     (Common_RAM + 8)
clipptr         equ     (Common_RAM + 8)
highbanks       equ     (Common_RAM + 10)


;===============================================================================
; PINS usage definitions

LED             equ     RA1

PWRKEY          equ     RB0
PIN_DTR         equ     RB3
CHARGER         equ     RB4
BUTTON          equ     RB5


;===============================================================================
; Macroses

Bank0   MACRO
        bcf     STATUS, RP0
        ENDM

Bank1   MACRO
        bsf     STATUS, RP0
        ENDM

BSF1    MACRO   file, bit       ; установить бит регистра из банка 1
        Bank1
        bsf     (file), (bit)
        ENDM

BCF1    MACRO   file, bit       ; сбросить бит регистра из банка 1
        Bank1
        bcf     (file), (bit)
        ENDM

SETPC   MACRO                   ; для отправки AT команды
        bcf     PCLATH, 0
        bcf     PCLATH, 1
        bcf     PCLATH, 2
        addwf   PCL, F
        ENDM

MOVLF   MACRO   value, file
        movlw   (value)
        movwf   (file)
        ENDM

MOVLF0  MACRO   value, file
        movlw   (value)
        Bank0
        movwf   (file)
        ENDM

MOVLF1  MACRO   value, file
        movlw   (value)
        Bank1
        movwf   (file)
        ENDM

MOVFF   MACRO   src, dst
        movf    (src), W
        movwf   (dst)
        ENDM

IFG     MACRO   var, n, label   ; если больше
        movf    (var), W
        sublw   (n)
        btfss   STATUS, C
        goto    (label)
        ENDM

IFL     MACRO   var, n, label   ; если меньше
        movf    (var), W
        sublw   (n)
        btfsc   STATUS, C
        goto    (label)
        ENDM

IFNE    MACRO   var, n, label   ; если не равно
        movf    (var), W
        sublw   (n)
        btfss   STATUS, Z
        goto    (label)
        ENDM

IFEQ    MACRO   var, n, label   ; если равно
        movf    (var), W
        sublw   (n)
        btfsc   STATUS, Z
        goto    (label)
        ENDM

DTR0   MACRO                   ; сбросить DTR
        bcf     PORTB, PIN_DTR
        BCF1    TRISB, PIN_DTR
        ENDM

DTRP    MACRO                   ; дернуть DTR
        bsf     PORTB, PIN_DTR
        BCF1    TRISB, PIN_DTR
        ENDM

DELAY   MACRO   n               ; задержка
        MOVLF0  (n), delay_arg
        call    function_delay
        ENDM

LDELAY  MACRO   n, file         ; длинная задержка
        MOVLF   (n), (file)
        MOVLF   250, delay_arg
        call    function_delay
        decfsz  (file), F
        goto    $-4
        ENDM

BLINK   MACRO   n               ; мигание светодиодом
        MOVLF   (n), blink_arg  ; Bank0 уже выбран
        call    function_blink
        ENDM

BLINKP  MACRO   n               ; мигание светодиодом
        MOVLF0  (n), blink_arg  ; Bank0
        call    function_blink
        ENDM

SEND    MACRO   char            ; отправить символ
        movlw   (char)
        btfss   PIR1, TXIF
        goto    $-1
        movwf   TXREG
        ENDM

SENDF   MACRO   file            ; отправить "файл"
        movf    (file), W
        btfss   PIR1, TXIF
        goto    $-1
        movwf   TXREG
        ENDM

TXSTR   MACRO   m, proc, n      ; отправить строку
        LOCAL   next_char
        clrf    (m)
next_char:
        movf    (m), W
        call    (proc)
        incf    (m), F
        movwf   (Common_RAM + 7)
        SENDF   (Common_RAM + 7)
        movlw   (n)
        subwf   (m), W
        btfss   STATUS, Z
        goto    next_char
        ENDM

; отправить AT-команду
ATCMDB  MACRO   tmp, proc, length, delay
        ; очистить буфер до отправки
        call    function_clear_buffer
        TXSTR   (tmp), (proc), (length)
        LDELAY  (delay), (tmp)
        ENDM

ATCMDA  MACRO   tmp, proc, length, delay
        TXSTR   (tmp), (proc), (length)
        ; очистить буфер после
        call    function_clear_buffer
        LDELAY  (delay), (tmp)
        ENDM

;===============================================================================
; CODE area

        ; code

        org     __CODE_START

vector_reset:

        MOVLF   0, PCLATH       ; select program memory page 0
        goto    reset_vector
        nop

vector_int:                     ; обработчик прерываний

        movwf   (Common_RAM + 15)
        swapf   STATUS, W
        clrf    STATUS
        movwf   STATUS_TEMP
        MOVFF   (Common_RAM + 15), 0x20
        MOVFF   PCLATH, PCLATH_TEMP
        clrf    PCLATH
        swapf   0x20, F
        MOVFF   FSR, FSR_TEMP
        MOVFF   (Common_RAM + 7), 0x23
        MOVFF   (Common_RAM + 8), 0x24
        MOVFF   (Common_RAM + 9), 0x25
        MOVFF   (Common_RAM + 10), 0x26
        MOVFF   (Common_RAM + 11), 0x27

        bcf     STATUS, IRP     ; 0 = Bank 0, 1 (00h - FFh)
        Bank0
        MOVLF   PIE1, FSR       ; IRP:FSR<7> = 01 = Bank 1

        btfss   INDF, RCIE      ; 1 = Enables the USART receive interrupt
        goto    check_timer

        btfsc   PIR1, RCIF      ; test RCIF receive interrupt
        goto    byte_arrived

check_timer:
        MOVLF   PIE1, FSR
        btfss   INDF, TMR1IE    ; TMR1 Overflow Interrupt Enable bit
        goto    restore
        btfsc   PIR1, TMR1IF    ; TMR1 Overflow Interrupt Flag bit
        goto    timer_interrupt

restore:                        ; выход из обработчика прерывания
        MOVFF   FSR_TEMP, FSR
        MOVFF   0x23, (Common_RAM + 7)
        MOVFF   0x24, (Common_RAM + 8)
        MOVFF   0x25, (Common_RAM + 9)
        MOVFF   0x26, (Common_RAM + 10)
        MOVFF   0x27, (Common_RAM + 11)
        MOVFF   PCLATH_TEMP, PCLATH
        swapf   STATUS_TEMP, W
        movwf   STATUS
        swapf   (Common_RAM + 15), F
        swapf   (Common_RAM + 15), W
        retfie

byte_arrived:
        bcf     PCLATH, 3
        goto    byte_arrived2

timer_interrupt:
        bcf     PCLATH, 3
        goto    timer_interrupt2

function_ATE0:
        SETPC
        dt      "ATE0\r", 0

function_ATCREG:        ; registration status
        SETPC
        dt      "AT+CREG?\r", 0

function_ATCMGF:        ; SMS text mode
        SETPC
        dt      "AT+CMGF=1\r", 0

function_ATCMGD:        ; delete SMS
        SETPC
        dt      "AT+CMGD=%d\r", 0

function_ATCHFA:        ; set the audio channel to Half-Duplex
        SETPC
        dt      "AT+CHFA=1\r", 0

function_ATCMIC:
        SETPC
        dt      "AT+CMIC=1,15\r", 0

function_ATCLIP:
        SETPC
        dt      "AT+CLIP=1\r", 0

function_ATCSCLK:
        ; enable the Serial Command Mode for SMS message waiting indications (SMS-CB)
        ; This command informs the module to send SMS-CB (Cell Broadcast) messages to the connected terminal.
        SETPC
        dt      "AT+CSCLK=1\r", 0

function_ATA:
        SETPC
        dt      "ATA\r", 0

function_ATH:
        SETPC
        dt      "ATH\r", 0

function_ATCMGDC:       ; delete SMS
        SETPC
        dt      "AT+CMGD=%c\r", 0

function_ATCBC:         ; report the battery charge status of the module
        SETPC
        dt      "AT+CBC\r", 0

byte_arrived2:
        ; принятый ответ на AT-команду сохраняется в буфере:
        ; buffer[bufptr++] = RCREG;
        IFG     bufptr, BUFSZ, buffer_full
        movf    bufptr, W
        incf    bufptr, F
        addlw   buffer
        movwf   FSR

        ; Register Bank Select bit (used for indirect addressing)
        ; 0 = Bank 0, 1 (00h - FFh)
        bcf     STATUS, IRP

        ; источник зависаний
        ; правильный алгоритм работы с USART от Microchip см. в p16_tiri.asm
        btfss   PIR1, RCIF
        goto    $-1

        MOVFF   RCREG, INDF
        goto    the_end

buffer_full:
        ; источник зависаний
        btfss   PIR1, RCIF
        goto    $-1

        ; правильное поведение: при переполнении буфера лишние символы игнорируются
        movf    RCREG, W

the_end:
        ; ошибка, см. стр. 81 даташита
        ; Flag bit RCIF is a read-only bit, which is cleared by the hardware.
        bcf     PIR1, RCIF

        bcf     PCLATH, 3
        goto    restore

timer_interrupt2:
        btfsc   flags, FLAG_CALL
        incf    time_counter, F
        ; 1 = TMR1 register overflowed (must be cleared in software)
        bcf     PIR1, TMR1IF
        bcf     PCLATH, 3
        goto    restore

function_delay:

        MOVLF   delay_arg, FSR
        bcf     STATUS, IRP
        movf    INDF, W
        btfsc   STATUS, Z
        goto    label_015
label_011:
        MOVLF   1, (Common_RAM + 8)
label_012:
        MOVLF   191, (Common_RAM + 7)
        clrwdt
        decfsz  (Common_RAM + 7), F
        goto    $-2
        decfsz  (Common_RAM + 8), F
        goto    label_012
        MOVLF   74, (Common_RAM + 7)
        decfsz  (Common_RAM + 7), F
        goto    $-1
        nop
        clrwdt
        decfsz  INDF, F
        goto    label_011
label_015:
        retlw   0x00

function_blink:

        movf    blink_arg, F
        btfsc   STATUS, Z
        goto    label_016
        bcf     PORTA, LED
        BCF1    TRISA, LED
        DELAY   250
        BSF1    TRISA, LED
        DELAY   250
        decf    blink_arg, F
        goto    function_blink
label_016:
        retlw   0

; 1 - DTR pulse, 0 - DTR low
function_DTR:
        movf    dtr_arg, F
        btfss   STATUS, Z
        goto    label_017
        DTR0
        DELAY   50
        goto    label_018
label_017:
        DTRP
        Bank0
label_018:
        retlw   0

function_clear_buffer:

        clrf    bufptr
label_019:
        IFG     bufptr, BUFSZ, label_020
        movlw   buffer
        addwf   bufptr, W
        movwf   FSR
        bcf     STATUS, IRP
        clrf    INDF
        incf    bufptr, F
        goto    label_019
label_020:
        clrf    bufptr
        retlw   0

start:
        ; To allow the bit rate to be synchronized simply issue an "AT" or "at" string.
        ; This is necessary when you start up the module while autobauding is enabled
        call    function_clear_buffer
        SEND    'A'
        SEND    'T'
        SEND    '\r'
        call    function_clear_buffer

        LDELAY  2, a

        ; кривая проверка на "OK"
        IFEQ    buffer,     'A', have_ok
        IFEQ    buffer + 2, 'O', have_ok

        MOVLF   FALSE, result
        goto    have_result
        ; unreachable code
        goto    have_result

have_ok:
        MOVLF   TRUE, result
        goto    have_result

have_result:
        bcf     PCLATH, 3
        goto    check_result

check_charger:
        BSF1    TRISB, CHARGER
        Bank0

        ; зарядка подключена?
        btfss   PORTB, CHARGER
        goto    no_charger

        movf    state, F
        btfss   STATUS, Z
        goto    check_battery

        ; передаем несколько раз "AT\r"
        clrf    a
send_at:
        IFG     a, 2, check_battery
        SEND    'A'
        SEND    'T'
        SEND    '\r'
        LDELAY  2, c
        incf    a, F
        goto    send_at

check_battery:
        ATCMDB   c, function_ATCBC, 7, 4

        ; +CBC: <battery connected status>, <battery charging_loop level>, <voltage>

        IFNE    buffer + 15, '1', dont_blink
        BLINK   1
dont_blink:

        IFNE    buffer + 15, '2', charger_disconnected

charging_loop:
        ; зацикливаемся на время зарядки
        BSF1    TRISB, CHARGER
        Bank0
        btfss   PORTB, CHARGER
        goto    charger_disconnected
        ; Для зарядки аккумулятора надо выключать устройство, подключить через
        ; шнур mini USB с соответствующему порту компьютера и дождаться
        ; постоянного горения светодиода.
        bcf     PORTA, LED
        BCF1    TRISA, LED
        DELAY   100
        goto    charging_loop

charger_disconnected:
        goto    charger_disconnected2

no_charger:
        BSF1    TRISA, LED
        Bank0

charger_disconnected2:
        bcf     PCLATH, 3
        goto    check_button

; Нажмите на кнопку и ждите короткой вспышки светодиода.
; Это означает, что контроллер обратил внимание на кнопку.
function_button:

        BSF1    TRISB, BUTTON
        Bank0
        btfsc   PORTB, BUTTON
        goto    label_048

        bcf     PORTA, LED
        BCF1    TRISA, LED
        DELAY   50
        BSF1    TRISA, LED
        DELAY   50
        BSF1    TRISB, BUTTON
        Bank0
        btfsc   PORTB, BUTTON
        goto    label_046

label_043:
        BSF1    TRISB, BUTTON
        Bank0
        btfsc   PORTB, BUTTON
        goto    label_045
        LDELAY  2, a
        goto    label_043

label_045:
        MOVLF   TRUE, button_state
        goto    exit_button
        goto    label_047

label_046:
        MOVLF   FALSE, button_state
        goto    exit_button

label_047:
        goto    exit_button

label_048:
        MOVLF   FALSE, button_state
        goto    exit_button

exit_button:
        retlw   0

function_SIM300D_power:

        bcf     PORTB, PWRKEY
        BCF1    TRISB, PWRKEY
        Bank0
        ; пауза
        clrf    c
label_050:
        IFG     c, 7, label_052
        LDELAY  2, d
        clrwdt
        incf    c, F
        goto    label_050
label_052:
        BSF1    TRISB, PWRKEY
        Bank0
        retlw   0x00

power_on_continue:
        clrf    a
        call    function_clear_buffer
        clrf    a

label_054:
        ; кривая проверка на "OK"
        IFEQ    buffer,     'A', label_060
        IFEQ    buffer + 2, 'O', label_060
        IFNE    a, 7, label_055
        call    function_SIM300D_power
        clrf    a

label_055:
        call    function_clear_buffer
        SEND    'A'
        SEND    'T'
        SEND    '\r'
        call    function_clear_buffer
        LDELAY  2, c
        incf    a, F
        goto    label_054

label_060:
        call    function_clear_buffer
        ATCMDA  c, function_ATE0, 5, 2
        clrf    regcnt

network_registration_loop:
        ; регистрация в сети
        IFEQ    buffer + 11, '1', registered
        IFNE    regcnt, 30, label_atcreg
        call    function_SIM300D_power
        clrf    regcnt
        goto    label_054

label_atcreg:
        incf    regcnt, F
        ATCMDA  c, function_ATCREG, 9, 2
        goto    network_registration_loop

registered:
        bcf     PCLATH, 3
        goto    after_registration

function_018:

        movf    arg2, W
        clrf    (Common_RAM + 8)
        subwf   arg1, W
        btfsc   STATUS, C
        goto    label_070
        MOVFF   arg1, (Common_RAM + 7)
        goto    label_072

label_070:
        clrf    (Common_RAM + 7)
        MOVLF   8, j

label_071:
        rlf     arg1, F
        rlf     (Common_RAM + 7), F
        movf    arg2, W
        subwf   (Common_RAM + 7), W
        btfsc   STATUS, C
        movwf   (Common_RAM + 7)
        rlf     (Common_RAM + 8), F
        decfsz  j, F
        goto    label_071

label_072:
        retlw   0

itoa:
        ; преобразование числа в строку
        movlw   ' '
        btfss   cmgd_arg2, 4
        MOVLF   '0', itoabuf0
        MOVFF   cmgd_arg1, (Common_RAM + 7)
        btfss   cmgd_arg1, 7
        goto    label_074
        comf    (Common_RAM + 7), F
        incf    (Common_RAM + 7), F
        MOVFF   (Common_RAM + 7), cmgd_arg1
        MOVLF   '-', itoabuf0
        bsf     cmgd_arg2, 7

label_074:
        MOVFF   cmgd_arg1, arg1
        MOVLF   100, arg2
        call    function_018
        MOVFF   (Common_RAM + 7), cmgd_arg1
        movlw   '0'
        addwf   (Common_RAM + 8), W
        movwf   itoabuf1

        MOVFF   cmgd_arg1, arg1
        MOVLF   10, arg2
        call    function_018
        movlw   '0'
        addwf   (Common_RAM + 7), W
        movwf   itoabuf3
        movlw   '0'
        addwf   (Common_RAM + 8), W
        movwf   itoabuf2

        MOVFF   itoabuf0, (Common_RAM + 7)
        btfss   cmgd_arg2, 0x3
        goto    $+3
        btfss   cmgd_arg2, 0x7
        bcf     cmgd_arg2, 0x2

        btfsc   cmgd_arg2, 0x4
        goto    label_076
        btfss   cmgd_arg2, 0x7
        goto    label_078
        btfsc   cmgd_arg2, 0x2
        goto    label_078
        MOVFF   (Common_RAM + 7), itoabuf1
        btfsc   cmgd_arg2, 0x1
        goto    label_078
        MOVFF   (Common_RAM + 7), itoabuf2
        goto    label_078

label_076:
        movlw   '0'
        subwf   itoabuf1, W
        btfss   STATUS, Z
        goto    label_078
        MOVFF   (Common_RAM + 7), itoabuf1
        MOVLF   ' ', itoabuf0
        btfss   cmgd_arg2, 0x3
        goto    label_077
        bcf     cmgd_arg2, 0x2
        bsf     cmgd_arg2, 0x1
        btfss   cmgd_arg2, 0x7
        bcf     cmgd_arg2, 0x1

label_077:
        movlw   '0'
        subwf   itoabuf2, W
        btfss   STATUS, Z
        goto    label_078
        MOVFF   (Common_RAM + 7), itoabuf2
        MOVLF   ' ', itoabuf1
        btfss   cmgd_arg2, 0x3
        goto    label_077
        bcf     cmgd_arg2, 0x1
        btfss   cmgd_arg2, 0x7
        bcf     cmgd_arg2, 0x0

label_078:
        btfss   cmgd_arg2, 0x2
        goto    label_080
        SENDF   itoabuf0

label_080:
        btfss   cmgd_arg2, 0x1
        goto    label_082
        SENDF   itoabuf1

label_082:
        btfss   cmgd_arg2, 0x0
        goto    label_084
        SENDF   itoabuf2

label_084:
        SENDF   itoabuf3
        bcf     PCLATH, 3
        goto    return_from_itoa

remove_all_sms:
        ATCMDB   d, function_ATCMGF, 10, 2
        MOVLF   1, i
delete_next:
        IFG     i, 19, delete_done
        call    function_clear_buffer
        TXSTR   d, function_ATCMGD, 8
        MOVFF   i, cmgd_arg1
        MOVLF   31, cmgd_arg2
        goto    itoa
return_from_itoa:
        SEND    '\r'
        LDELAY  2, d
        incf    i, F
        goto    delete_next

delete_done:
        ATCMDB   d, function_ATCHFA, 10, 2
        ATCMDB   d, function_ATCMIC, 13, 2
        ATCMDB   d, function_ATCLIP, 10, 2
        ATCMDB   d, function_ATCSCLK, 11, 2

        bcf     PCLATH, 3
        goto    ready

ringing:
        clrf    quotes
        clrf    i

parse_call_info:
        ; +CLIP: "number", "type", "alphaId"
        IFEQ    quotes, 5, parse_call_done
        movlw   buffer
        addwf   i, W
        movwf   FSR
        bcf     STATUS, IRP
        movf    INDF, W
        ; подсчет количества кавычек
        sublw   '\"'
        btfsc   STATUS, Z
        incf    quotes, F
        incf    i, F
        goto    parse_call_info
        ; выход за пределы буфера не проверяется!

parse_call_done:
        MOVFF   i, namepos
        clrf    i

        ; memmove(buffer, buffer + namepos, BUFSZ + 1 - namepos)
movename:
        ; end of buffer?
        movf    namepos, W
        ; W = BUFSZ + 1 - namepos
        sublw   BUFSZ + 1
        ; W = i - (BUFSZ + 1 - namepos)
        subwf   i, W
        btfsc   STATUS, C
        goto    check_callee

        ; clipptr = &buffer[i]
        movlw   buffer
        addwf   i, W
        movwf   clipptr

        ; select Bank 2, 3 if clipptr > 0xff?
        clrf    highbanks
        btfsc   STATUS, C
        incf    highbanks, F

        ; FSR = &buffer[namepos + i]
        movf    namepos, W
        addwf   i, W
        addlw   buffer
        movwf   FSR

        ; itoabuf0 = buffer[namepos + i]
        bcf     STATUS, IRP
        MOVFF   INDF, itoabuf0

        ; FSR = clipptr = buffer + i
        MOVFF   clipptr, FSR
        ; 1 = Bank 2, 3 (100h - 1FFh)
        bcf     STATUS, IRP
        btfsc   highbanks, 0
        bsf     STATUS, IRP

        ; buffer[i] = buffer[i + namepos]
        MOVFF   itoabuf0, INDF

        incf    i, F
        goto    movename

check_callee:
        clrf    c

        ; проверка имени контакта на SIM карте (Ph1)
        IFNE    buffer, 'P', label_ATH
        IFNE    buffer + 1, 'h', label_ATH
        IFNE    buffer + 2, '1', label_ATH

        ; очистить счетчик времени соединения
        clrf    time_counter

        ; принять звонок
        ATCMDB   d, function_ATA, 4, 2

        ; активен звонок
        bsf     flags, FLAG_CALL

        ; чтение счетчика удачных соединений из EEPROM
        MOVLF1  EEPROM_CALLS_COUNTER, EEADR

        bcf     EECON1, 7       ; Unimplemented
        bsf     EECON1, RD
        movf    EEDATA, W
        Bank0
        ; увеличение на единицу
        movwf   calls_counter
        incf    calls_counter, F
        ; запись нового значения
        MOVLF1  EEPROM_CALLS_COUNTER, EEADR
        Bank0
        movf    calls_counter, W
        Bank1
        movwf   EEDATA
        bsf     EECON1, WREN
        Bank0
        MOVFF   INTCON, INTCON_TEMP
        bcf     INTCON, GIE
        Bank1
        ; Flash programming unlock sequence
        MOVLF   0x55, EECON2
        MOVLF   0xaa, EECON2
        bsf     EECON1, WR
        btfsc   EECON1, WR
        goto    $-1
        bcf     EECON1, WREN

        movf    INTCON_TEMP, W
        Bank0
        iorwf   INTCON, F
        goto    label_121

label_ATH:
        TXSTR   d, function_ATH, 4

label_121:
        LDELAY  2, d
        bcf     PCLATH, 3
        goto    not_a_ring

sms_received:
        ; пришло СМС
        clrf    dtr_arg
        call    function_DTR
        clrf    commaptr
find_comma:
        movlw   buffer
        addwf   commaptr, W
        movwf   FSR
        bcf     STATUS, IRP
        IFEQ    INDF, ',', comma_found
        incf    commaptr, F
        goto    find_comma

comma_found:
        ; пропустить запятую
        movlw   1
        addwf   commaptr, W
        ; номер слота СМС после запятой
        movwf   slotptr
        movlw   buffer
        addwf   slotptr, W
        movwf   FSR
        bcf     STATUS, IRP

        MOVFF   INDF, sms_slot

        ; Команды отсылаются с телефона хозяина, все “чужие” смс просто удаляются.

        ; В демонстрационной версии отсутствует код чтения СМС и выполнения команды.
        ; Надеюсь, в полной версии номер отправителя проверяется?

        ; ...


        call    function_clear_buffer

        ; удаляем СМС
        TXSTR   tmp4, function_ATCMGDC, 8
        SENDF   sms_slot
        SEND    '\r'
        LDELAY  2, 102
        MOVLF   1, dtr_arg
        call    function_DTR
        bcf     PCLATH, 3
        goto    not_a_sms

reset_vector:

        clrf    FSR

        ; очистить IRP, RP1, RP0 - Bank0
        bcf     STATUS, IRP
        movlw   ~((1 << IRP) | (1 << RP1) | (1 << RP0))
        andwf   STATUS, F

        ; INTOSC oscillator frequency: 1 = 4 MHz typical
        BSF1    PCON, OSCF
        ; Bank1

        ; Baud Rate Generator Register (BRGH = 1):
        MOVLF   (F_OSC / BAUD / 16 - 1), SPBRG

        ; CSRC: Clock Source Select bit
        ; Synchronous mode: 1 = Master mode (Clock generated internally from BRG)
        ; TXEN: Transmit Enable bit
        ; BRGH: High Baud Rate Select bit
        ; TRMT: Transmit Shift Register STATUS bit: 1 = TSR empty
        MOVLF   (1 << CSRC) | (1 << TXEN) | (1 << BRGH) | (1 << TRMT), TXSTA

        ; SPEN: Serial Port Enable bit
        ; CREN: Continuous Receive Enable bit
        MOVLF0  (1 << SPEN) | (1 << CREN), RCSTA
        ; Bank0

        ; Comparators Off
        MOVLF   (1 << CM2) | (1 << CM1) | (1 << CM0), CMCON

        clrf    bufptr
        MOVLF   STATE_RESET, state
        bcf     flags, FLAG_CALL

        ; T0CS: TMR0 Clock Source Select bit
        ; T0SE: TMR0 Source Edge Select bit
        ; PSA: Prescaler Assignment bit: 1 = Prescaler is assigned to the WDT
        ; PS2:PS0: Prescaler Rate Select bits
        ; TMR0 Rate 1:256 WDT Rate 1:128
        Bank1
        movf    OPTION_REG, W
        andlw   ~((1<<T0CS)|(1<<T0SE)|(1<<PSA)|(1<<PS2)|(1<<PS1)|(1<<PS0))
        movwf   OPTION_REG

        ; см. 6.3.1 SWITCHING PRESCALER ASSIGNMENT на стр. 39 даташита
        MOVLF   (1<<PSA)|(1<<PS2)|(1<<PS1)|(1<<PS0), (Common_RAM + 7)

        movlw   7
        Bank0
        clrf    TMR0

        MOVLF   OPTION_REG, FSR
        bcf     STATUS, IRP
        movf    INDF, W
        andlw   ~((1 << PSA) | (1 << PS2) | (1 << PS1) | (1 << PS0))
        iorlw   (1 << PS2) | (1 << PS1) | (1 << PS0)
        movwf   INDF

        clrwdt

        movf    INDF, W
        andlw   ~(1 << PSA)
        btfsc   (Common_RAM + 7), (1 << PS1) | (1 << PS0)
        andlw   ~((1 << PSA) | (1 << PS2) | (1 << PS1) | (1 << PS0))
        iorwf   (Common_RAM + 7), W
        movwf   INDF

        MOVLF   0x80|(1<<T1CKPS1)|(1<<T1CKPS0)|(1<<NOT_T1SYNC)|(1<<TMR1ON), T1CON
        MOVLF   0, (Common_RAM + 8)
        movwf   T2CON

        ; Timer2 Period Register
        MOVLF1  0, PR2

        ; ?
        ; Comparators Off
        MOVLF0  (1 << CM2) | (1 << CM1) | (1 << CM0), CMCON

        ; ?
        Bank1
        movf    PORTA, W

        clrwdt
        MOVLF   2, k
short_delay:
        decfsz  k, F
        goto    short_delay
        goto    $+1

        ; ?
        Bank0
        movf    CMCON, W

        ; Clear pending interrupts
        ; CMIF: Comparator Interrupt Flag bit: 0 = Comparator output has not changed
        bcf     PIR1, CMIF

        Bank1
        clrf    CMCON

        ; разрешить прерывания от таймера и последовательного порта
        bsf     PIE1, TMR1IE
        bsf     PIE1, RCIE

        ; GIE: Global Interrupt Enable bit
        ; PEIE: Peripheral Interrupt Enable bit
        movlw   (1 << GIE) | (1 << PEIE)
        Bank0
        iorwf   INTCON, F

        ; OSCF: INTOSC oscillator frequency: 1 = 4 MHz typical
        BSF1    PCON, OSCF

        bsf     PORTA, LED
        bsf     PORTB, CHARGER

        MOVLF   EEPROM_CALLS_COUNTER, EEADR
        bcf     EECON1, 7       ; Unimplemented
        bsf     EECON1, RD
        IFNE    EEDATA, 0xff, check_calls_counter

        ; инициализация счетчика удачных соединений (демо-прошивка)
        MOVLF   EEPROM_CALLS_COUNTER, EEADR
        clrf    EEDATA
        bsf     EECON1, WREN
        Bank0
        MOVFF   INTCON, INTCON_TEMP
        bcf     INTCON, GIE
        Bank1
        ; Flash programming unlock sequence
        MOVLF   0x55, EECON2
        MOVLF   0xaa, EECON2
        bsf     EECON1, WR
        btfsc   EECON1, WR
        goto    $-1
        bcf     EECON1, WREN
        movf    INTCON_TEMP, W
        Bank0
        iorwf   INTCON, F
        Bank1

check_calls_counter:
        ; проверка счетчика звонков
        MOVLF   EEPROM_CALLS_COUNTER, EEADR
        bcf     EECON1, 7       ; Unimplemented
        bsf     EECON1, RD
        ; достигли максимального количества звонков для свободной версии?
        IFNE    EEDATA, MAX_CALLS, have_free_calls
        ; достигли - зацикливаемся
        BLINKP  5
        LDELAY  6, a
        Bank1
        goto    check_calls_counter

have_free_calls:
        ; еще не достигли
        bcf     OPTION_REG, NOT_RBPU    ; PORTB Pull-up Enable bit

        Bank0
        clrf    dtr_arg
        call    function_DTR

label_138:
        movf    state, W
        sublw   STATE_RESET
        btfss   STATUS, Z
        goto    bad_result
        goto    start

check_result:
        movf    result, F
        btfss   STATUS, Z
        goto    good_result
        clrf    state
        goto    bad_result

good_result:
        MOVLF   STATE_READY, state

bad_result:
        BSF1    OPTION_REG, NOT_RBPU    ; PORTB Pull-up Enable bit
        Bank0

        goto    check_charger

check_button:
        BCF1    OPTION_REG, NOT_RBPU    ; PORTB Pull-up Enable bit
        Bank0

        movf    state, F
        btfss   STATUS, Z
        goto    label_147
        ; state == STATE_OFF

        call    function_button
        movf    button_state, F
        btfss   STATUS, Z
        goto    power_on

        sleep
        goto    go_sleep2

power_on:
        ; Затем после того как вы отпустите он моргнет один раз – это означает
        ; что начался процесс включения модуля.
        DTR0
        BLINKP  1
        goto    power_on_continue

after_registration:
        ; Затем светодиод моргнет два раза – это означает что модуль
        ; настроен и зарегистрировался в сети GSM.
        BLINK   2
        goto    remove_all_sms

ready:
        ; После того как светодиод моргнет три раза – устройство готово к работе.
        ; Устройство перейдет в режим сна и будет ждать входящего звонка.
        BLINK   3
        DTRP
        MOVLF0  STATE_READY, state

go_sleep2:
        goto    go_sleep

label_147:
        call    function_button
        movf    (Common_RAM + 8), F
        btfss   STATUS, Z
        goto    power_off

        call    function_clear_buffer
        LDELAY  2, a

        ; "RING"
        IFNE    buffer + 2, 'R', not_a_ring
        IFEQ    buffer + 3, 'I', ringing

not_a_ring:
        ; пришло SMS
        ; <CR><LF>+CMTI: <mem>,<n><CR><LF>
        ; value of mem is the storage location where the sms was stored.
        ; Usually its value is SM, which stands for SIM memory.
        ; the value of n is the sms slot on which the incoming message was stored
        IFNE    buffer + 2, '+', not_a_sms
        IFNE    buffer + 3, 'C', not_a_sms
        IFNE    buffer + 4, 'M', not_a_sms
        IFEQ    buffer + 5, 'T', sms_received

not_a_sms:
        btfss   flags, FLAG_CALL
        goto    check_calls_counter2

        ; проверка максимальной длительности соединения
        IFL     time_counter, MAX_TIME, check_calls_counter2

        clrf    dtr_arg
        call    function_DTR

        bcf     flags, FLAG_CALL
        clrf    time_counter

        ; положить трубку
        ATCMDB   a, function_ATH, 4, 2

        MOVLF   1, dtr_arg
        call    function_DTR

check_calls_counter2:
        ; проверка счетчика удачных соединений (демо-прошивка)
        MOVLF1  EEPROM_CALLS_COUNTER, EEADR
        bcf     EECON1, 7
        bsf     EECON1, RD
        ; достигли максимума?
        IFNE    EEDATA, MAX_CALLS, have_free_calls2
        ; лимит исчерпан
        BLINKP  5
        ; сбрасываем звонок
        TXSTR   a, function_ATH, 4
        LDELAY  6, a
        ; зацикливаемся
        goto    check_calls_counter2
        Bank1

have_free_calls2:
        Bank0
        goto    label_138
        ; unreachable code
        goto    go_sleep

power_off:
        ; Выключение происходит как и включение.
        ; Нажмите на кнопку и держите покуда не моргнет светодиод, как отпустите
        ; он моргнет 2 раза. Это означает, что девайс выключен.
        BLINK   2
        call    function_SIM300D_power
        clrf    state

go_sleep:
        sleep

        end

Если найдете ошибку, напишите в комментариях.

Подпишитесь на блог, чтобы узнавать о новых статьях сразу.

Все статьи →

© Copyright 2025 Badradio. All rights reserved.
Все права защищены. Копирование материалов сайта запрещено.
При цитировании ставить кликабельную ссылку на первоисточник.