PDA

Просмотр полной версии : Работа ПЛК и модем (SIEMENS M35i)



deniska13
27.01.2010, 20:32
Вот решил освоить работу ПЛК с модемами, вроде разобрался как работать с портом, с настройками, чтением и записью. Но вот с модемом ничего не выходит, при отправке ему любой АТ команды, модем отвечает "$R" не могу понять почему, подскажите как программно работать с модемом, если вас не затруднит поясните как работает ваша программа, которую я здесь скачал. Основная часть в принципе понятна, но лучше если полностью мне кто нибудь пояснить саму суть. По Гипер Терминалу модем все прекрасно понимает, отвечает на АТ команды. Подключал так же ПЛК - ПК - Модем, контроллер по изменению переменной отправлял АТ команду, в гипер терминале я ее увидел, так же контроллер принимает данные отправленные с гипер терминала, а модем ничего не видит, думал что то с кабелем, но нет, скорее всего я где то в программе допускаю ошибку, мне кажется что неправильно принимаю данные, подскажите как именно это делается?

FUNCTION_BLOCK GSM_Modem_SMS
VAR_INPUT
com_num:PORTS:=COM1; (*Номер порта для работы с модемом*)
phone_num:STRING; (*Телефонный номер для посылки смс*)
send_SMS_text:STRING(255); (*Строка для отправки по указанному номеру шлем если не пустая*)
rcvSMS:BOOL:=FALSE; (*Флаг необходимости проверки SMS*)
use_unicode: BOOL := FALSE; (* Использование кодовой таблицы - юникод - ограничение на сообщ - 21 символ*)
END_VAR
VAR_OUTPUT
rcvedSMS:STRING(255); (*Полученное СМС*)
rcvedPhonNum:STRING(20); (*Телефон с которого отправлено SMS*)
rcvedTm:STRING(25); (* Время отправки*)
sended_OK:BOOL; (*Признак отправки СМС*)
END_VAR
VAR
port_opened: BOOL := FALSE; (*Признак открытия порта*)
com_handle: DWORD;
init_stage:BYTE:=0; (*Стадия инициализации*)
db:DecodeBuf;
(*Буфферы для обмена*)
rcvBUF: ARRAY [0..1023] OF BYTE;
rcvStr:STRING(255);
snd_str:STRING(255);


iter: DWORD;
com_set: COMSETTINGS;


(*Комманда чтения СМС*)
strTakeNewSMS:STRING:='AT+CNMI=1,1$R';
strGetNewSMS:STRING:='+CMTI: ';
strSetCharSetUC:STRING:='AT+CSCS="UCS2"$R'; (* Формат UNICODE*)
strSetCharSet8B:STRING:='AT+CSCS="GSM"$R'; (* Формат UNICODE*)
strSetMsgMode:STRING:='AT+CMGF=0$R'; (* Использовать !НЕ! Text Mode!! А __PDU__*)
strGetNewMsg:STRING:='AT+CMGR=';
strGetDelMsg:STRING:='AT+CMGD=';
strGetAllMsg:STRING:='AT+CMGL=1$R';
strSMS_num:STRING(20);

do_send_sms2: BOOL := FALSE;
sz: DWORD := 0;
a_char: POINTER TO STRING;
do_rcv_sms2: BOOL := FALSE;
port_init:BOOL:=FALSE;
res:BOOL;

(*Таймеры ожидания для работы*)
tmr_rcv_wait:TON;
tmr_snd_wait:TON;
tmr_rq_wait:TON;
(* Number out*)

NUMBER_OUT: STRING(20);
I: BYTE;
PACKET:STRING(255);
uc_sms_text:STRING(255);

sms_c:STRING(255);
END_VAR

:confused:

(*Открываем порт*)
IF NOT port_opened THEN
com_handle:=SysComOpen(com_num);
IF com_handle<>16#FFFFFFFF THEN
port_init:=TRUE;
ELSE
SysComClose( com_num);
com_handle:=SysComOpen( com_num);
port_init:=TRUE;
END_IF

(*Настраиваем скорость*)
com_set.Port:=com_num;
com_set.dwBaudRate:=9600;
com_set.byParity:=0;
com_set.dwTimeout:=0;
com_set.byStopBits:=0; (* *)
com_set.dwBufferSize:=0;
com_set.dwScan:=0;
res:=SysComSetSettings(com_num,ADR(com_set));
(*Успешно открыли*)
IF NOT res THEN
port_opened:=TRUE;
END_IF
(* Установка PDU*)
SysComWrite(com_num,ADR(strSetMsgMode),LEN(strSetM sgMode),0);
rcvstr:='';
END_IF

IF init_stage<2 THEN (* Ожидание настройки PDU*)
tmr_rq_wait(in:=(init_stage=1),PT:=t#3s);
init_stage:=1;
sz:=SysComRead(com_num,ADR(rcvBUF),1024,0);
IF sz>0 THEN (*Что то приняли*)
FOR iter:=0 TO sz-1 DO
a_char:=ADR(rcvBuf[iter]);
rcvStr:=CONCAT(rcvStr,LEFT(a_char^,1) );
IF LEN(rcvStr)>250 THEN
rcvStr:=DELETE(rcvStr,1,1);
END_IF
END_FOR
END_IF
IF FIND(rcvStr,'OK')<>0 THEN
init_stage:=2;
(*Инициализация успешна шлем CharSet*)
IF use_unicode THEN
SysComWrite(com_num,ADR(strSetCharSetUC),LEN(strSe tCharSetUC),0);
ELSE
SysComWrite(com_num,ADR(strSetCharSet8B),LEN(strSe tCharSet8B),0);
END_IF
rcvstr:='';
END_IF
IF tmr_rq_wait.Q THEN (*Недождались - переиниц-ая*)
init_stage:=0;
port_init:=FALSE;
END_IF
RETURN;
END_IF

IF init_stage>1 AND init_stage<4 THEN (* Ожидание настройки CSCS*)
tmr_rq_wait(in:=(init_stage=3),PT:=t#3s);
init_stage:=3;
sz:=SysComRead(com_num,ADR(rcvBUF),1024,0);
IF sz>0 THEN (*Что то приняли*)
FOR iter:=0 TO sz-1 DO
a_char:=ADR(rcvBuf[iter]);
rcvStr:=CONCAT(rcvStr,LEFT(a_char^,1) );
IF LEN(rcvStr)>250 THEN
rcvStr:=DELETE(rcvStr,1,1);
END_IF
END_FOR
END_IF
IF FIND(rcvStr,'OK')<>0 THEN
init_stage:=4;
(*Инициализация успешна*)
rcvstr:='';
SysComWrite(com_num,ADR(strTakeNewSMS),LEN(strTake NewSMS),0);
END_IF
IF tmr_rq_wait.Q THEN (*Недождались - переиниц-ая*)
init_stage:=0;
port_init:=FALSE;
END_IF
RETURN;
END_IF

IF init_stage>3 AND init_stage<6 THEN

tmr_rq_wait(in:=(init_stage=4),PT:=t#3s);
init_stage:=5;
sz:=SysComRead(com_num,ADR(rcvBUF),1024,0);

IF sz>0 THEN (*Что то приняли*)
FOR iter:=0 TO sz-1 DO
a_char:=ADR(rcvBuf[iter]);
rcvStr:=CONCAT(rcvStr,LEFT(a_char^,1) );
IF LEN(rcvStr)>250 THEN
rcvStr:=DELETE(rcvStr,1,1);
END_IF
END_FOR
END_IF

IF FIND(rcvStr,'OK')<>0 THEN
init_stage:=6;
(*Инициализация успешна*)
rcvstr:='';
END_IF

IF tmr_rq_wait.Q THEN (*Недождались - переиниц-ая*)
init_stage:=0;
port_init:=FALSE;
END_IF
RETURN;
END_IF


(*Взводим таймер если надо*)
tmr_snd_wait(IN:=LEN(send_SMS_text)>0 AND do_send_sms2,PT:=t#5s);

(*Если таймер сработал больше не ждем ответа от модема*)
IF tmr_snd_wait.Q THEN
do_send_sms2:=FALSE;
tmr_snd_wait(IN:=LEN(send_SMS_text)>0 AND do_send_sms2,PT:=t#5s);
rcvStr:='';
END_IF

(*Начинаем посылку*)
sended_OK:=FALSE;
(*Если нужно послать СМС*)
IF LEN(send_SMS_text)>0 AND NOT do_send_sms2 THEN
NUMBER_OUT:='';
FOR I:=1 TO 10 DO
IF (I MOD 2)<>0 THEN
NUMBER_OUT:=CONCAT(NUMBER_OUT,MID(phone_num,1,I+1) );
ELSIF (I MOD 2)=0 THEN
NUMBER_OUT:=CONCAT(NUMBER_OUT,MID(phone_num,1,I-1));
END_IF
END_FOR

NUMBER_OUT:=CONCAT(NUMBER_OUT, 'F');
NUMBER_OUT:=CONCAT(NUMBER_OUT, MID(phone_num,1,11));

PACKET:='0001000B91'; (*SCA =00 PDU=01 MR=00*)
PACKET:=CONCAT(PACKET,NUMBER_OUT);

IF use_unicode THEN

PACKET:=CONCAT(PACKET,'0008'); (*PID 00(обычн смс) = DCS=06(кодовая схема - полный UCS2)*)

IF LEN(send_sms_text)>69 THEN (*Обрезаем строку до 70*)
send_sms_text:=LEFT(send_sms_text,69);
END_IF
uc_sms_text:=CP1251_TO_UTF8oct(send_sms_text);
ELSE
(* 0001000B919762527348F500040E *)

PACKET:=CONCAT(PACKET,'0004'); (*PID 00(обычн смс) = DCS=04(кодовая схема - 8 битовое)*)
IF LEN(send_sms_text)>159 THEN (*Обрезаем строку до 255 символов*)
send_sms_text:=LEFT(send_sms_text,159);
END_IF
uc_sms_text:=CP1251_TO_Octets(send_sms_text);

END_IF

uc_sms_text:=CONCAT(uc_sms_text,'$1A');
IF use_unicode THEN
I:=INT_TO_BYTE(LEN(send_sms_text)*2);
ELSE
I:=INT_TO_BYTE(LEN(send_sms_text));
END_IF
PACKET:=CONCAT(PACKET,tetr2hex[SHR(I,4)]);
PACKET:=CONCAT(PACKET,tetr2hex[I AND 16#F]);

snd_str:=CONCAT('AT+CMGS=',INT_TO_STRING((LEN(PACK ET)/2)-1+I));
snd_str:=CONCAT(snd_str,'$R');

SysComWrite(com_num,ADR(snd_str),LEN(snd_str),0);

rcvStr:='';

(*Ждать ответа от модема*)
do_send_sms2:=TRUE;

END_IF

(*
(*Таймер ожидания получения*)
tmr_rcv_wait(IN:=do_rcv_sms2,PT:=t#5s);
IF tmr_rcv_wait.Q THEN
do_rcv_sms2:=FALSE;
SysComWrite(com_num,ADR(strSetDelivRep),LEN(strSet DelivRep),0);
tmr_rcv_wait(IN:=do_rcv_sms2,PT:=t#5s);
rcvStr:='';
END_IF
*)

(*Если нужно получить ответ от модема*)
IF rcvSMS AND NOT do_send_sms2 AND NOT do_rcv_sms2 THEN
rcvStr:='';
do_rcv_sms2:=TRUE;
END_IF

(*Получаем данные из порта*)
sz:=SysComRead(com_num,ADR(rcvBUF[0]),20,0);
(*Таймер получения ответа от модема -2 секунды*)
IF LEN(rcvStr)=0 THEN
tmr_rq_wait(IN:=FALSE,PT:=t#2s);
ELSE
tmr_rq_wait(IN:=TRUE,PT:=t#2s);
END_IF
IF sz<>0 THEN

FOR iter:=0 TO sz-1 DO
a_char:=ADR(rcvBuf[iter]);
rcvStr:=CONCAT(rcvStr,LEFT(a_char^,1) );
IF LEN(rcvStr)>250 THEN
rcvStr:=DELETE(rcvStr,1,1);
END_IF
END_FOR

IF do_send_sms2 THEN
(*При посылке СМС ожидаем готовности модема знак >*)
IF FIND(rcvStr,'>') <> 0 THEN
(*Шлем SMS*)
SysComWrite(com_num,ADR(PACKET),LEN(PACKET),0);
SysComWrite(com_num,ADR(uc_sms_text),LEN(uc_sms_te xt),0);
i:=16#1A;
SysComWrite(com_num,ADR(i),1,0);
do_send_sms2:=FALSE;
(*СМС Послано*)
sended_OK:=TRUE;
END_IF
END_IF
END_IF
(*Если прием СМС*)
IF do_rcv_sms2 AND tmr_rq_wait.q THEN
(*Если ждем эхо*)

IF FIND(rcvStr,strGetNewSMS) <> 0 THEN
rcvStr:=DELETE(rcvStr,FIND(rcvStr,strGetNewSMS) +LEN(strGetNewSMS)+1,1);
WHILE (LEFT(rcvStr,1)<>',') DO
rcvStr:=DELETE(rcvStr,1,1);
END_WHILE
rcvStr:=DELETE(rcvStr,1,1);
strSMS_num:=rcvStr;
rcvStr:=CONCAT(strGetNewMsg,rcvSTR);

SysComWrite(com_num,ADR(rcvSTR),LEN(rcvSTR),0);

rcvStr:='';
END_IF

(*Начато тел. номера из россии это +7 *)
IF FIND(rcvStr,'+CMGR: ')<>0 THEN

rcvStr:=DELETE(rcvStr,FIND(rcvStr,'$0A') ,1);
rcvStr:=DELETE(rcvStr,FIND(rcvStr,'$0A') ,1);
(*СМС ограничено переводами строк*)
DB(pBuf:=ADR(rcvStr),str_sender=>rcvedPhonNum,str_time=>rcvedTm,str_message=>rcvedSMS);

rcvStr:=CONCAT(strGetDelMsg,strSMS_num);
SysComWrite(com_num,ADR(rcvSTR),LEN(rcvSTR),0);
rcvStr:='';
END_IF

rcvStr:='';

END_IF

Jeck
27.01.2010, 21:27
deniska13, ставьте точки останова и смотрите как работает

lara197a
27.01.2010, 21:46
Этот пример выложенн на диске входящем в ПЛК
Проверено все работает.
Смотрите,читайте и пользуйтесь.

Дмитрий Артюховский
28.01.2010, 21:09
Пример, кстати, фигово работает ))) Основная проблема в работе с модемом - это понимание принципа "сканирующего выполнения", т.е. то что весь текст программы пробегается каждую миллисекунду. Это вызывает большие трудности в синхронизации и обеспечении последовательностей выполнения функций.
Когда нужно обеспечить строгую последовательность обмена лучше использовать конструкции CASE ... тогда видно в каком месте нахродиться диалог с модемом. А плохая работа примера объясняется не полной инициализацией модема перед обменом и отсутствием способа выходить из ошибок.... Очень часто модему что-то не понравиться и он ответит "ERROR"... и будет так отвечать до выключения питания )))

deniska13
28.01.2010, 22:40
у меня этот пример не работает в том то и дело, как только я загружаю программу в контроллер, при нажатии Run он перезагружается, причем загорается лампа "работа" и при этом он вообще не "дышит" если замкнуть один из входов то соответствующая лампа не светится, приходится его снова перегружать и заливать программу снова, ну и так по кругу)...

Денис
29.01.2010, 08:22
Извините, если не в тему, но у меня тоже проблема при работе плк100 и указанного терминала - не принимает SMS. Через гиппертерминал AT командой +CMGD= удаляю SMS из памяти SIM карты - и пример работает и принимает и отправляет SMS. Однако работает только пока не заполнится память SIM - 25 сообщений. Если кто сталкивался - подскажите какой параметр терминала нужно изменить, чтобы он работал независимо от заполненности памяти?

Ден
16.02.2010, 14:36
Здравствуйте!
Пожалуйста выложите здесь последнюю версию примера sms_send_seample.pro. Буду очень признателен.

Capiton
05.05.2011, 10:49
Здравствуйте. Разложил всю программу на косточки и натолкнулся на такую проблему не как не могу понято что означает rcvStr:="; просмотрел справку так и не нашел может кто подскажет.

Леонид
05.05.2011, 13:50
Рассматривал пример работы с модемом и наткнулся на

IF FIND(rcvStr,strGetNewSMS) <> 0 THEN
rcvStr:=DELETE(rcvStr,FIND(rcvStr,strGetNewSMS) +LEN(strGetNewSMS)+1,1);
WHILE (LEFT(rcvStr,1)<>',') DO
rcvStr:=DELETE(rcvStr,1,1);
END_WHILE

И тут возник вопрос по поводу цикла WHILE
Может ли этот цикл работать в ПЛК?
Я по рекомендациям форума исспользую его для перезагрузки плк при отключении питания, чтоб контроллер не работал от аккумулятора.

Николаев Андрей
05.05.2011, 14:06
Если Вы его использовали - значит может. :)
Для перезагрузки он специально вводится в "не правильные условия".
Надо просто четко понимать как он работает. И особо важно понимать, что If While и прочие команды в ПЛК работают ПО ДРУГОМУ, нежели на ПК.