В этом уроке мы дадим вторую жизнь телефонному аппарату с дисковым номеронабирателем, превратив его в мобильный (переносной) ретро-аппарат сотовой связи.
Есть стационарные телефонные аппараты у которых нет провода между трубкой и базой, но есть провод к розетке АТС. В нашем проекте у телефона останется провод между трубкой и базой, но пропадёт провод к розетке, так как связь будет осуществляться по сети GSM.
Описание работы ретро GSM телефона:
- После подачи питания дождитесь кратковременного колокольного звонка, он оповещает о том, что модем GSM зарегистрирован в сети сотового оператора связи.
- Телефон может принимать входящие звонки если трубка лежит на телефоне.
- Можно снять трубку (при отсутствии входящего звонка) для перехода в режим «я занят».
- Для ответа на входящий звонок нужно поднять трубку.
- Для завершения разговора нужно положить трубку на телефон.
- Набираемый номер должен состоять из 11 цифр и начинаться с цифры 7 или 8.
- Можно набирать номера 01, 02, 03, 04, 100, предварительно указав код города 8(495).
- Можно набирать номера 101, 102, 103, 104, 112.
- Ввод цифр номера осуществляется поворотом заводного диска до нужной цифры с последующим самовозвратом диска в исходное положение.
- Для совершения исходящего вызова выполните следующие действия:
- Поднимите трубку при отсутствии входящего вызова.
- Дождитесь появления гудка в трубке, он сигнализирует о наличии связи с сотовым оператором, следовательно, готовности к набору номера.
- Наберите номер вызываемого абонента.
- Если Вы ошиблись, опустите, поднимите трубку и повторите набор заново.
- Во время набора номера гудок в трубке должен пропасть. Вместо него, во время возврата заводного диска, имитируется звук "щелчков" от набора номера.
- После ввода последней (одиннадцатой) цифры номера дождитель появления сигнала вызова (длинные гудки или мелодия), или сигнала занят (короткие гудки).
- Если абонент ответит на Ваш вызов, то установится голосовое соединение.
- Если абонент разорвёт голосовую связь, Вы услышите сигнал занят (короткие гудки).
- Завершить вызов, набор, соединение или разговор можно в любое время повесив трубку.
- Динамик в телефонной трубке излучает звуки разговора и сигнал вызова (длинные гудки или мелодия), а все остальные сигналы формируются звукоизлучателем (зуммером), так же установленным в телефонную трубку.
Нам понадобится:
- Arduino / Piranha UNO.
- GSM/GPRS Shield A9.
- Источник питания 5В.
- Аккумулятор 18650 Li-ion, 3.7V
- Коннектор power jack Папа с клемником для Arduino
- Звук разговора и сигналов (можно выбрать один из вариантов):
- Динамик + микрофон + зуммер с генератором (в корпусе трубки телефона).
- Гарнитура с микрофоном + Trema зуммер с генератором.
- Колокольный звонок (можно выбрать один из вариантов):
- Колокольный звонок телефона + Trema силовой ключ + повышающий DC-DC преобразователь.
- Звонок из соленоида + колокол + Trema силовой ключ + повышающий DC-DC преобразователь.
- Звонок из сервопривода + колокол.
- Дисковый номеронабиратель (если его нет в корпусе телефона).
- Трема кнопка (если в корпусе телефона нет кнопки опускания трубки).
- Корпус телефона.
- Для реализации проекта нам необходимо установить библиотеку:
- iarduino_GSM.
- Библиотеки SoftwareSerial и Servo входят в стандартный набор Arduino IDE.
О том как устанавливать библиотеки, Вы можете ознакомиться на странице Wiki - Установка библиотек в Arduino IDE.
Схема сборки:
Arduino / Piranha UNO:
Если Вы собираетесь разместить устройство в корпусе телефона, найдите место для установки Arduino / Piranha UNO и закрепите её.
GSM/GPRS Shield:
Установите GSM/GPRS Shield A9 на Arduino / Piranha UNO:
На плате GSM/GPRS Shield A9 имеется слот для SIM-карт и переключатель UART. Установите SIM-карту в слот, выберите положение переключателя RX-7/TX-8.
Trema Shield:
На GSM/GPRS Shield A9 установите Trema Shield:
Номеронабиратель:
Подключите номеронабиратель к выводам GND, D5, D6 и Трема кнопку к выводу D4:
Если Вы собираете устройство в корпусе телефона, то вместо Trema кнопки подключите кнопку фиксации опускания трубки, между выводами GND и D4).
Колокольный звонок:
Подключите модули управления колокольным звонком:
Напряжение питания 5В подводится на вход повышающего DC-DC преобразователя, а напряжение с его выхода (уровень напряжения регулируется потенциометром преобразователя) подводится к соленоиду или родной катушке звонка телефона, через Trema силовой ключ, управление которым осуществляется через вывод D2.
Колокольный звонок можно собрать не на соленоиде, а на сервоприводе, подключив его к выводу D2:
Преимуществом данной схемы является меньшее число деталей. Но в скетче нужно присвоить переменной modeBEEL
значение 2 (разкомментировать строку в начале скетча), а так же указать углы сервопривода при которых боёк касается колокола и удаляется от него (углы указываются в функции funcBELL
в конце скетча).
Устройство ввода/вывода звука:
Если Вы собираетесь разместить динамик, микрофон и зуммер в трубке телефона, то подключите их согласно схеме: (трубка соединяется с аппаратом четырехпроводным кабелем).
В телефонной трубке, рядом с динамиком, необходимо разместить и зуммер. Он подключается к выводу D3 и нужен для подачи сигналов "готов к набору" (гудок при снятой трубке) и "занято" (прерывистые гудки после разрыва голосового соединения).
Если Вы не собираетесь размещать элементы ввода/вывода звука в телефонной трубке, то более простым вариантом является использование гарнитуры, которая подключается к соответствующему разъёму на плате GSM/GPRS Shield A9, а сигналы "готов к набору" и "занято" будут выводиться отдельно, через Trema зуммер, так же подключённый к выводу D3.
Если Вы не собираетесь размещать элементы ввода/вывода звука в телефонной трубке, но и не желаете использовать гарнитуру, то реализуйте вот такую схему:
Полная схема устройства:
Пример схемы с использованием гарнитуры и колокольного звонка на базе соленоида:
Подключение питания
Настройте выход 5-12V Источника питания 5В на максимум (12V) и установите в него Аккумулятор 18650 Li-ion, 3.7V. Подключите вывод 5-12V источника к джеку питания Arduino / Piranha UNO при помощи Коннектора power jack Папа с клемником.
Код программы (скетч):
В скетче предусмотрена возможность выбора типа колокольного звонка modeBEEL
=0,1,2 и алгоритма работы кнопки фиксирующей опускание телефонной трубки flgHANG
=0,1. Для выбора необходимого значения закомментируёте существующее и разкомментируйте требуемое.
В скетче используются библиотеки iarduino_GSM, SoftwareSerial и Servo (две последние входят в стандартный набор Arduino IDE).
Если Вы используете старую версию GSM шилда (A6), то в строках 10-12 необходимо заменить значения переменных pinPWR, pinRX и pinTX на соответсвтующие для этого шилда (pinPWR = 9, pinRX = 7, pinTX = 8).
// Телефонный аппарат с импульсным номеронабирателем на базе GSM/GPRS Shield A9 // ============================================================================ // // Определяем номера выводов: // uint8_t pinBELL = 2; // Вывод (выход) используемый для подключения силового ключа (для включения звонка вызова). uint8_t pinBEEP = 3; // Вывод (выход) используемый для подключения излучателя звука (для вывода гудков в трубке). uint8_t pinHANG = 4; // Вывод (вход) используемый для подключения кнопки (NC) фиксирующей опускание телефонной трубки. uint8_t pinDIAL = 5; // Вывод (вход) используемый для подключения шунтирующего контакта (NO) номеронабирателя. uint8_t pinPULSE = 6; // Вывод (вход) используемый для подключения тактирующего контакта (NC) номеронабирателя. uint8_t pinPWR = 7; // Вывод PWR GSM шилда uint8_t pinRX = 8; // Вывод (вход) используемый как линия RX (приём ) программной шины UART (данные от GSM/GPRS Shield к Arduino). uint8_t pinTX = 9; // Вывод (выход) используемый как линия TX (передача) программной шины UART (данные к GSM/GPRS Shield от Arduino). // // Определяем тип колокольного звонка: // uint8_t modeBEEL = 0; // Колокольный звонок собран на соленоиде (электромагнитной катушке, собственном звонке телефона). // uint8_t modeBEEL = 1; // Колокольный звонок собран на электромоторе с бойком закреплённым к его ротору. // uint8_t modeBEEL = 2; // Колокольный звонок собран на сервоприводе с бойком закреплённым к его качалке. // // Определяем алгоритм работы кнопки: // bool flgHANG = 0; // 0-(NC) контакты кнопки замкнуты при лежащей трубке. // bool flgHANG = 1; // 1-(NO) контакты кнопки разомкнуты при лежащей трубке. // // Объявляем переменные и функции: // bool flgPowerON = true; // Определяем флаг подачи питания. uint8_t cntPULSE; // Объявляем переменную для подсчёта импульсов в последней набранной цифре (10 импульсов для цифры 0). uint8_t cntDigits; // Объявляем переменную для подсчёта набранных цифр номера. char strNumber[12]; // Объявляем строку для хранения номера вызываемого/вызывающего телефона (11 символов номера + символ конца строки). void funcBELL(bool); // Объявляем функцию управления звонком (true - подаёт один колокольный звон, false - выключает колокольный звонок). // // Подключаем библиотеки: // #include <SoftwareSerial.h> // Подключаем библиотеку SoftwareSerial для программной реализации шины UART. #include <iarduino_GSM.h> // Подключаем библиотеку iarduino_GSM для работы с GSM/GPRS Shield. #include <Servo.h> // Подключаем библиотеку Servo для работы с сервоприводом (если колокольный звонок собран на сервоприводе). // // Создаём объекты: // iarduino_GSM gsm(pinPWR); // Создаём объект gsm для работы с функциями и методами библиотеки iarduino_GSM, указав вывод PWR. SoftwareSerial softSerial(pinRX, pinTX); // Создаём объект softSerial указывая выводы платы Arduino используемые в качестве линий RX и TX программной шины UART. Servo srv; // Создаём объект srv для работы с функциями и методами библиотеки Servo (если колокольный звонок собран на сервоприводе). // void setup(){ // Serial.begin(9600); // █ Инициируем связь с монитором последовательного порта на скорости 9600 бит/сек. if(modeBEEL==2){srv.attach(pinBELL);} // Назначаем объекту srv управление сервоприводом подключённым к выводу pinBELL (если колокольный звонок собран на сервоприводе). else{pinMode(pinBELL,OUTPUT); digitalWrite(pinBELL,LOW);} // Переводим вывод pinBELL в режим выхода и устанавливаем на нём уровень логического «0» (если колокольный звонок собран на соленоиде/электромагните/электромоторе). pinMode(pinBEEP, OUTPUT); digitalWrite(pinBEEP, LOW ); // Переводим вывод pinBEEP в режим выхода и устанавливаем на нём уровень логического «0». pinMode(pinHANG, INPUT ); digitalWrite(pinHANG, HIGH); // Переводим вывод pinHANG в режим входа и подтягиваем его к Vcc. pinMode(pinDIAL, INPUT ); digitalWrite(pinDIAL, HIGH); // Переводим вывод pinDIAL в режим входа и подтягиваем его к Vcc. pinMode(pinPULSE, INPUT ); digitalWrite(pinPULSE, HIGH); // Переводим вывод pinPULSE в режим входа и подтягиваем его к Vcc. // funcBELL(false); // Отключаем колокольный звонок входящего вызова. gsm.begin(softSerial); // Инициируем работу GSM/GPRS Shield, указывая объект (или класс) для работы с её шиной UART. // // Ждём готовность GSM/GPRS Shield к работе: // while(gsm.status()!=GSM_OK){delay(1000);} // Ждём завершения регистрации модема в сети оператора связи. // // // Информируем о готовности модуля кратковременным включением колокольного звонка: // if(flgPowerON){ // // Если функция setup() выполняется в первый раз: // uint32_t i = millis() + 1000; // Определяем длительность звонка готовности модуля. while(i>millis()){ funcBELL(true); } funcBELL(false); // Включаем и отключаем колокольный звонок. flgPowerON = false; // Сбрасываем флаг подачи питания. } // Serial.println(F("Готов к работе!")); // █ Можно добавить код выполняемый однократно после готовности аппарата при подаче питания. } // // void loop (){ // /******* СОВЕРШАЕМ ИСХОДЯЩИЙ ЗВОНОК *******/ // Для исходящего звонка нужно поднять трубку и набрать номер. if(digitalRead(pinHANG)^flgHANG){ // Если на входе pinHANG установлена логическая «1» (трубка снята). // Если трубка снята: // delay(100); // Подавляем дребезг поднятия трубки. // Готовимся к набору номера: // cntDigits = 0; // Сбрасываем счетчик набранных цифр номера (номер ещё не набирался). strNumber[0]='\0'; // Чистим строку набираемого номера. digitalWrite(pinBEEP, LOW); // Отключаем тоновый сигнал в трубке телефона (если он был включён). Serial.println(F("Трубка снята, проверяем готовность к набору номера ...")); // █ Можно добавить код выполняемый однократно при поднятии трубки для набора номера, до проверки наличия связи с оператором. // Проверяем готовность GSM/GPRS Shield к работе: // if(gsm.status()!=GSM_OK){ // // Если модуль не готов к работе (например, ошибка регистрации в сети): // Serial.println(F("Перезагрузка модуля")); // █ Выводим сообщение о перезагрузке модуля. // Заново инициируем работу с модулем: // setup(); // } // // Информируем о готовности к набору номера: // digitalWrite(pinBEEP, HIGH); // Включаем тоновый сигнал в трубке телефона (оповещая о готовности к набору номера). Serial.println(F("Можно набирать номер ...")); // █ Можно добавить код выполняемый однократно при поднятии трубки для набора номера, после проверки связи с оператором. while(digitalRead(pinHANG)^flgHANG){ // Входим в цикл, который будет завершён опусканием трубки на телефон. // Цикл выполняется всё время, пока снята трубка: // if(!digitalRead(pinDIAL)){ // Если шунтирующая контактная группа номеронабирателя замкнулась (значат набор цифры), то ... // Если начинается набор очередной цифры номера: // delay(20); // Подавляем дребезг шунтирующей контактной группы номеронабирателя. digitalWrite(pinBEEP, LOW); // Отключаем тоновый сигнал в трубке телефона (если он был включён). cntPULSE=0; // Сбрасываем счётчик поступивших импульсов от номеронабирателя. Serial.print(F("Набирается цифра ... ")); // █ Можно добавить код выполняемый однократно перед набором каждой цифры номера while(!digitalRead(pinDIAL) && (digitalRead(pinHANG)^flgHANG)){ // Если чтение импульсов набираемой цифры разрешено (шунтирующие контакты номеронабирателя замкнуты) и трубка снята, то ... // Цикл выполняется пока набирается очередная цифра номера: // if(digitalRead(pinPULSE)){ // Если поступил тактирующий импульс (импульсная контактная группа номеронабирателя разомкнулась), то ... // Фронт импульса: // digitalWrite(pinBEEP, HIGH); // Включаем тоновый сигнал в трубке телефона. delay(5); // Подавляем дребезг импульсной контактной группы номеронабирателя. digitalWrite(pinBEEP, LOW); // Отключаем тоновый сигнал в трубке телефона. while(digitalRead(pinPULSE) && (digitalRead(pinHANG)^flgHANG)){delay(5);} // Ждём завершения тактирующего импульса (замыкания импульсной контактной группы номеронабирателя) или опускания трубки. // Спад импульса: // delay(5); // Подавляем дребезг импульскной контактной группы номеронабирателя. cntPULSE++; // Увеличиваем счётчик полученных импульсов. } // } // delay(20); // Подавляем дребезг шунтирующей контактной группы номеронабирателя. // Очередная цифра номера набрана: // if(cntPULSE){ // Если от импульсной контактной группы номеронабирателя поступил хотя бы 1 импульс, то ... // Если цифра набрана корректно (во время набора поступил хотя бы один импульс) // if(cntPULSE>=10){cntPULSE=0;} // Если поступило 10 импульсов, значит набрана цифра 0. strNumber[cntDigits]=cntPULSE+48; // Сохраняем код набранной цифры в строку с набираемым номером. cntDigits++; // Переходим к следующей цифре набираемого номера. strNumber[cntDigits]='\0'; // Сохраняем код конца строки. Serial.println(cntPULSE); // █ Можно добавить код выполняемый однократно после набора каждой цифры номера. } // // Проверяем введённые цифры номера: // if( cntDigits==11 // Если набрано 11 цифр номера *(***)***-**-** - обычный номер. || (cntDigits==7 && strncmp("8495100", strNumber, 8)==0) // Если набрано 7 цифр номера 8(495)100 - точное время (городской). || (cntDigits==6 && strncmp("849501", strNumber, 7)==0) // Если набрано 6 цифр номера 8(495)01 - пожарная служба (городской). || (cntDigits==6 && strncmp("849502", strNumber, 7)==0) // Если набрано 6 цифр номера 8(495)02 - полиция (городской). || (cntDigits==6 && strncmp("849503", strNumber, 7)==0) // Если набрано 6 цифр номера 8(495)03 - скорая помощь (городской). || (cntDigits==6 && strncmp("849504", strNumber, 7)==0) // Если набрано 6 цифр номера 8(495)04 - газовая служба (городской). || (cntDigits==3 && strncmp("101", strNumber, 4)==0) // Если набрано 3 цифры номера 101 - пожарная служба. || (cntDigits==3 && strncmp("102", strNumber, 4)==0) // Если набрано 3 цифры номера 102 - полиция. || (cntDigits==3 && strncmp("103", strNumber, 4)==0) // Если набрано 3 цифры номера 103 - скорая помощь. || (cntDigits==3 && strncmp("104", strNumber, 4)==0) // Если набрано 3 цифры номера 104 - газовая служба. || (cntDigits==3 && strncmp("112", strNumber, 4)==0) // Если набрано 3 цифры номера 112 - экстренные оперативные службы. ){ // // Если номер набран полностью, то инициируем вызов ... // if(gsm.CALLdial(strNumber)){ // Инициируем исходящий голосовой вызов на номер указанный в строке strNumber. // Если исходящий вызов инициирован, ждём завершения набора номера ... // Serial.println((String) "Набор номера " + strNumber + " ..."); // █ Можно добавить код выполняемый однократно при начале набора номера. while(gsm.CALLstatus()==GSM_CALL_OUT_DIAL && (digitalRead(pinHANG)^flgHANG)){} // Цикл выполняется пока установлено состояние вызова "набирается номер" и снята трубка. while(gsm.CALLstatus()==GSM_CALL_OUT_DIAL && (digitalRead(pinHANG)^flgHANG)){} // Повторяем цикл на случай кратковременного изменения статуса вызова. while(gsm.CALLstatus()==GSM_CALL_OUT_DIAL && (digitalRead(pinHANG)^flgHANG)){} // Повторяем цикл на случай кратковременного изменения статуса вызова. if(gsm.CALLstatus()==GSM_OK){ // // Если произошёл обрыв связи с оператором: // Serial.println(F("произошёл обрыв связи с оператором.")); // █ Можно добавить код выполняемый однократно при обрыве связи с оператором. } // if(gsm.CALLstatus()==GSM_CALL_OUT_BEEP){ // Если установилось состояние вызова "дозвон", то ... // Если начался дозвон, то ждём пока вызываемый абонент не ответит ... // Serial.println(F("Ожидание ответа ...")); // █ Можно добавить код выполняемый однократно при поступлении гудков у вызываемого абонента. while(gsm.CALLstatus()==GSM_CALL_OUT_BEEP && (digitalRead(pinHANG)^flgHANG)){} // Цикл выполняется пока установлено состояние вызова "дозвон" и снята трубка. delay(500); // Даём время для установки состояния вызова - "соединён". } // if(gsm.CALLstatus()==GSM_CALL_ACTIVE){ // Если установилось состояние вызова "соединён", то ... // Если установлено активное голосовое соединение ... // Serial.println(F("Исходящее голосовое соединение установлено.")); // █ Можно добавить код выполняемый однократно при установлении активного голосового соединения. while(gsm.CALLstatus()==GSM_CALL_ACTIVE && (digitalRead(pinHANG)^flgHANG)){} // Цикл выполняется пока установлено активное голосовое соединение и снята трубка. // Если голосовое соединение разорвано или его требуется разорвать ... // } // Serial.println(F("Разговор завершён.")); // █ Можно добавить код выполняемый однократно в момент завершения разговора. } // // Разрываем голосовое соединение, если разговор завершён опусканием трубки: // gsm.CALLend(); // Разъединяем голосовое соединение. // Выводим короткие звуковые сигналы в трубку телефона... // while(digitalRead(pinHANG)^flgHANG){ // Цикл выполняется пока снята трубка. if(millis()%1000<500){digitalWrite(pinBEEP, HIGH);} // Выводим тоновый сигнал в трубке телефона в течении первых 500 мс каждых 1000 мс. else {digitalWrite(pinBEEP, LOW );} // Отключаем тоновый сигнал в трубке телефона в течении остального времени из 1000 мс. } digitalWrite(pinBEEP, LOW ); // Отключаем тоновый сигнал в трубке телефона. } // } // gsm.CALLend(); // Разъединяем голосовое соединение, если нам позвонили пока поднята трубка (до или в момент набора номера). } // Serial.println(F("Трубка опущена на аппарат.")); // █ Можно добавить код выполняемый однократно в момент опускания трубки на аппарат. }else{ // /******* ПРИНИМАЕМ ВХОДЯЩИЙ ЗВОНОК *******/ // Для приёма входящих звонков трубка должна быть опущена. // Если трубка лежит на телефоне: // delay(100); // Подавляем дребезг опускания трубки. digitalWrite(pinBEEP, LOW); // Отключаем тоновый сигнал в трубке телефона (если он был включён). Serial.println(F("Трубка лежит на аппарате, режим ожидания звонка ...")); // █ Можно добавить код выполняемый однократно в момент перехода в режим ожидания входящего звонка while(!digitalRead(pinHANG)^flgHANG){ // Входим в цикл, который будет завершён поднятием трубки с телефона. // Цикл выполняется всё время, пока трубка не поднята: // if(gsm.CALLavailable(strNumber)){ // Функция CALLavailable() возвращает true если есть входящий дозванивающийся вызов, номер вызывающего абонента сохраняется в строку strNumber. // Если есть входящий вызов в режиме дозвона, то ждём ответа поднятием трубки ... // Serial.println((String)"Входящий вызов "+strNumber+", ждём поднятия трубки ..."); // █ Можно добавить код выполняемый однократно в момент поступления входящего звонка while(gsm.CALLavailable() && !(digitalRead(pinHANG)^flgHANG)){ // Цикл выполняется пока есть входящий вызов в режиме дозвона и трубка не поднята. // Информируем колокольными звонками о наличии входящего вызова: // while(millis()%4000<2000){funcBELL(true);} // Включаем колокольный звонок в течении первых 2000 мс каждых 4000 мс. funcBELL(false); // Отключаем колокольный звонок в течении остального времени. } // delay(100); // Подавляем дребезг поднятия трубки. // Проверяем почему был завершён цикл ожидания ответа ... // if(digitalRead(pinHANG)^flgHANG){ // Если трубка снята. // Если цикл завершён по причине поднятия трубки: // Serial.println(F("Трубка снята, отвечаем на звонок")); // █ Можно добавить код выполняемый однократно в момент поднятия трубки для ответа на входящий звонок. if(gsm.CALLavailable()){ // Функция CALLavailable() возвращает true если есть входящий дозванивающийся вызов. // Если вызывающий абонент всё ещё ждёт ответа (поднятия трубки) ... // gsm.CALLup(); // Отвечаем на вызов. // Ждём пока состояние вызова "дозвон" не сменится ... // while(gsm.CALLstatus()==GSM_CALL_IN_BEEP){;} // Функция CALLstatus() возвращает статус текущего голосового вызова, значение GSM_CALL_IN_BEEP указывает на наличие входящего дозванивающегося вызова. if(gsm.CALLstatus()==GSM_CALL_ACTIVE){ // Функция CALLstatus() возвращает статус текущего голосового вызова, значение GSM_CALL_ACTIVE указывает на наличие активного голосового соединения. // Если установлено активное голосовое соединение ... // Serial.println(F("Входящее голосовое соединение установлено.")); // █ Можно добавить код выполняемый однократно при установлении активного голосового соединения. while(gsm.CALLstatus()==GSM_CALL_ACTIVE && (digitalRead(pinHANG)^flgHANG)){} // Цикл выполняется пока установлено активное голосовое соединение и снята трубка. } // // Если голосовое соединение разорвано или требуется разорвать ... // Serial.println(F("Разговор завершён.")); // █ Можно добавить код выполняемый однократно в момент завершения разговора. // Разрываем голосовое соединение, если разговор завершён опусканием трубки: // gsm.CALLend(); // Разъединяем голосовое соединение, это требуется если мы инициировали разрыв соединения опусканием трубки. } // // Выводим короткие звуковые сигналы в трубку телефона... // while(digitalRead(pinHANG)^flgHANG){ // Цикл выполняется пока снята трубка. if(millis()%1000<500){digitalWrite(pinBEEP, HIGH);} // Выводим тоновый сигнал в трубке телефона в течении первых 500 мс каждых 1000 мс. else {digitalWrite(pinBEEP, LOW );} // Отключаем тоновый сигнал в трубке телефона в течении остального времени из 1000 мс. } digitalWrite(pinBEEP, LOW ); // Отключаем тоновый сигнал в трубке телефона. }else{ // // Если цикл завершён по причине сброса вызова: // Serial.println(F("Вызов завершён по причине сброса вызова")); // █ Можно добавить код выполняемый однократно в момент сброва вызова. } // }else{ // // Если входящих вызовов в режиме дозвона нет: // if(gsm.status()!=GSM_OK){ // // Если модуль не готов к работе (например, ошибка регистрации в сети): // Serial.println(F("Перезагрузка модуля")); // █ Выводим сообщение о перезагрузке модуля. // Заново инициируем работу с модулем: // setup(); // } // } // } // } // } // // // Функция управления колокольным звонком: // В зависимости от параметра (f) функция либо отключает колокольный звонок, либо подаёт один колокольный звон входящего вызова. void funcBELL(bool f){ // В данной функции можно регулировать тональность колокольного звонка, меняя задержку delay(). if(modeBEEL==0){ // // Если колокольный звонок собран на соленоиде (электромагнитной катушке): // if(f){digitalWrite(pinBELL, HIGH); delay(20); // Если установлен флаг f, то: - подаём высокий уровень на выход pinBELL (силовой ключ замкнётся , через катушку потечёт ток и боёк ударит о колокол), ждём 20 мс. digitalWrite(pinBELL, LOW ); delay(20); // - подаём низкий уровень на выход pinBELL (силовой ключ разомкнётся, катушка будет обесточена и боёк удалится от колокола), ждём 20 мс. }else{digitalWrite(pinBELL, LOW );} // Если сброшен флаг f, то - подаём низкий уровень на выход pinBELL (силовой ключ разомкнётся, катушка будет обесточена и боёк удалится от колокола). }else if(modeBEEL==1){ // // Если колокольный звонок собран на электромоторе: // if(f){digitalWrite(pinBELL, HIGH);} // Если установлен флаг f, то - подаём высокий уровень на выход pinBELL (силовой ключ замкнётся , электромотор включится и боёк на его роторе начнёт бить по колоколу). else {digitalWrite(pinBELL, LOW );} // Если сброшен флаг f, то - подаём низкий уровень на выход pinBELL (силовой ключ разомкнётся, электромотор отключится и боёк перестанет бить по колоколу). }else if(modeBEEL==2){ // // Если колокольный звонок собран на сервоприводе: // if(f){srv.write(50); delay(20); // Если установлен флаг f, то: - поворачиваем сервопривод на угол при котором боёк закреплённый к его качалке ударит о колокол, ждём 20 мс. srv.write(60); delay(20); // - поворачиваем сервопривод на угол при котором боёк закреплённый к его качалке удалится от колокола, ждём 20 мс. }else{srv.write(60);} // Если сброшен флаг f, то - поворачиваем сервопривод на угол при котором боёк закреплённый к его качалке удалится от колокола. } // Вместо углов 50° и 60° необходимо указать Ваши углы (значение подбирается экспериментально). }
В разделе функции funcBELL
отвечающем за управление сервоприводом указаны углы 50° и 60° (три последние строки). Если Вы используете колокольный звонок на сервоприводе, измените угол 50° на тот при котором сервопривод ударяет бойком по колоколу, а угол 60° на тот при котором боёк удаляется от него.
Алгоритм работы скетча:
До кода Setup() определяются номера выводов, тип колокольного звонка, алгоритм работы кнопки фиксирующей опускание трубки, объявляются переменные и функции, подключаются библиотеки, и создаются объекты для работы с ними.
В коде setup() конфигурируются выбранные выводы, инициируется работа GSM/GPRS Shield, звук переводится на разъём гарнитуры, выполняется цикл ожидания готовности GSM/GPRS Shield к работе (регистрация в сети оператора). И после выполнения всех указанных действий выполняется оповещение о готовности к работе, путем включения колокольного звонка на 1 секунду.
Код цикла loop() разделён на две основные части: совершение исходящих звонков (данная часть выполняется если телефонная трубка снята) и приём входящих вызовов (данная часть выполняется если трубка лежит на телефоне).
Совершение исходящих звонков состоит из следующих действий:
- Обнуление переменных, проверка связи с оператором, вывод сигнала в трубку телефона о готовности к работе.
- Дальнейшие действия происходят в отдельном цикле, выход из которого возможен только если положить трубку на телефон. Так же в этом цикле постоянно сбрасывается голосовое соединение, не давая другим абонентам позвонить нам при снятой трубке.
- Если начинается набор номера, то отключаем сигнал в телефонной трубке, подсчитываем количество импульсов набираемых цифр. После каждой введённой цифры из значение добавляется в строку с номером, которая проверяется на корректность (достижение 11 знаков, или совпадение с коротким номером). При желании Вы можете добавить или удалить некоторые короткие номера из скетча.
- Если номер в строке корректен, то производится его набор, с дальнейшей проверкой состояния связи. Если связь установлена, то выполняется пустой цикл ожидания её разрыва.
- При разрыве голосового соединения выполняется цикл вывода коротких звуковых сигналов в телефонную трубку. Этот цикл выполняется постоянно, пока не положить трубку на телефон.
Приём входящих вызовов состоит из следующих действий:
- Отключение тонального сигнала в телефонной трубке (на случай если он был).
- Дальнейшие действия происходят в отдельном цикле, выход из которого возможен только если снять трубку с телефона при отсутствии входящего вызова.
- Если зафиксирован входящий вызов, то выполняется цикл включающий колокольный звонок, пока входящий вызов не изменит свой статус или не будет поднята трубка.
- Если статус вызова изменился по причине поднятия трубки, то устанавливается голосовое соединение, и выполняется пустой цикл ожидания разрыва этого соединения.
- После разрыва голосового соединения выполняется цикл вывода коротких звуковых сигналов в телефонную трубку. Этот цикл выполняется постоянно, пока не положить трубку на телефон.
В конце скетча определена функция управления колокольным звонком. Данная функция принимает один параметр типа bool
(true
- ударить в колокол и освободить его / false
- освободить колокол). В зависимости от значения переменной modeBEEL
функция работает с колокольными звонками собранными на базе соленоида, родного звонка телефона, сервопривода или электромотора.
Обсуждение