(23 Aralık 2017 tarihli picproje.org adresindeki yazımdan alıntıdır.)
Merhaba.
Şimdi fırsat buldukça CCS C ve Pic ile ilgili öğrendiklerimi konu başlıkları halinde paylaşmaya çalışacağım. PIC ve GSM Modül arasında iletişimin donanım detayına çok fazla girmeden yazılım kısmında PIC ve GL865 harici donanım projelerinde de kullanılabilecek kodlar paylaşmaya çalışacağım.
Bu kodun yapı örneğini benimle paylaşan İzmir'de ikamet eden sevgili dostum Aykut ULUSAN'a da buradan teşekkürü borç bilirim.
Öncelikle PIC ve GL865 Modül uart üzerinde 115200 baudrate ile haberleşiyor.
PIC tarafından GSM'e veri göndermek için bir çok komut var.
Bunları:
Şebeke ile ilgili olanlar
SMS ile ilgili olanlar
GPRS ile ilgili olanlar
SES araması ile ilgili olanlar
GSM Modül ile ilgili donanımsal olanlar diye gruplayabiliriz.
Bu komutları bazen tek AT\r\n gibi
bazen de AT+FCLASS=8 gibi değişen parametrelerle gönderiyoruz.
İlk önce komut yapısında structure ve enum tanımı yapılması hem komutların gönderimi hem de anlaşılması için gereklidir.
Çünkü her bölümde fprintf(port,"ATxxxxx%s=%c"param1,param2) gibi komut gönderimi çok uygun değildir.
enum state{
OK,
CONNECT,
RING,
NO_CARRIER,
ERROR,
CONNECT_1200,
NO_DIALTONE,
NO_ANSWER,
BUSY,
};
şeklinde bir enum tanımladım.
Bu yapı sayesinde 0 yerine OK, 1 yerine CONNECT kullanabileceğim
Aşağıdaki max_my_modem_response_char ile maksimum 15 karakter atayacağım bir değişken tanımlıyorum.
response_nr ile de 12 tane komut tanımlayacağımı belirtiyorum.
yapının içinde bir sayı ve bir text bulunuyor.
Text için gelen cevap yada göndereceğim komut textini aktarıyorum.
#define max_my_modem_response_char 15 //dönen modem cevabı için max char size
#define response_nr 12
//dönen cevap sayısı
typedef struct my_modem_response{
u8 cmd;
char response[max_my_modem_response_char];
}my_mdm_resp;
Bu kısımda da tanımladığım değişkenlere değerleri aktarıyorum.
my_mdm_resp const mdm_resp[response_nr]={
OK,{"OK"},
CONNECT,{"CONNECT"},
RING,{"RING"},
NO_CARRIER,{"NO_CARRIER"},
ERROR,{"ERROR"},
CONNECT_1200,{"CONNECT_1200"},
NO_DIALTONE,{"NO_DIALTONE"},
NO_ANSWER,{"NO_ANSWER"},
BUSY,{"BUSY"},
EMPTY,0,
};
Programlamaya yeni başlayan arkadaşlar şimdi ne gerek var bu kadar koda ben fprintf ile yazar geçerim diyecekler.
Ama bir süre sonra uzun programlar yazmaya başladıklarında saç baş yolmaya başlayacaklardır.
Bu yüzden hem anlaşılır hem de kullanışlı kod yazmak, iyi bir alışkanlıktır.
Aynı yapıyı aşağıda GSM komut kütüphanesi için de kuralım kullanım detaylarına bakalım.
//Komutlar için struct
enum{
eAT, //0
eAT_FCLASS8,
eAT_MONI,
eAT_CREG,
eATD,
eATH,
eATE0,
eATV0,
eAT_IPR,
eAT_CLIP1,
eAT_CLIR1,
eAT_CLIR0,
eAT_CGCLASS_B,
eAT_CGCLASS_CG,
eAT_CGCLASS_CC,
eAT_CGATT0,
eAT_CGATT1,
eAT_CGREG,
eAT_CGDCONT,
eAT_CSCA,
eAT_CMGF1,
eAT_CNMI21,
eAT_CMGS,
eAT_GPRS0,
eAT_GPRS1,
eAT_SLED2,
eAT_GPIO12, //Simkart kontrolü için GPIO
eAT_K0,
eAT_USERID,
eAT_PASSW,
eAT_SD,
eAT_GPRS,
e3plus,
};
#define RESPONSE_MAX_CHAR 55
#define CMD_NUMBER 40 // yukarıda 40 tane modem komutu var
typedef struct my_command_type{
u8 Cmd; // enum içindeki komutları tutar (gönderdiğin veya cevap alacağın komutun ne olduğunu buradan anlarsın)
vu16 Timeout; // her komutun timeout'u için kullanılır
vu8 ModemData[RESPONSE_MAX_CHAR]; // modemden gelen veya gidecek data, interrupt içinde usarttan bu buffer'a kopyalancağından volatile yaptım
vu8 lcd_data[RESPONSE_MAX_CHAR];
// herşeyi buraya ekleyebilirsin
}MyModemStruct_Typedef;
MyModemStruct_Typedef const SendCmdDefaults[CMD_NUMBER]={
eAT, 10,{"AT\r\n"},{"AT"},
eAT_FCLASS8, 10,{"AT+FCLASS=8\r\n"},{"AT+FCLASS=8"}, // bu komut için 1000*10ms=10sn timeout koydum
eAT_MONI, 150,{"AT#MONI\r\n"},{"AT#MONI"},
eAT_CREG,150,{"AT+CREG?\r\n"},{"AT+CREG"},
eATD, 100,{"ATD"},{"ATD"},
eATH, 100,{"ATH\r\n"},{"ATH"},
eATE0, 10,{"ATE0\r\n"},{"ATE0"},
eATV0, 10,{"ATV0\r\n"},{"ATV0"},
eAT_IPR, 10,{"AT+IPR="},{"AT+IPR="},
eAT_CLIP1, 10,{"AT+CLIP=1\r\n"},{"AT+CLIP=1"},
eAT_CLIR1, 10,{"AT+CLIR=1\r\n"},{"AT+CLIR=1"},
eAT_CLIR0, 10,{"AT+CLIR=0\r\n"},{"AT+CLIR=0"},
eAT_CGCLASS_B, 500,{"AT+CGCLASS=B\r\n"},{"AT+CGCLASS=B"},
eAT_CGCLASS_CG, 500,{"AT+CGCLASS=CG\r\n"},{"AT+CGCLASS=CG"},
eAT_CGCLASS_CC, 500,{"AT+CGCLASS=CC\r\n"},{"AT+CGCLASS=CC"},
eAT_CGATT0, 500,{"AT+CGCATT=0\r\n"},{"AT+CGCATT=0"},
eAT_CGATT1, 500,{"AT+CGCATT=1\r\n"},{"AT+CGCATT=1"},
eAT_CGREG, 500,{"AT+CREG"},{"AT+CREG"},
eAT_CGDCONT, 500,{"AT+CGDCONT=1,""IP"",""internet"",""0.0.0.0"",0,0\r\n"},{"AT+CGDCONT=1,""IP"",""internet"",""0.0.0.0"",0,0"},
eAT_CSCA, 10,{"ATCSCA="},{"ATCSCA="},
eAT_CMGF1, 10,{"AT+CMGF=1\r\n"},{"AT+CMGF=1"},
eAT_CNMI21, 10,{"AT+CNMI=2,1\r\n"},{"AT+CNMI=2,1"},
eAT_CMGS, 10,{"AT+CMGS=0\r\n"},{"AT+CMGS=0"},
eAT_GPRS0, 50,{"AT#GPRS=0\r\n"},{"AT#GPRS=0"},
eAT_GPRS1, 150,{"AT#GPRS=1\r\n"},{"AT#GPRS=1"},
eAT_SLED2, 10,{"AT#SLED=2\r\n"},{"AT#SLED=2"},
eAT_GPIO12,10,{"AT#GPIO=1,2\r\n"},{"AT#GPIO=1,2"}, //Simkart kontrolü için GPIO
eAT_K0,10,{"AT&K0\r\n"},{"AT&K0"},
eAT_USERID,10,{"AT#USERID=""""\r\n"},{"AT#USERID="""""}, //GPRS USERID
eAT_PASSW,10,{"AT#PASSW=""""\r\n"},{"AT#PASSW="""""}, //GPRS PASSWORD
eAT_SD,250,{"AT#SD=1,0,80,"},{"AT#SD=1,0,80,"}, //Socket Dial
eAT_GPRS,250,{"AT#GPRS?\r\n"},{"AT#GPRS?"},
e3plus,1000,{"+++"},{"+++"}
};
Yukarıdaki kodları iyi okuyanların şimdi gülümsediğini görür gibiyim. Yukarıdaki yapıda timeout isminde bir değişken daha tanımlı.
Bu değişken her komut için ayrı ayrı süreleri tutuyor.
AT için timeout 0.1 saniye ise AT#GPRS için 250sn
Kütüphanenein en büyük güzelliği burda.
Komutu gönder cevap gelene kadar timeout kadar bekle.
Eğer cevap gelirse beklemeyi bitir. Cevap gelmezse Timeout ver çık ;D ;D
Bir de GPRS ile bağlanacağımız adresleri ve yapıları tanımlayalım.
//gprsle bağlanılacak web adresleri
enum enum_web_addr{
IP,
IP2,
connection_close,
connection_keep_alive,
gsm_timetable,
t_sync,
defect_add,
get_sub_terminal,
};
#define max_addr_length 50 //dönen modem cevabı için max char size
#define piece_of_web_addr 10
//dönen cevap sayısı
typedef struct my_gprs_modem_response{
u8 cmd;
char web_addr_str[max_addr_length];
}my_web_addr;
my_web_addr const web_addr[piece_of_web_addr]={
IP,{"xxx.xxx.xxx.xxx "}, //Noktalarla ayrılmış şekilde IP adresi yazılacak
IP2,{"xxx.xxx.xxx.xxx"}, //GSM Modüllerin sadece gerçek IP adreslerine çağrı yapabildiğini yani dedicated server kullanmanız gerektiğini unutmayın.
connection_close,{"Connection: Close\r\n\r\n"},
connection_keep_alive,{"Connection: Keep-Alive\r\n\r\n"},
gsm_timetable,{"GET /timetable.aspx?dev="},
t_sync,{"GET /time_sync.aspx?dev="},
defect_add,{"GET /defect_add.aspx?dev="},
get_sub_terminal,{"GET /get_sub_terminal.aspx?dev="}
};
Yukardaki kodarın çağrı yaptığı site şu anda aktif olmadığı için kodları aynen yayınlamakta bir sakınca görmüyorum.
Kullanım detaylarına bakacak olursak;
GSM Modüllerin sadece gerçek IP adreslerine çağrı yapabildiğini yani dedicated server kullanmanız gerektiğini unutmayın.
Uart tanımı
#pin_select U3TX=PIN_G7
#pin_select U3RX=PIN_G6
#use rs232(UART3, baud=115200, stream=gsm_comm)
şeklinde yapıldı.
gsm_comm GSM Modülün bağlandığı uart portunun adıdır.
İlk önce cevap_bekle'yi tanımlıyorum.
void cevap_bekle(u16 sure)
{
u16 sayac=0;
do{
bekle(100);
sayac++;
fprintf(Comm1,"sayac:%u\r\n"sayac);
}while((!(sayac>sure)&&(gsm_interrupt!=1))&&(sayac<1000)); //Buraya dikkat karşılaştırmada hata
if ((sayac==sure)||(sayac>sure))
{
fprintf(Comm1,"timeout\r\n"); //ilerde burası kapatılacak
gsm_cmd_timeout=1;
}
if (gsm_response_state!=EMPTY)
{
// fprintf(Comm1,"RDA interrupt\r\n"); //ilerde burası kapatılacak
gsm_cmd_timeout=0;
}
if(sayac>1000)
{
fprintf(Comm1,"Sayac exceeded\r\n"); // sayac saçmalarsa
}
gsm_interrupt=0;
}
Burada yukarıda bahsettiğim timeout değişkeni hayati öneme sahip. komutu gönderdim.
3 ihtimal var. Komuta OK cevbı geldi, Komuta ERROR cevabı geldi. Komuta cevap gelmedi, timeout oluştu. her komutun timeout süresini daha önce tanımladığım için şimdi sadece komutun adını yazmam yeterli. Kodlamayı seviyorum:)
Aşağıda komut gönderme yapısına bakalım.
void send_cmd(u8 cmd)
{
is_ok=0;
is_0=0;
send_next=0;
gsm_response_state=EMPTY; //komut göndermeden önce daha önceki kalan response state'le karışma olmasın diye boşalt
[color=red]fprintf(gsm_comm,"%s"sendcmddefaults[cmd].modemdata);[/color]
[color=yellow]fprintf(comm1,"\r\n%s\r\n"sendcmddefaults[cmd].modemdata);[/color]
cevap_bekle(sendcmddefaults[cmd].Timeout);
// adres(1,1);
//printf(lcd_yaz,"%s"sendcmddefaults[cmd].lcd_data);
}
void send_cmd_wo_wait(u8 cmd)
{
fprintf(gsm_comm,"%s"sendcmddefaults[cmd].modemdata);
}
fprintf(gsm_comm,"%s"sendcmddefaults[cmd].modemdata); satırı ile komutu gönderdim ama herşey daha yeni başlıyor.
send_cmd(eAT); yazmam bu komutu göndermem ve maksimum timeout süresi kadar beklemem için yeterli.
kütüphanenin timeout gerçekleşince yapılacaklar kısmını yazmadım. cevap_bekle() kütüphanesinde timeout kısmına istenen kodlar ihtiyaca göre yazılabilir.
kütüphaneyi okurken bekle, hi_x, gibi CCs kütüphanede olmayan komutlar var. aslında tanıdık gelecektir.
#define bekle(x) delay_ms(x)
#define bekle_ss(x) delay_ms(x)
#define bekle_us(x) delay_us(x)
#define hi_x(x) output_high(x)
#define lo_x(x) output_low(x)
#define x_to(x,y) output_bit(x,y)
sanırım kodları anlamada daha yardımcı olur.
const u8 t_mini=1;
const u8 t_short=50;
const u8 t_medium=250;
const u16 t_long=1000;
tanımlaması da kod yazma esnasında iş görür.
bekle(t_mini); hem sonradan değiştirilebilir hem de port edilebilir bir komut haline gelir.
RDA kesmesi içinde bu komutlarla ilgili bir ayrıntı var.
#int_RDA3
void RDA3_isr(void)
{
const u16 max_gsm_rda_data=400; /*Sayfa eğer bulunamazsa dönüş çıktısı uzun olur. Hepsi ile işlemciyi meşgul etme. Salla gitsin*/
char gsm_answer[max_gsm_rda_data];
char dummy_resp;
u8 char_base;
u32 temp_counter=0;
u16 data_counter;//=0;
[color=red] gsm_interrupt=1;[/color] //interrupt geldiğinde
data_counter=0;
temp_counter=0;
for (temp_counter=0;temp_counter<max_gsm_rda_data;temp_counter++)
{
gsm_answer[temp_counter]=0;
}
temp_counter=0;
do{
if(kbhit(gsm_comm))
{
dummy_resp=fgetc(gsm_comm);
if(data_counter<max_gsm_rda_data)
{
gsm_answer[data_counter]=dummy_resp;
data_counter++;
}
temp_counter=0;
}
temp_counter++;
}while (temp_counter<15000);
gsm_answer[data_counter]='\0';
fprintf(Comm1,"\r\nGSM RDA :%s\r\n "gsm_answer);
Bu kısmın kullanımında açıklamam gereken bişeyler var.
Bu kısmı yazarken karşılaştığım en büyük zorluk belirli bir uzunluğa sahip olmayan ve belirli beir karakterle bitmeyen texti almaktı.
birkaçtane line feed gelebilir, enter gelebilir, gelen cevap bir harf de olabilir, 200 harf de.
Bunun için ben de başka bir mantık kurdum. Bir karakter geldiğinde önce aldığın diziyi boşalt, sonra 15000 defa dön. Sayı fazla gelebilir ama 20Mhz de çalışan bir işlemci 15000 döngüyü 2-3 msde alır. Bu arada karakter gelirse sayacı sıfırla ve 15000 daha dön. Bu döngü işi sadece toplam süreci 2-3 ms uzattığı için o zaman mantıklı geldi. Kullanımda da bir sıkıntı çıkmadı.
Burda önemli olan değişken gsm_interrupt=1; satırıdır. cevap_bekle() içinde hatırlarsanız timeout test ediliyordu. Bir komut için timeout süresi kadar beklemek akıllıca olmaz. timeout beklemezseniz de komutun cevap verip vermediğini bilemezsiniz. Ben de burada komutu gönderip timeout içindeki süreyi 10ms paketlere böldüm. 10ms bekle cevp var mı bak. eğer cevap varsa cevabı değerlendir. cevap yoksa timeout dolana kadar 10ms 10ms bekle.
Beklemek size mantıklı gelmeyebilir ama GSM bağlantısını yapamadıysanız GPRS'e bağlanamazsınız. GPRS bağlantınız henüz açılmadıysa Soket açamazsınız. Yani paşalar gibi beklemek zorundasınız.
Toparlamak gerekirseprojenin kodarının tamamını paylaşmadım. Aldığım textleri nasıl işlediğimi paylaşmadım. Amacım birilerine hazır ödevi eline vermek değil profesyonellerin deneyimleri sonucu elde ettikleri ve haklı olarak paylaşmak istemedikleri kodları öğrenmek isteyenlerle yapısal ve çalışma mantığı noktasında paylaşmak.
typedef unsigned int8 u8;
typedef volatile unsigned int8 vu8;
typedef unsigned int16 u16;
typedef volatile unsigned int16 vu16;
typedef unsigned int32 u32;
kısımlarının kaldığını gördüm.
kod kısmı çinde yazıya zemin rengi verilemiyormuş.
[color=red]fprintf(gsm_comm,"%s"sendcmddefaults[cmd].modemdata);
fprintf(comm1,"\r\n%s\r\n"sendcmddefaults[cmd].modemdata);
kısımları renkli yazması için bu şekilde yazdım ama kodları doğrudan çıktı.
fprintf(gsm_comm,"%s"sendcmddefaults[cmd].modemdata);
fprintf(comm1,"\r\n%s\r\n"sendcmddefaults[cmd].modemdata);
şeklinde olacak.
Nacizane tavsiyem elinizde güçlü debug aygıtları olsa da olmasa da muhakkak işlemciye yaptırdığınız işleri uart portundan anlaşılır parçalar halinde gönderin.
KodSeç
fprintf(comm1,"\r\n%s\r\n"sendcmddefaults[cmd].modemdata);
satırı bu iş için ayrıldı. Bu sayede işlemci ne aldı, ne okudu, ne iş yapıyor nerde takıldı görürsünüz. canlı debug yaparsınız.
GSM modülle uğraşacaklar TELİT için RSTERM, RSTERM PLUS,
Quectel için QUECTEL için kendi seri port dinleme programı var.
Quectelin programı biraz daha ayrıntılı. Ben çok faydasını gördüm.
void gsm_boot(void)
{
u8 timeout_try;
printf(lcd_yaz,"GSM On");
output_float(pin_gsm_pwrmon); //Modülün PWRMON çıkışı takip etmek için
output_drive(pin_gsm_power_on); //Modül besleme kontrolü Pin Ayarı
bekle(t_mini);
gsm_power_state(1); //Modül beslemesi AÇIK/kapalı
bekle(3*t_long);
gsm_power_pwrmon=is_gsm_power_on(); //Takip için PWRMON okuma
lcd_sil();
printf(lcd_yaz,"GSM Boot");
enable_interrupts(INT_RDA3); //GSM modül verisi okuma için interrupt enable
bekle(t_mini);
gsm_interrupt=0;
hi_x(led4);
do{
send_cmd(eAT);
bekle(t_short);
}while(is_ok!=1);
lo_x(led4);
//Bu komutların Error verme durumu olmadığı için geri bildirim koymadım.
send_cmd(eATV0); //parametresiz sabit komutlar için bu komutu kullanabilirim.
send_cmd(eATE0); //sabit fonksiyonlar için bir numara. komut dönüşünde de timeout var
send_cmd(eAT_FCLASS8); //Ses araması için
send_cmd(eAT_CNMI21); // Gelen mesaj bildirimi Dikkat SIM takılı olmadığı zaman error geri dönüyor.
send_cmd(eAT_CMGF1); //Giden mesaj formatı
//send_cmd(eAT_CSCA); Mesaj Servis merkezi sonra girilecek
send_cmd(eAT_CLIP1); //Gelen arama Numara gösterimi
send_cmd(eAT_CLIR1); //Giden arama Numara gösterimi
send_cmd(eAT_SLED2); //Status Led durumu
send_cmd(eAT_K0); // Taşma kontrolu kapalı Bu komutu vermeyince Modül mal gibi kalıyor.
// send_cmd(eAT_GPIO12); //Sim Kart Kontrolü
/*zurnanın zırt dediği yer
Burada AT#MONI koutuyla şebeke bulunana kadar
AT#MONI verecek Buraya timeout yanında sonra timeout_try ekle
Belirli bir sefer sonunda da hala şebeke yoksa başka bir çareye bak
*/
bekle(5*t_long);
timeout_try=0;
do{
send_cmd(eAT_MONI);
bekle(t_long);
timeout_try++;
}while((gsm_response_state!=OK)&&(timeout_try<max_timeout_try));
if(timeout_try==max_timeout_try)
{
fprintf(Comm1,"Sebeke Yok!!!\r\n");
hi_x(led3);
}
hi_x(led7);
bekle(t_medium);
send_cmd(eAT_USERID);
send_cmd(eAT_PASSW);
send_cmd(eAT_CGDCONT);
hi_x(led4);
timeout_try=0;
do{
send_cmd(eAT_GPRS1);
bekle(t_long);
timeout_try++;
}while((gsm_response_state!=OK)&&(timeout_try<max_timeout_try));
if(timeout_try==max_timeout_try)
{
fprintf(Comm1,"GPRS Bağlantısı yapılamadı Yok!!!\r\n");
hi_x(led2);
}
hi_x(led6);
//gsm_boot();
//Buraya gsm modul açılırken verilecek olan std komutlar girilecek.
}
yukardaki kod da GSM modülün açılma, bağlanma, test ve GPRS bağlantı kısımlarını kontrol ediyor.
Telit GSM modül kullananlar AT&K0 komutuna dikkat etsin. Beni bir hafta uğraştırdı. Absürd bir şekilde GSM modül yanıt vermedi. Bu komutu verince alakasız şekilde çalışmaya başladı.
hazırlanan kütüphanenin kullanımı ile ilgili yukarıda yeterince örnek var.
u8 socket_dial(u8 ip_addr)
{
gsm_response_state=EMPTY; //komut göndermeden önce daha önceki kalan response state'le karışma olmasın diye boşalt
fprintf(gsm_comm,"%s%c%s%c,0\r\n"sendcmddefaults[eAT_SD].modemdata,dbl_toe,web_addr[ip_addr].web_addr_str,dbl_toe);
fprintf(Comm1,"%s%c%s%c,0\r\n"sendcmddefaults[eAT_SD].modemdata,dbl_toe,web_addr[ip_addr].web_addr_str,dbl_toe);
cevap_bekle(sendcmddefaults[eAT_SD].Timeout);
fprintf(Comm1,"GPRS Cevap %s\r\n"mdm_resp[gsm_response_state].response);
return gsm_response_state;
}
void send_http_request(u8 http_req1,u8 http_req2)
{
hi_x(led5);
send_next=0; //istenen cevaplardan biri dönene kadar bekle
fprintf(gsm_comm,"%s"web_addr[http_req1].web_addr_str);
fprintf(gsm_comm,"%s"web_addr[http_req2].web_addr_str);
fprintf(Comm1,"%s"web_addr[http_req1].web_addr_str);
fprintf(Comm1,"%s"web_addr[http_req2].web_addr_str);
cevap_bekle(sendcmddefaults[eAT_SD].Timeout);
lo_x(led5);
}
Son bölüm olarak da yukarda Sockek dial ve httprequest kısımları var. Siteye yapılacak istekler buraya eklenecektir.
Kütüphanenin kullanım örneği:
fprintf(Comm1,"GPRS Baglanti tamam");
socket_state=0;
adres(1,1);
printf(lcd_yaz,"AT#SD=1,0,80,IP,0 ");
socket_state=socket_dial(IP2);
adres(1,2);
printf(lcd_yaz,"Socket Stat:%c "socket_state+48);
if(socket_state==CONNECT)
{
//time_sync sayfa çağırma
//send_http_request_w_device_id(t_sync,connection_close);
//send_http_request(dummy_default,connection_close);
//timetable çekme
fprintf(gsm_comm,"%s%s&day=%u\r\n"web_addr[gsm_timetable].web_addr_str,device_id,day);
fprintf(gsm_comm,"%s"web_addr[connection_close].web_addr_str);
gönderilen sayfa isteği ismiyle geri dönecek. Bu yüzden istekte bulunulan her sayfa
bu isteğe göre revize edilecek
// }
sanırım yukarıdaki iki satırda olayı anlamışsınızdır.
socket_state=socket_dial(IP2);
soket aç ve
KodSeç
if(socket_state==CONNECT){
fprintf(gsm_comm,"%s%s&day=%u\r\n"web_addr[gsm_timetable].web_addr_str,device_id,day);
fprintf(gsm_comm,"%s"web_addr[connection_close].web_addr_str);
Umarım ihtiyacı olanlara faydalı olur.
Merhaba.
Şimdi fırsat buldukça CCS C ve Pic ile ilgili öğrendiklerimi konu başlıkları halinde paylaşmaya çalışacağım. PIC ve GSM Modül arasında iletişimin donanım detayına çok fazla girmeden yazılım kısmında PIC ve GL865 harici donanım projelerinde de kullanılabilecek kodlar paylaşmaya çalışacağım.
Bu kodun yapı örneğini benimle paylaşan İzmir'de ikamet eden sevgili dostum Aykut ULUSAN'a da buradan teşekkürü borç bilirim.
Öncelikle PIC ve GL865 Modül uart üzerinde 115200 baudrate ile haberleşiyor.
PIC tarafından GSM'e veri göndermek için bir çok komut var.
Bunları:
Şebeke ile ilgili olanlar
SMS ile ilgili olanlar
GPRS ile ilgili olanlar
SES araması ile ilgili olanlar
GSM Modül ile ilgili donanımsal olanlar diye gruplayabiliriz.
Bu komutları bazen tek AT\r\n gibi
bazen de AT+FCLASS=8 gibi değişen parametrelerle gönderiyoruz.
İlk önce komut yapısında structure ve enum tanımı yapılması hem komutların gönderimi hem de anlaşılması için gereklidir.
Çünkü her bölümde fprintf(port,"ATxxxxx%s=%c"param1,param2) gibi komut gönderimi çok uygun değildir.
enum state{
OK,
CONNECT,
RING,
NO_CARRIER,
ERROR,
CONNECT_1200,
NO_DIALTONE,
NO_ANSWER,
BUSY,
};
şeklinde bir enum tanımladım.
Bu yapı sayesinde 0 yerine OK, 1 yerine CONNECT kullanabileceğim
Aşağıdaki max_my_modem_response_char ile maksimum 15 karakter atayacağım bir değişken tanımlıyorum.
response_nr ile de 12 tane komut tanımlayacağımı belirtiyorum.
yapının içinde bir sayı ve bir text bulunuyor.
Text için gelen cevap yada göndereceğim komut textini aktarıyorum.
#define max_my_modem_response_char 15 //dönen modem cevabı için max char size
#define response_nr 12
//dönen cevap sayısı
typedef struct my_modem_response{
u8 cmd;
char response[max_my_modem_response_char];
}my_mdm_resp;
Bu kısımda da tanımladığım değişkenlere değerleri aktarıyorum.
my_mdm_resp const mdm_resp[response_nr]={
OK,{"OK"},
CONNECT,{"CONNECT"},
RING,{"RING"},
NO_CARRIER,{"NO_CARRIER"},
ERROR,{"ERROR"},
CONNECT_1200,{"CONNECT_1200"},
NO_DIALTONE,{"NO_DIALTONE"},
NO_ANSWER,{"NO_ANSWER"},
BUSY,{"BUSY"},
EMPTY,0,
};
Programlamaya yeni başlayan arkadaşlar şimdi ne gerek var bu kadar koda ben fprintf ile yazar geçerim diyecekler.
Ama bir süre sonra uzun programlar yazmaya başladıklarında saç baş yolmaya başlayacaklardır.
Bu yüzden hem anlaşılır hem de kullanışlı kod yazmak, iyi bir alışkanlıktır.
Aynı yapıyı aşağıda GSM komut kütüphanesi için de kuralım kullanım detaylarına bakalım.
//Komutlar için struct
enum{
eAT, //0
eAT_FCLASS8,
eAT_MONI,
eAT_CREG,
eATD,
eATH,
eATE0,
eATV0,
eAT_IPR,
eAT_CLIP1,
eAT_CLIR1,
eAT_CLIR0,
eAT_CGCLASS_B,
eAT_CGCLASS_CG,
eAT_CGCLASS_CC,
eAT_CGATT0,
eAT_CGATT1,
eAT_CGREG,
eAT_CGDCONT,
eAT_CSCA,
eAT_CMGF1,
eAT_CNMI21,
eAT_CMGS,
eAT_GPRS0,
eAT_GPRS1,
eAT_SLED2,
eAT_GPIO12, //Simkart kontrolü için GPIO
eAT_K0,
eAT_USERID,
eAT_PASSW,
eAT_SD,
eAT_GPRS,
e3plus,
};
#define RESPONSE_MAX_CHAR 55
#define CMD_NUMBER 40 // yukarıda 40 tane modem komutu var
typedef struct my_command_type{
u8 Cmd; // enum içindeki komutları tutar (gönderdiğin veya cevap alacağın komutun ne olduğunu buradan anlarsın)
vu16 Timeout; // her komutun timeout'u için kullanılır
vu8 ModemData[RESPONSE_MAX_CHAR]; // modemden gelen veya gidecek data, interrupt içinde usarttan bu buffer'a kopyalancağından volatile yaptım
vu8 lcd_data[RESPONSE_MAX_CHAR];
// herşeyi buraya ekleyebilirsin
}MyModemStruct_Typedef;
MyModemStruct_Typedef const SendCmdDefaults[CMD_NUMBER]={
eAT, 10,{"AT\r\n"},{"AT"},
eAT_FCLASS8, 10,{"AT+FCLASS=8\r\n"},{"AT+FCLASS=8"}, // bu komut için 1000*10ms=10sn timeout koydum
eAT_MONI, 150,{"AT#MONI\r\n"},{"AT#MONI"},
eAT_CREG,150,{"AT+CREG?\r\n"},{"AT+CREG"},
eATD, 100,{"ATD"},{"ATD"},
eATH, 100,{"ATH\r\n"},{"ATH"},
eATE0, 10,{"ATE0\r\n"},{"ATE0"},
eATV0, 10,{"ATV0\r\n"},{"ATV0"},
eAT_IPR, 10,{"AT+IPR="},{"AT+IPR="},
eAT_CLIP1, 10,{"AT+CLIP=1\r\n"},{"AT+CLIP=1"},
eAT_CLIR1, 10,{"AT+CLIR=1\r\n"},{"AT+CLIR=1"},
eAT_CLIR0, 10,{"AT+CLIR=0\r\n"},{"AT+CLIR=0"},
eAT_CGCLASS_B, 500,{"AT+CGCLASS=B\r\n"},{"AT+CGCLASS=B"},
eAT_CGCLASS_CG, 500,{"AT+CGCLASS=CG\r\n"},{"AT+CGCLASS=CG"},
eAT_CGCLASS_CC, 500,{"AT+CGCLASS=CC\r\n"},{"AT+CGCLASS=CC"},
eAT_CGATT0, 500,{"AT+CGCATT=0\r\n"},{"AT+CGCATT=0"},
eAT_CGATT1, 500,{"AT+CGCATT=1\r\n"},{"AT+CGCATT=1"},
eAT_CGREG, 500,{"AT+CREG"},{"AT+CREG"},
eAT_CGDCONT, 500,{"AT+CGDCONT=1,""IP"",""internet"",""0.0.0.0"",0,0\r\n"},{"AT+CGDCONT=1,""IP"",""internet"",""0.0.0.0"",0,0"},
eAT_CSCA, 10,{"ATCSCA="},{"ATCSCA="},
eAT_CMGF1, 10,{"AT+CMGF=1\r\n"},{"AT+CMGF=1"},
eAT_CNMI21, 10,{"AT+CNMI=2,1\r\n"},{"AT+CNMI=2,1"},
eAT_CMGS, 10,{"AT+CMGS=0\r\n"},{"AT+CMGS=0"},
eAT_GPRS0, 50,{"AT#GPRS=0\r\n"},{"AT#GPRS=0"},
eAT_GPRS1, 150,{"AT#GPRS=1\r\n"},{"AT#GPRS=1"},
eAT_SLED2, 10,{"AT#SLED=2\r\n"},{"AT#SLED=2"},
eAT_GPIO12,10,{"AT#GPIO=1,2\r\n"},{"AT#GPIO=1,2"}, //Simkart kontrolü için GPIO
eAT_K0,10,{"AT&K0\r\n"},{"AT&K0"},
eAT_USERID,10,{"AT#USERID=""""\r\n"},{"AT#USERID="""""}, //GPRS USERID
eAT_PASSW,10,{"AT#PASSW=""""\r\n"},{"AT#PASSW="""""}, //GPRS PASSWORD
eAT_SD,250,{"AT#SD=1,0,80,"},{"AT#SD=1,0,80,"}, //Socket Dial
eAT_GPRS,250,{"AT#GPRS?\r\n"},{"AT#GPRS?"},
e3plus,1000,{"+++"},{"+++"}
};
Yukarıdaki kodları iyi okuyanların şimdi gülümsediğini görür gibiyim. Yukarıdaki yapıda timeout isminde bir değişken daha tanımlı.
Bu değişken her komut için ayrı ayrı süreleri tutuyor.
AT için timeout 0.1 saniye ise AT#GPRS için 250sn
Kütüphanenein en büyük güzelliği burda.
Komutu gönder cevap gelene kadar timeout kadar bekle.
Eğer cevap gelirse beklemeyi bitir. Cevap gelmezse Timeout ver çık ;D ;D
Bir de GPRS ile bağlanacağımız adresleri ve yapıları tanımlayalım.
//gprsle bağlanılacak web adresleri
enum enum_web_addr{
IP,
IP2,
connection_close,
connection_keep_alive,
gsm_timetable,
t_sync,
defect_add,
get_sub_terminal,
};
#define max_addr_length 50 //dönen modem cevabı için max char size
#define piece_of_web_addr 10
//dönen cevap sayısı
typedef struct my_gprs_modem_response{
u8 cmd;
char web_addr_str[max_addr_length];
}my_web_addr;
my_web_addr const web_addr[piece_of_web_addr]={
IP,{"xxx.xxx.xxx.xxx "}, //Noktalarla ayrılmış şekilde IP adresi yazılacak
IP2,{"xxx.xxx.xxx.xxx"}, //GSM Modüllerin sadece gerçek IP adreslerine çağrı yapabildiğini yani dedicated server kullanmanız gerektiğini unutmayın.
connection_close,{"Connection: Close\r\n\r\n"},
connection_keep_alive,{"Connection: Keep-Alive\r\n\r\n"},
gsm_timetable,{"GET /timetable.aspx?dev="},
t_sync,{"GET /time_sync.aspx?dev="},
defect_add,{"GET /defect_add.aspx?dev="},
get_sub_terminal,{"GET /get_sub_terminal.aspx?dev="}
};
Yukardaki kodarın çağrı yaptığı site şu anda aktif olmadığı için kodları aynen yayınlamakta bir sakınca görmüyorum.
Kullanım detaylarına bakacak olursak;
GSM Modüllerin sadece gerçek IP adreslerine çağrı yapabildiğini yani dedicated server kullanmanız gerektiğini unutmayın.
Uart tanımı
#pin_select U3TX=PIN_G7
#pin_select U3RX=PIN_G6
#use rs232(UART3, baud=115200, stream=gsm_comm)
şeklinde yapıldı.
gsm_comm GSM Modülün bağlandığı uart portunun adıdır.
İlk önce cevap_bekle'yi tanımlıyorum.
void cevap_bekle(u16 sure)
{
u16 sayac=0;
do{
bekle(100);
sayac++;
fprintf(Comm1,"sayac:%u\r\n"sayac);
}while((!(sayac>sure)&&(gsm_interrupt!=1))&&(sayac<1000)); //Buraya dikkat karşılaştırmada hata
if ((sayac==sure)||(sayac>sure))
{
fprintf(Comm1,"timeout\r\n"); //ilerde burası kapatılacak
gsm_cmd_timeout=1;
}
if (gsm_response_state!=EMPTY)
{
// fprintf(Comm1,"RDA interrupt\r\n"); //ilerde burası kapatılacak
gsm_cmd_timeout=0;
}
if(sayac>1000)
{
fprintf(Comm1,"Sayac exceeded\r\n"); // sayac saçmalarsa
}
gsm_interrupt=0;
}
Burada yukarıda bahsettiğim timeout değişkeni hayati öneme sahip. komutu gönderdim.
3 ihtimal var. Komuta OK cevbı geldi, Komuta ERROR cevabı geldi. Komuta cevap gelmedi, timeout oluştu. her komutun timeout süresini daha önce tanımladığım için şimdi sadece komutun adını yazmam yeterli. Kodlamayı seviyorum:)
Aşağıda komut gönderme yapısına bakalım.
void send_cmd(u8 cmd)
{
is_ok=0;
is_0=0;
send_next=0;
gsm_response_state=EMPTY; //komut göndermeden önce daha önceki kalan response state'le karışma olmasın diye boşalt
[color=red]fprintf(gsm_comm,"%s"sendcmddefaults[cmd].modemdata);[/color]
[color=yellow]fprintf(comm1,"\r\n%s\r\n"sendcmddefaults[cmd].modemdata);[/color]
cevap_bekle(sendcmddefaults[cmd].Timeout);
// adres(1,1);
//printf(lcd_yaz,"%s"sendcmddefaults[cmd].lcd_data);
}
void send_cmd_wo_wait(u8 cmd)
{
fprintf(gsm_comm,"%s"sendcmddefaults[cmd].modemdata);
}
fprintf(gsm_comm,"%s"sendcmddefaults[cmd].modemdata); satırı ile komutu gönderdim ama herşey daha yeni başlıyor.
send_cmd(eAT); yazmam bu komutu göndermem ve maksimum timeout süresi kadar beklemem için yeterli.
kütüphanenin timeout gerçekleşince yapılacaklar kısmını yazmadım. cevap_bekle() kütüphanesinde timeout kısmına istenen kodlar ihtiyaca göre yazılabilir.
kütüphaneyi okurken bekle, hi_x, gibi CCs kütüphanede olmayan komutlar var. aslında tanıdık gelecektir.
#define bekle(x) delay_ms(x)
#define bekle_ss(x) delay_ms(x)
#define bekle_us(x) delay_us(x)
#define hi_x(x) output_high(x)
#define lo_x(x) output_low(x)
#define x_to(x,y) output_bit(x,y)
sanırım kodları anlamada daha yardımcı olur.
const u8 t_mini=1;
const u8 t_short=50;
const u8 t_medium=250;
const u16 t_long=1000;
tanımlaması da kod yazma esnasında iş görür.
bekle(t_mini); hem sonradan değiştirilebilir hem de port edilebilir bir komut haline gelir.
RDA kesmesi içinde bu komutlarla ilgili bir ayrıntı var.
#int_RDA3
void RDA3_isr(void)
{
const u16 max_gsm_rda_data=400; /*Sayfa eğer bulunamazsa dönüş çıktısı uzun olur. Hepsi ile işlemciyi meşgul etme. Salla gitsin*/
char gsm_answer[max_gsm_rda_data];
char dummy_resp;
u8 char_base;
u32 temp_counter=0;
u16 data_counter;//=0;
[color=red] gsm_interrupt=1;[/color] //interrupt geldiğinde
data_counter=0;
temp_counter=0;
for (temp_counter=0;temp_counter<max_gsm_rda_data;temp_counter++)
{
gsm_answer[temp_counter]=0;
}
temp_counter=0;
do{
if(kbhit(gsm_comm))
{
dummy_resp=fgetc(gsm_comm);
if(data_counter<max_gsm_rda_data)
{
gsm_answer[data_counter]=dummy_resp;
data_counter++;
}
temp_counter=0;
}
temp_counter++;
}while (temp_counter<15000);
gsm_answer[data_counter]='\0';
fprintf(Comm1,"\r\nGSM RDA :%s\r\n "gsm_answer);
Bu kısmın kullanımında açıklamam gereken bişeyler var.
Bu kısmı yazarken karşılaştığım en büyük zorluk belirli bir uzunluğa sahip olmayan ve belirli beir karakterle bitmeyen texti almaktı.
birkaçtane line feed gelebilir, enter gelebilir, gelen cevap bir harf de olabilir, 200 harf de.
Bunun için ben de başka bir mantık kurdum. Bir karakter geldiğinde önce aldığın diziyi boşalt, sonra 15000 defa dön. Sayı fazla gelebilir ama 20Mhz de çalışan bir işlemci 15000 döngüyü 2-3 msde alır. Bu arada karakter gelirse sayacı sıfırla ve 15000 daha dön. Bu döngü işi sadece toplam süreci 2-3 ms uzattığı için o zaman mantıklı geldi. Kullanımda da bir sıkıntı çıkmadı.
Burda önemli olan değişken gsm_interrupt=1; satırıdır. cevap_bekle() içinde hatırlarsanız timeout test ediliyordu. Bir komut için timeout süresi kadar beklemek akıllıca olmaz. timeout beklemezseniz de komutun cevap verip vermediğini bilemezsiniz. Ben de burada komutu gönderip timeout içindeki süreyi 10ms paketlere böldüm. 10ms bekle cevp var mı bak. eğer cevap varsa cevabı değerlendir. cevap yoksa timeout dolana kadar 10ms 10ms bekle.
Beklemek size mantıklı gelmeyebilir ama GSM bağlantısını yapamadıysanız GPRS'e bağlanamazsınız. GPRS bağlantınız henüz açılmadıysa Soket açamazsınız. Yani paşalar gibi beklemek zorundasınız.
Toparlamak gerekirseprojenin kodarının tamamını paylaşmadım. Aldığım textleri nasıl işlediğimi paylaşmadım. Amacım birilerine hazır ödevi eline vermek değil profesyonellerin deneyimleri sonucu elde ettikleri ve haklı olarak paylaşmak istemedikleri kodları öğrenmek isteyenlerle yapısal ve çalışma mantığı noktasında paylaşmak.
typedef unsigned int8 u8;
typedef volatile unsigned int8 vu8;
typedef unsigned int16 u16;
typedef volatile unsigned int16 vu16;
typedef unsigned int32 u32;
kısımlarının kaldığını gördüm.
kod kısmı çinde yazıya zemin rengi verilemiyormuş.
[color=red]fprintf(gsm_comm,"%s"sendcmddefaults[cmd].modemdata);
fprintf(comm1,"\r\n%s\r\n"sendcmddefaults[cmd].modemdata);
kısımları renkli yazması için bu şekilde yazdım ama kodları doğrudan çıktı.
fprintf(gsm_comm,"%s"sendcmddefaults[cmd].modemdata);
fprintf(comm1,"\r\n%s\r\n"sendcmddefaults[cmd].modemdata);
şeklinde olacak.
Nacizane tavsiyem elinizde güçlü debug aygıtları olsa da olmasa da muhakkak işlemciye yaptırdığınız işleri uart portundan anlaşılır parçalar halinde gönderin.
KodSeç
fprintf(comm1,"\r\n%s\r\n"sendcmddefaults[cmd].modemdata);
satırı bu iş için ayrıldı. Bu sayede işlemci ne aldı, ne okudu, ne iş yapıyor nerde takıldı görürsünüz. canlı debug yaparsınız.
GSM modülle uğraşacaklar TELİT için RSTERM, RSTERM PLUS,
Quectel için QUECTEL için kendi seri port dinleme programı var.
Quectelin programı biraz daha ayrıntılı. Ben çok faydasını gördüm.
void gsm_boot(void)
{
u8 timeout_try;
printf(lcd_yaz,"GSM On");
output_float(pin_gsm_pwrmon); //Modülün PWRMON çıkışı takip etmek için
output_drive(pin_gsm_power_on); //Modül besleme kontrolü Pin Ayarı
bekle(t_mini);
gsm_power_state(1); //Modül beslemesi AÇIK/kapalı
bekle(3*t_long);
gsm_power_pwrmon=is_gsm_power_on(); //Takip için PWRMON okuma
lcd_sil();
printf(lcd_yaz,"GSM Boot");
enable_interrupts(INT_RDA3); //GSM modül verisi okuma için interrupt enable
bekle(t_mini);
gsm_interrupt=0;
hi_x(led4);
do{
send_cmd(eAT);
bekle(t_short);
}while(is_ok!=1);
lo_x(led4);
//Bu komutların Error verme durumu olmadığı için geri bildirim koymadım.
send_cmd(eATV0); //parametresiz sabit komutlar için bu komutu kullanabilirim.
send_cmd(eATE0); //sabit fonksiyonlar için bir numara. komut dönüşünde de timeout var
send_cmd(eAT_FCLASS8); //Ses araması için
send_cmd(eAT_CNMI21); // Gelen mesaj bildirimi Dikkat SIM takılı olmadığı zaman error geri dönüyor.
send_cmd(eAT_CMGF1); //Giden mesaj formatı
//send_cmd(eAT_CSCA); Mesaj Servis merkezi sonra girilecek
send_cmd(eAT_CLIP1); //Gelen arama Numara gösterimi
send_cmd(eAT_CLIR1); //Giden arama Numara gösterimi
send_cmd(eAT_SLED2); //Status Led durumu
send_cmd(eAT_K0); // Taşma kontrolu kapalı Bu komutu vermeyince Modül mal gibi kalıyor.
// send_cmd(eAT_GPIO12); //Sim Kart Kontrolü
/*zurnanın zırt dediği yer
Burada AT#MONI koutuyla şebeke bulunana kadar
AT#MONI verecek Buraya timeout yanında sonra timeout_try ekle
Belirli bir sefer sonunda da hala şebeke yoksa başka bir çareye bak
*/
bekle(5*t_long);
timeout_try=0;
do{
send_cmd(eAT_MONI);
bekle(t_long);
timeout_try++;
}while((gsm_response_state!=OK)&&(timeout_try<max_timeout_try));
if(timeout_try==max_timeout_try)
{
fprintf(Comm1,"Sebeke Yok!!!\r\n");
hi_x(led3);
}
hi_x(led7);
bekle(t_medium);
send_cmd(eAT_USERID);
send_cmd(eAT_PASSW);
send_cmd(eAT_CGDCONT);
hi_x(led4);
timeout_try=0;
do{
send_cmd(eAT_GPRS1);
bekle(t_long);
timeout_try++;
}while((gsm_response_state!=OK)&&(timeout_try<max_timeout_try));
if(timeout_try==max_timeout_try)
{
fprintf(Comm1,"GPRS Bağlantısı yapılamadı Yok!!!\r\n");
hi_x(led2);
}
hi_x(led6);
//gsm_boot();
//Buraya gsm modul açılırken verilecek olan std komutlar girilecek.
}
yukardaki kod da GSM modülün açılma, bağlanma, test ve GPRS bağlantı kısımlarını kontrol ediyor.
Telit GSM modül kullananlar AT&K0 komutuna dikkat etsin. Beni bir hafta uğraştırdı. Absürd bir şekilde GSM modül yanıt vermedi. Bu komutu verince alakasız şekilde çalışmaya başladı.
hazırlanan kütüphanenin kullanımı ile ilgili yukarıda yeterince örnek var.
u8 socket_dial(u8 ip_addr)
{
gsm_response_state=EMPTY; //komut göndermeden önce daha önceki kalan response state'le karışma olmasın diye boşalt
fprintf(gsm_comm,"%s%c%s%c,0\r\n"sendcmddefaults[eAT_SD].modemdata,dbl_toe,web_addr[ip_addr].web_addr_str,dbl_toe);
fprintf(Comm1,"%s%c%s%c,0\r\n"sendcmddefaults[eAT_SD].modemdata,dbl_toe,web_addr[ip_addr].web_addr_str,dbl_toe);
cevap_bekle(sendcmddefaults[eAT_SD].Timeout);
fprintf(Comm1,"GPRS Cevap %s\r\n"mdm_resp[gsm_response_state].response);
return gsm_response_state;
}
void send_http_request(u8 http_req1,u8 http_req2)
{
hi_x(led5);
send_next=0; //istenen cevaplardan biri dönene kadar bekle
fprintf(gsm_comm,"%s"web_addr[http_req1].web_addr_str);
fprintf(gsm_comm,"%s"web_addr[http_req2].web_addr_str);
fprintf(Comm1,"%s"web_addr[http_req1].web_addr_str);
fprintf(Comm1,"%s"web_addr[http_req2].web_addr_str);
cevap_bekle(sendcmddefaults[eAT_SD].Timeout);
lo_x(led5);
}
Son bölüm olarak da yukarda Sockek dial ve httprequest kısımları var. Siteye yapılacak istekler buraya eklenecektir.
Kütüphanenin kullanım örneği:
fprintf(Comm1,"GPRS Baglanti tamam");
socket_state=0;
adres(1,1);
printf(lcd_yaz,"AT#SD=1,0,80,IP,0 ");
socket_state=socket_dial(IP2);
adres(1,2);
printf(lcd_yaz,"Socket Stat:%c "socket_state+48);
if(socket_state==CONNECT)
{
//time_sync sayfa çağırma
//send_http_request_w_device_id(t_sync,connection_close);
//send_http_request(dummy_default,connection_close);
//timetable çekme
fprintf(gsm_comm,"%s%s&day=%u\r\n"web_addr[gsm_timetable].web_addr_str,device_id,day);
fprintf(gsm_comm,"%s"web_addr[connection_close].web_addr_str);
gönderilen sayfa isteği ismiyle geri dönecek. Bu yüzden istekte bulunulan her sayfa
bu isteğe göre revize edilecek
// }
sanırım yukarıdaki iki satırda olayı anlamışsınızdır.
socket_state=socket_dial(IP2);
soket aç ve
KodSeç
if(socket_state==CONNECT){
fprintf(gsm_comm,"%s%s&day=%u\r\n"web_addr[gsm_timetable].web_addr_str,device_id,day);
fprintf(gsm_comm,"%s"web_addr[connection_close].web_addr_str);
Umarım ihtiyacı olanlara faydalı olur.