
В этом уроке мы дадим вторую жизнь телефонному аппарату с дисковым номеронабирателем, превратив его в мобильный (переносной) ретро-аппарат сотовой связи.
Есть стационарные телефонные аппараты у которых нет провода между трубкой и базой, но есть провод к розетке АТС. В нашем проекте у телефона останется провод между трубкой и базой, но пропадёт провод к розетке, так как связь будет осуществляться по сети 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 функция работает с колокольными звонками собранными на базе соленоида, родного звонка телефона, сервопривода или электромотора.
Ссылки:
Комплект для повторения проекта
Что понадобится
Это быстрый ориентир по основным модулям и деталям. Полный список для повторения проекта смотрите в самой статье.
15 позиций
Телефонный дисковый номеронабиратель
дисковым номеронабирателем
Открыть в iArduino
Динамик 40мм, 3W, 4Ом.
Динамик
Открыть в iArduino
Зуммер со встроенным генератором (Trema-модуль)
Позволяет излучать звук фиксированной тональности
Открыть в iArduino
Arduino Uno R3 (USB ATmega16U2)
Платформа c микроконтроллером ATmega328P на ядре AVR с чипом USB ATmega16U2 для разработки электронных устройств на языке C++
Открыть в iArduino
Piranha Uno R3
Прямой аналог Arduino Uno c микроконтроллером ATmega328P на ядре AVR для разработки электронных устройств на языке C++
Открыть в iArduino
GSM/GPRS Shield A9
Плата расширения для добавления контроллеру Arduino функций мобильной сети
Открыть в iArduino
Источник питания 5В, 5-12В (Li-ion 18650)
Источник питания 5В
Открыть в iArduino
Коннектор power jack Папа с клемником
Коннектор power jack Папа с клемником для Arduino
Открыть в iArduino
Микрофон CZN-15E
микрофон
Открыть в iArduino
Силовой ключ N-канал (Trema-модуль)
Позволит управлять нагрузкой ШИМ сигналом. Например яркостью светодиодной ленты или скоростью мотора
Открыть в iArduino
Мини повышающий DC-DC преобразователь
повышающий DC-DC преобразователь
Открыть в iArduino
Соленоид JF-0520B (4 Н, 12 В) / TAU-0520
Электромеханический толкатель c усилием 4 Н и номинальным питанием 12 В
Открыть в iArduino
Кнопка, красная (Trema-модуль)
Тактовая кнопка, которая может служить источником сигналов (команд) для Ваших проектов
Открыть в iArduino
Trema Shield
Плата расширения для удобного подключения периферийных устройств
Открыть в iArduino
Battery Shield (Li-po, 2300 мА·ч)
Battery Shield
Открыть в iArduino