На самом деле, я уже давно так не считаю, так как натура у меня такая - всегда стараюсь не упускать возможность, стремлюсь узнать что-то новое. Тем более, прошло уже много лет с того момента, как я понял, что Си - чересчур сложен для меня. Все оказалось не так уж страшно.Век живи - век учись...
В общем, интересоваться платами arduino я начал относительно давно... Мне было интересно именно то, что для этих плат не нужно было рисовать схему, подбирая элементы из тех, что можно у нас достать, рисовать PCB, выпиливать, утюжить и травить плату, так как времени на это уходит очень много. А его как раз у меня, в последние года 2 категорически не хватает...
Останавливало лишь необходимость в неизбежном изучении языка Си, который с детства меня обошел стороной, так как учительница по информатике владела исключительно basic-ом. В институте же почему-то нам преподавали турбопаскаль. Но, как бы то ни было, это наложило серьезный отпечаток на мое дальнейшее развитие. :)
В общем, накупил я себе разных плат ардуино и начал шаманить. Самым первым тестовым проектом было установление связи с моим телефоном и управление светодиодом, в том числе и его яркостью по bluetooth. C восторгом я наблюдал, как буквально через пару часов разбирательств с arduino и Basic4Android, светодиод начал менять яркость по движению моего пальца по экрану! Это было круто! Самое интересное, что на написание кода для arduino leonardo ушло каких-то 5-10 минут! Впоследствии, надеюсь, мы сможем уделить время и среде разработки для Android. А пока статья о другом.
И вот, практически на прошлой неделе в нашу контору обратился представитель компании МТС в нашем регионе с просьбой решить следующую задачу - требуется следить за уровнем воды в емкости и сообщать менеджерам о необходимости пополнения, так как, как это часто бывает в России, за этим смотрел персонал, не имеющий к этому никакого отношения. Так,... как бы заодно... Естественно, это очень часто приводило к отсутствию воды на объекте и суточным, а то и более, ожиданиям приезда машины с водой.
Меня обрадовало это и я немедленно приступил к разработке.
Мне пришлось немного задуматься о способе записи номеров в прибор, так как это влияло и на сложность разработки. Остановился на простом варианте с кнопками и светодиодами. Ниже поясню. В качестве управляющего контроллера был выбран малоногий контроллер Arduino Nano с разъемом USB для программирования. Он имеет PWM выходы, которые я использовал в проекте для плавного мигания светодиодами. Смотрится очень красиво.
Для работы с прибором требуется какой-либо GSM модем. Я взял промышленный модем ПМ01, так как он был под рукой. Дороговат для любительских разработок... Вообще подойдет любой. Помните историю с телефоном сименс C35? Здесь он тоже подойдет. Главное, согласовать уровни.
В общем была составлена такая схема:
Принцип работы прост. Есть вода - электроды замкнуты - на входе 0В, нет воды - разомкнуты - на входе +5В.
Я в программе анализирую это и при отсутствии воды отправляю СМС на три номера (таково было задание) о том, что вода заканчивается. После отправки смс я ставлю флаг, запрещающий повторную отправку до тех пор, пока вода снова не появится и после этого вновь не уйдет ниже уровня.
Принцип записи номеров в память контроллера такой - нажимаем одну из трех кнопок - входим таким образом в режим записи номера (при этом плавно мигает соответствующий светодиод). Звоним по номеру сим-карты прибора. Прибор вычисляет номер входящего звонка, сохраняет его в память и зажигает светодиод на постоянку. Таким образом, пользователь знает, что номер в эту ячейку уже записан. Так же с остальными ячейками. Стереть номер из ячейки можно, нажав соответствующую кнопку при включении прибора. После того, как светодиод мигнет, можно быть уверенным, что номер стерт. Все просто!
Белый светодиод показывает, есть ли вода в емкости или нет. Если горит постоянно - вода есть. Часто мигает - воды нет.
После того, как прибор обнаружил отсутствие воды, если в памяти есть хоть один номер, он отправляет смс с текстом "Low water level", хотя текст может быть любой. Я не стал заморачиваться с PDU, как в прошлый раз, для русского текста.
#include<EEPROM.h>//Подключим библиотеку для работы с EEPROM
#include<SoftwareSerial.h> //Подключим библиотеку для USART SoftwareSerial SIM900(7, 8); //Инициализируем софтовый USART
constint flashdel = 500;//для плавного мигания светодиодов constint addr1 = 101; //Адреса памяти для хранения информации constint addr2 = 102;//о том, записан ли номер в соответствующую ячейку constint addr3 = 103;//или нет constint led_1 = 9;//Светодиод первой ячейки памяти constint led_2 = 10;//второй constint led_3 = 11;//третьей constint power_led = 6; //Светодиод питания constint power_level = 13; //Питание датчика уровня constint contact = 12;//Сухой контакт constint level = 2; //Номер пина для детектора уровня constint button_1 = 3; //Кнопка записи/стирания первого номера constint button_2 = 4; //второго constint button_3 = 5; //третьего constint button_pins[] = {3, 4, 5}; //Массив номеров пинов кнопок constint led_pins[] = {9, 10, 11}; //Массив номеров пинов светодиодов char numtel[20]; //Переменные для номера телефона String NUMBER = ""; int Cell_1 = 0; //Ячейка первого символа первого номера int Cell_2 = 13; //второго int Cell_3 = 26; //третьего int numOk = 0; //Был считан номер int SMSNeed = 0; //Флаг того, что требуется отправка СМС int SMSSend = 1; //Флаг того, что СМС на все номера были отправлены int one, one_ = 0;//Флаги режимов записи int two, two_ = 0; int three, three_ = 0;
voidsetup() { //Serial.begin(9600);
SIM900.begin(9600); //заведем софтверный USART // EEPROM.write(addr1, 1); for (int x = 3; x <= 5; x++) { pinMode(x + 6, OUTPUT); //настроим пины светодиодов digitalWrite(x + 6, LOW); //x+6 это для удобства, так как pinMode(x, INPUT); // так как номера пинов кнопок и светодиодов отличаются на 6 digitalWrite(x, HIGH);
} digitalWrite(level, HIGH); pinMode(level, INPUT); pinMode(power_led, OUTPUT); pinMode(power_level, OUTPUT); pinMode(contact, OUTPUT); digitalWrite(power_led, LOW); digitalWrite(contact, HIGH); digitalWrite(power_level, HIGH); for (int i = 1; i <= 25; i++) { //для ожидания регистрации модема в сети
flash(power_led,1200); delay(200);
} //И зажжем светодиод вполсилы, так как он яркий
SIM900.print("AT+CMGF=1"); //Формат сообщений - текстовый
SIM900.println();//Enter delay(250);
SIM900.print("AT+CLIP=1"); //Отображать номер телефона входящего звонка
SIM900.println();//Enter delay(250); if (digitalRead(button_1) == 0) {//Если нажата кнопка 1 до загрузки основной программы EEPROM.write(addr1, 0); //забываем номер в ячейке 1
flash(led_1,1000);
} if (digitalRead(button_2) == 0) {//Если нажата кнопка 2 до загрузки основной программы EEPROM.write(addr2, 0);//забываем номер в ячейке 2
flash(led_2,1000);
} if (digitalRead(button_3) == 0) {//Если нажата кнопка 3 до загрузки основной программы EEPROM.write(addr3, 0);//забываем номер в ячейке 3
flash(led_3,1000);
} analogWrite(power_led, 100); //Зажжем белый светодиод вполсилы, так как он яркий delay(1000); digitalWrite(power_level, HIGH);//Подадим питание на плату измерения уровня
}
void readlevel() {// if (digitalRead(level) == HIGH ) {//Если обнаружено, что уровень ушел if (SMSSend == 0) {//Если СМС еще не были отправлены for (int i = 0; i <= 440; i++) {//Даем небольшую задержку - фильтр от колебаний воды
flash(power_led,flashdel);//и мигаем светодиодом в это время delay(20);
SMSNeed=1;// Требуется отправка СМС if (digitalRead(level) == LOW ) { //Если это просто колебания - выходим
SMSNeed=0; break; }
} if (SMSNeed == 1 ) { //Если уровень ушел все-таки digitalWrite(contact, LOW);//Включим реле
}
}
flash(power_led,flashdel);//а если смс уже были отправлены, то просто мигаем светодиодом
} else { for (int i = 0; i <= 2000; i++) { //Даем небольшую задержку - фильтр от колебаний воды analogWrite(power_led, 100); //и мигаем светодиодом в это время delay(20); if (digitalRead(level) == HIGH ) { //Если это просто колебания - выходим break;
}
} if (digitalRead(level) == LOW ) {//Если уровень в норме,
SMSNeed=0;//сбрасываем флаги
SMSSend=0;// digitalWrite(contact, HIGH);//Выключим реле
} analogWrite(power_led, 100); //И зажжем светодиод вполсилы, так как он яркий
}
}
void led_on_off() { //Если номер записан в соотв. ячейку, то включаем светодиод for (int i = 0; i <= 2; i++ ) { //Иначе - выключаем digitalWrite(led_pins[i], EEPROM.read(i + addr1)); //Последовательно отражаем состояние светодиодов
}
}
void readPort() { // Чтение всего, что приходит по программному последовательному порту String content = ""; //Создадим переменные char character; while (SIM900.available()) {//Пока что-то есть для приема
character=SIM900.read();//читаем if (character == ('+')) {//Пытаемся обнаружить номер
character=SIM900.read(); if (character == ('7')) { for (int i = 1; i <= 10; i++) {//И здесь его весь читаем в массив
numtel[i]=SIM900.read();
content.concat(numtel[i]);
numOk=1;//Номер считан
}
}
}
}
}
void sendSMS(String nomer, int led) { // Отправка сообщения
SIM900.println("AT + CMGS = \"+7" + nomer + "\""); // Получатель сообщения delay(500); //Задержка для стабильности
SIM900.println("Low water level."); // Сообщение для отправки delay(500); //Задержка для стабильности
SIM900.println((char)26); // Конец АТ-команды delay(500); //Задержка для стабильности
SIM900.println(); //Перевод каретки for (int i = 0; i <= 50; i++)
flash(led,100);// Время на отправку СМС
}
void writeNumber (int addr, char num[]) {//Запись считанного номера входящего звонка for (int i = 1; i < 11; i++) { char character = num[i]; EEPROM.write(addr, character); delay(10);
addr++;
}
}
char *readNumber (int addr) {//Процедура считывания номера из памяти staticchar num[11]; for (int i = 1; i <= 10; i++) { //Читаем 10 цифр номера без +7
num[i]=EEPROM.read(addr);
addr++;
} return num; //Возвращаем номер в массиве символов
}
//Процедура плавного мигания указанным светодиодом void flash(int chan, int delay_) { for (int z = 0; z <= 150; z++) { //В эту процедуру мы передаем два параметра analogWrite(chan, z); delayMicroseconds(delay_); //канал, которым надо мигнуть и время мигания
} for (int z = 150; z >= 0; z-- ) { analogWrite(chan, z); delayMicroseconds(delay_);
} delay(100);
}
void resetCall() {
SIM900.println("AT+CHUP");// Положим трубку
} voidloop()
{ if (one == 0 || two == 0 || three == 0)
led_on_off();//Если не нажата ни одна кнопка, зажигаем светодиод если // в соответствующей ячейке записан номер телефона if (one != 1 && two != 1 && three != 1)
readlevel();//Проверим уровень воды в баке
if (digitalRead(button_1) == LOW) { //Если нажата кнопка № 1
one_=1;//Включим режим записи номера
} elseif (digitalRead(button_2) == LOW) { //Если нажата кнопка № 2
two_=1;//Включим режим записи номера
} elseif (digitalRead(button_3) == LOW) { //Если нажата кнопка № 3
three_=1;//Включим режим записи номера
} if (one_ == 1 && digitalRead(button_1) == HIGH) { if (one == 0) {
one=1;//Флаг режима записи первого номера включен
two=0;//Остальные выключим
three=0;
} else
one=0;
one_=0;//Выйдем из режима
} if (two_ == 1 && digitalRead(button_2) == HIGH) { if (two == 0) {
two=1;//Флаг режима записи второго номера включен
one=0;//Остальные выключим
three=0;
} else
two=0;//
two_=0;//Выйдем из режима
} if (three_ == 1 && digitalRead(button_3) == HIGH) { if (three == 0) {
three=1;//Флаг режима записи третьего номера включен
one=0;//Остальные выключим
two=0;
} else
three=0;
three_=0;//Выйдем из режима
} if (one == 1) {
flash(led_1,flashdel);//Мигаем светодиодом, показывая, что включен режим записи первой ячейки
readPort();//Прочитаем порт модема на предмет входящего звонка if (numOk == 1) { if (EEPROM.read(addr1) == 0) {//если в первой ячейке нет номера, то
writeNumber(Cell_1,numtel);//записываем номер входящего звонка в первую ячейку EEPROM.write(addr1, 1); //Запишем 1 по адресу addr1, указывая на то, что первый номер записан for (int i = 0; i <= 4; i++) {
flash(led_1,flashdel);//Пауза чтобы чел услышал гудок
}
resetCall();// Положим трубку
numOk=0;
one=0;
}
}
} if (two == 1) {
flash(led_2,flashdel);//Мигаем светодиодом, показывая, что включен режим записи второй ячейки
readPort();//Прочитаем порт модема на предмет входящего звонка if (numOk == 1) { if (EEPROM.read(addr2) == 0) {//если во второй ячейке нет номера, то
writeNumber(Cell_2,numtel);//записываем номер входящего звонка во вторую ячейку EEPROM.write(addr2, 1); //Запишем 1 по адресу addr2, указывая на то, что второй номер записан for (int i = 0; i <= 4; i++) {
flash(led_2,flashdel);//Пауза чтобы чел услышал гудок
}
resetCall();// Положим трубку
numOk=0;
two=0;
}
}
} if (three == 1) {
flash(led_3,flashdel);//Мигаем светодиодом, показывая, что включен режим записи третьей ячейки
readPort();//Прочитаем порт модема на предмет входящего звонка if (numOk == 1) { if (EEPROM.read(addr3) == 0) {//если в третьей ячейке нет номера, то
writeNumber(Cell_3,numtel);//записываем номер входящего звонка в третью ячейку EEPROM.write(addr3, 1); //Запишем 1 по адресу addr3, указывая на то, что третий номер записан for (int i = 0; i <= 4; i++) {
flash(led_3,flashdel);//Пауза чтобы чел услышал гудок
}
resetCall();// Положим трубку
numOk=0;
three=0;
}
}
} if (SMSNeed == 1 && SMSSend == 0) { //Если требуется отправка СМС при низком уровне char *num; int timer = 0; if (EEPROM.read(addr1) == 1) { //Если в первую ячейку записан номер телефона
num=readNumber(Cell_1); for (int i = 1; i <= 10; i++) {
NUMBER=NUMBER+num[i];//Вычисляем номер телефона в строковую переменную
}
sendSMS(NUMBER,led_1);
NUMBER="";
} if (EEPROM.read(addr2) == 1) { //Если в первую ячейку записан номер телефона
num=readNumber(Cell_2); for (int i = 1; i <= 10; i++) {
NUMBER=NUMBER+num[i];//Вычисляем номер телефона в строковую переменную
}
sendSMS(NUMBER,led_2);
NUMBER="";
} if (EEPROM.read(addr3) == 1) { //Если в первую ячейку записан номер телефона
num=readNumber(Cell_3); for (int i = 1; i <= 10; i++) {
NUMBER=NUMBER+num[i];//Вычисляем номер телефона в строковую переменную
}
sendSMS(NUMBER,led_3);
NUMBER="";
}
SMSNeed=0;//Все, отправка не требуется, так как уже было сделано
SMSSend=1;//Разрешаем повторную отправку после появления воды
}
}
Так прибор выглядит снаружи и внутри:
Ну в общем, как-то так.. Прибор уже эксплуатируется. Я разместил на нашем сайте информацию. Так, для ознакомления Комментарии приветствуются.
В данном каталоге https://actualtraffic.ru представлено более 900 партнерских программ и сервисов для вебмастеров с отзывами пользователей и обзором функционала. Воспользуйтесь формой ниже для быстрого поиска нужной вам партнерской сети.
Да, собственно, ни при чём. Но почему бы и нет? Тем более, проект picbasic.ru уже давно перерос во что-то большее. Например, stm32 - это тоже не pic, но его можно программить на бейсике, как и atmel. Не так ли? Тем более, об этом просили сами пользователи. Просто название менять никто не будет. Все же basic для pic остаётся главной темой сайта.
По прошествии некоторого времени пришлось переработать и схему и программу. В данный момент программа новая. Дело было в том, что, как я выяснил, внутренние подтягивающие резисторы микроконтроллеров Atmel - 20 кОм. Вся проблема, таким образом, заключалась в наводках на электродах, так как 20 кОм - слишком много. Прибор ловил помехи и давал ложные срабатывания, отправляя ненужные смс. Вопрос решился внешней подтяжкой 7 кОм (был под рукой) и выкидыванием платы уровня, так как операционник усиливал сигнал помехи. Теперь 1 электрод - это 0В, а второй электрод - непосредственно вход контроллера, настроенный на вход и подтянутый к плюсу питания через 7 кОм. Работает отлично.
Добавлять комментарии могут только зарегистрированные пользователи. [ Регистрация | Вход ]