Timer fungsi untuk pengontrol industri Simatic S7-1200

Bahkan untuk seri S7-300 dan S7-400, di bawah Langkah 7, versi klasik dari timer yang ditawarkan kepada pengembang sudah cukup - ini adalah timer IEC standar, diimplementasikan sebagai blok fungsi, dan timer S5 (yang, bagaimanapun, masih ada untuk seri S7- 1500). Namun, dalam beberapa kasus, pengembang tidak menggunakan alat standar dan mengimplementasikan penghitung waktunya sendiri, paling sering dalam bentuk fungsi. Fungsi pengatur waktu seperti itu diperlukan dengan pendekatan “IT” untuk pemrograman, di mana mereka beroperasi tidak dengan contoh terpisah dari blok fungsional peralatan teknologi, dengan pengikatan input dan output yang sesuai, tetapi dengan susunan struktur. Misalnya, larik struktur tipe input diskrit. Atau larik struktur agregat. Pendekatan pemrograman ini memiliki hak untuk ada, karena memungkinkan Anda untuk secara serius menyimpan memori kerja CPU, tetapi,di sisi lain, membuat kode program sulit dibaca. Programmer pihak ketiga dan dengan tampilan sederhana dari program LAD hampir tidak dapat langsung mengetahuinya, tetapi tumpukan indeks, array, dan fungsi untuk memprosesnya tidak ada pertanyaan, di sini, tanpa dokumentasi untuk perangkat lunak (dan tanpa setengah liter, tentu saja), di mana pun.

Susunan struktur ini biasanya diproses dalam fungsi. Pada prinsipnya, tidak ada yang mencegah pemrosesan blok fungsi, tetapi selalu ada pertanyaan penting - bagaimana cara bekerja dengan timer dalam kasus ini? Penghitung waktu standar mengasumsikan angka (S5) atau turunan dari blok fungsi (IEC). Saya ingatkan Anda, ini adalah pertanyaan pemrosesan array struktur untuk PLC Simatic klasik, dan untuk "memutar" nomor timer ke dalam struktur ini, dan terlebih lagi, instance menjadi sulit atau tidak mungkin.

Untuk alasan ini, kami membuat fungsi timer sendiri sebagai fungsi. Pada prinsipnya, untuk pengoperasian timer apa pun, Anda hanya perlu mengetahui beberapa hal - keadaan input, pengaturan waktu, dan berapa banyak waktu yang telah berlalu sejak aktivasi.

Untuk seri 300 dan 400, ada dua cara untuk menentukan waktu ini. Yang pertama adalah untuk melihat runtime dari OB1 utama (ada variabel yang sesuai dalam OB1 itu sendiri) atau OB siklik dan meningkatkan akumulator waktu internal dengan setiap panggilan timer, asalkan "kebenaran" adalah input. Bukan pilihan yang baik, karena kali ini berbeda untuk OB1 dan OB siklik. Metode kedua adalah fungsi sistem TIME_TCK, yang, dengan setiap panggilan, mengembalikan nilai tunggal - penghitung milidetik internal prosesor sentral.

gambar

Jadi, untuk timer dari tipe TON (on delay), algoritma operasi adalah sebagai berikut:

  • di sisi atas permintaan respons, setel ulang output dan ingat nilai saat ini dari timer sistem TIME_TCK
  • «» , ( , TIME_TCK 0 (2 ^ 31 — 1), ). , . , «», — «»
  • «»,

Dengan munculnya seri "seperseribu", situasinya telah sedikit berubah. Faktanya adalah bahwa garis S7-1500 mewarisi dukungan untuk panggilan sistem TIME_TCK, dan pecinta pendekatan "berdiri dan di tempat tidur gantung" (bagaimana lagi Anda dapat memanggil program yang hanya melakukan proses apa susunan struktur, saat beroperasi dengan indeks menyeramkan?) dengan tenang terus menggunakan praktik terbaik mereka.

Seri pengendali basis S7-1200 didasarkan pada arsitektur yang berbeda, dan memiliki sejumlah perbedaan dari S7-1500. Termasuk tidak adanya panggilan sistem TIME_TCK. Di jajaran pengembang yang tidak memiliki fleksibilitas berpikir yang memadai, ketidakpuasan telah hilang - tidak mungkin untuk menjalankan salinan / pasta program lama. Namun, tugas menentukan berapa banyak waktu telah berlalu sejak panggilan sebelumnya dapat dilakukan menggunakan fungsi runtime.

Fungsi ini mengembalikan waktu yang telah berlalu sejak panggilan sebelumnya, dalam hitungan detik, sebagai nomor real LREAL dengan presisi ganda. Detail dijelaskan dalam bantuan. Untuk keperluan internal, variabel MEM tambahan (juga dari jenis LREAL) diperlukan.

Saya akan memberikan sumber perkiraan pertama dari fungsi, dan saya akan memberikan beberapa catatan.

Deklarasi fungsi:

FUNCTION "PerversionTON" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      IN : Bool;   //  
      PT : Real;   //    
   END_VAR

   VAR_OUTPUT 
      Q : Bool;   //  
   END_VAR

   VAR_IN_OUT 
      INPrv : Bool;
      MEM : LReal;
      TimeACC : UDInt;
   END_VAR

   VAR_TEMP 
      udiCycle : UDInt;
      udiPT : UDInt;
   END_VAR

Dengan input / output, semuanya jelas: IN, Q dan PT. Saya mengatur pengaturan waktu dalam bentuk yang nyata, itu detik. Hanya ingin (tetapi sia-sia, tetapi lebih pada itu di bawah). Lebih lanjut tentang variabel area InOut. Karena kami memiliki fungsi, kami tidak memiliki area STAT, tidak ada variabel yang mempertahankan nilainya selama pemanggilan fungsi berikutnya, dan variabel tersebut diperlukan:

INPrv - untuk menentukan tepi positif dari permintaan

MEM - variabel tambahan untuk panggilan sistem untuk bekerja runtime

TimeACC - akumulator waktu , yang akan menyimpan jumlah mikrodetik dari penundaan yang sedang berjalan.

Variabel TimeACC, udiCycle dan udiPT ditentukan dalam format UDINT, integer yang tidak ditandatangani, 4 byte. Terlepas dari kenyataan bahwa saya menentukan waktu sebagai nyata, dan fungsi runtime mengembalikan nyata sebanyak presisi ganda, saya lebih suka melakukan operasi penjumlahan dan membandingkan dengan operan integer sederhana untuk menghemat waktu prosesor. Waktu dalam kasus saya diperhitungkan dalam mikrodetik. Alasannya sederhana - jika Anda kasar waktu untuk milidetik, maka dengan OB1 hampir kosong (misalnya, jika hanya satu timer dipanggil dalam seluruh program pengontrol dan tidak lebih), "lompatan" siklus mungkin, program kadang-kadang berjalan selama 250 μs. Tetapi dalam kasus ini, nilai maksimum yang diizinkan dari akumulator waktu adalah 4.294 detik, hampir 4.295 (2 ^ 32 - 1 = 4.294.967.295). Tidak ada yang bisa dilakukan, "optimasi" seperti itu membutuhkan pengorbanan.

Teks fungsi.

#udiCycle := LREAL_TO_UDINT(RUNTIME(#MEM) * 1000000); //     
#udiPT := REAL_TO_UDINT(#PT * 1000000); //   

IF (#IN AND (NOT #INPrv)) THEN //         
    #TimeACC := 0;
    #Q := FALSE;
ELSIF (#IN AND #INPrv) THEN //     ""
    #TimeACC += #udiCycle; //     "    "
    IF #TimeACC >=  #udiPT THEN //      
        #Q := TRUE; //  ""
        #TimeACC := #udiPT; //  
    ELSE //      
        #Q := FALSE; // 
    END_IF;
ELSE //    -      
    #Q := FALSE;
    #TimeACC := 0;
END_IF;

#INPrv := #IN; //  

ENO := #Q; // ENO         LAD  FBD

Dua baris pertama adalah perhitungan kembali pengaturan timer dari jumlah detik yang ditentukan dalam format NYATA ke jumlah mikrodetik. Waktu dalam mikrodetik yang berlalu dari panggilan blok program sebelumnya juga ditentukan.

Lebih lanjut, algoritma ini adalah sebagai berikut, dan saya telah memberikannya:

  • pada sisi naik dari input IN, reset output Q dan reset akumulator waktu
  • jika "kebenaran" terus menjadi input, kami meningkatkan akumulator waktu dengan nilai udiCycle yang sudah diketahui dan membandingkannya dengan pengaturan waktu. Jika pengaturan waktu terlampaui, timer telah bekerja, berikan output "true", jika tidak, berikan output "false"
  • dalam hal menerapkan input palsu ke input IN, reset output Q dan reset akumulator waktu.

Di akhir fungsi, untuk menentukan tepi input IN, ingat nilai sebelumnya. Juga berikan output ENO (saat menggunakan fungsi dalam bahasa grafis, seperti LAD) nilai output Q.

Kami memastikan bahwa fungsi tersebut bekerja, setelah itu menjadi menarik untuk mengevaluasi kecepatannya dan, jika perlu, meningkatkan (sudah terlihat pada pandangan pertama bahwa sejumlah perhitungan idle dan buang waktu CPU sia-sia). Untuk mengevaluasi kinerja, saya mendeklarasikan susunan 1000 struktur data timer.

Deklarasi struktur. Fieldnya menduplikasi variabel input dan output dari fungsi timer.

TYPE "typePervTONdata"
VERSION : 0.1
   STRUCT
      IN : Bool;   //  
      PT : Real;   //   
      Q : Bool;   //  
      INPrv : Bool;   //    
      MEM : LReal;   //    
      TimeACC : UDInt;   //  
   END_STRUCT;

END_TYPE

Array struktur dideklarasikan di blok data global TortureTON:

TONs : Array[0..999] of "typePervTONdata";

Kode berikut dijalankan di blok organisasi OB1:

FOR #i := 0 TO 999 DO
    "TortureTON".TONs[#i].IN := "startton";
    "PerversionTON"(IN := "TortureTON".TONs[#i].IN,
                    PT := "TortureTON".TONs[#i].PT,
                    Q := "TortureTON".TONs[#i].Q,
                    INPrv := "TortureTON".TONs[#i].INPrv,
                    MEM := "TortureTON".TONs[#i].MEM,
                    TimeACC := "TortureTON".TONs[#i].TimeACC);
END_FOR;

Diumumkan 1000 "instance" dari timer, masing-masing mengatur waktu 10 detik. Semua 1000 timer mulai menghitung waktu dengan nilai variabel marker startton.

Saya meluncurkan fungsi diagnostik pengontrol (S7-1214C DC / DC / DC, versi FW 4.4, versi Step7 - V16) dan menonton waktu siklus pemindaian pengontrol. Pada "idle" (ketika "false" tiba pada input dari timer), seluruh ribu diproses rata-rata selama 36-42 milidetik. Selama hitungan mundur sepuluh detik, pembacaan ini tumbuh sekitar 6-8 milidetik dan kadang-kadang berguling selama 50 ms.

Kami melihat apa yang dapat ditingkatkan dalam kode fungsi. Pertama, baris di awal blok program:

#udiCycle := LREAL_TO_UDINT(RUNTIME(#MEM) * 1000000); //     
#udiPT := REAL_TO_UDINT(#PT * 1000000); //   

Mereka selalu dipanggil, terlepas dari apakah penghitung waktu menghitung waktu, tidak menghitung, atau sudah dihitung. Buang besar uang adalah untuk memuat CPU tidak terlalu kuat dari seri 1200 dengan perhitungan yang melibatkan bahan presisi ganda. Adalah masuk akal untuk mentransfer kedua baris ke bagian kode yang memproses hitung mundur (jika "kebenaran" terus masuk). Juga diperlukan untuk menduplikasi perhitungan udiCycle ke dalam kode yang memproses sisi positif pada input dari timer. Ini akan meringankan "operasi idle" dari timer ketika nilai input salah. Dalam praktiknya, penghitung waktu dalam pengontrol logika yang dapat diprogram paling sering bekerja "idle". Misalnya, waktu penyaringan bouncing kontak adalah puluhan milidetik. Pulsa kontrol dari output diskrit adalah beberapa ratus milidetik, biasanya dari 0,5 hingga 1,0 detik.Waktu untuk memantau pelaksanaan perintah unit (misalnya, waktu katup terbuka sepenuhnya) adalah dari puluhan detik hingga beberapa menit. PLC dalam produksi bekerja 24 jam sehari dan 365 (dan kadang-kadang lebih!) Hari dalam setahun. Artinya, paling sering input timer adalah "nol", dan timer tidak menghitung apa-apa, atau "unit" tiba untuk waktu yang lama, dan timer sudah menghitung semuanya. Untuk membongkar CPU idle tahap kedua (timer sudah dihitung), perlu untuk memeriksa pada tahap "input terus menerima kebenaran" - jika timer sudah menghitung semua waktu dan mengatur output ke true. Dalam hal ini, tidak ada perhitungan yang harus dilakukan.paling sering input penghitung waktu adalah "nol", dan penghitung waktu tidak menghitung apa pun, atau "unit" tiba untuk waktu yang lama, dan penghitung waktu sudah menghitung semuanya. Untuk membongkar CPU idle tahap kedua (timer sudah dihitung), perlu untuk memeriksa pada tahap "kebenaran terus masuk" - jika timer sudah menghitung semua waktu dan mengatur output ke true. Dalam hal ini, tidak ada perhitungan yang harus dilakukan.paling sering input penghitung waktu adalah "nol", dan penghitung waktu tidak menghitung apa pun, atau "unit" tiba untuk waktu yang lama, dan penghitung waktu sudah menghitung semuanya. Untuk membongkar CPU idle tahap kedua (timer sudah dihitung), perlu untuk memeriksa pada tahap "kebenaran terus masuk" - jika timer sudah menghitung semua waktu dan mengatur output ke true. Dalam hal ini, tidak ada perhitungan yang harus dilakukan.

Untuk melakukan perubahan ini, perlu untuk mentransfer output dari timer Q dari area OUTPUT ke area IN_OUT, dan nilai output akan disimpan dalam variabel eksternal (dalam contoh ini, dalam array struktur). Setelah penyempurnaan, seluruh kode fungsi, termasuk deklarasi, adalah sebagai berikut:

FUNCTION "PerversionTON" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      IN : Bool;   //  
      PT : Real;   //    
   END_VAR

   VAR_IN_OUT 
      Q : Bool;   //  
      INPrv : Bool;
      MEM : LReal;
      TimeACC : UDInt;
   END_VAR

   VAR_TEMP 
      udiCycle : UDInt;
      udiPT : UDInt;
   END_VAR


BEGIN
	IF (#IN AND (NOT #INPrv)) THEN //         
	    #TimeACC := 0;
	    #Q := FALSE;
	    #udiCycle := LREAL_TO_UDINT(RUNTIME(#MEM) * 1000000); // " "  
	ELSIF (#IN AND #INPrv) THEN //     ""
	    IF (NOT #Q) THEN
	        #udiCycle := LREAL_TO_UDINT(RUNTIME(#MEM) * 1000000); //     
	        #udiPT := REAL_TO_UDINT(#PT * 1000000); //   
	        #TimeACC += #udiCycle; //     "    "
	        IF #TimeACC >= #udiPT THEN //      
	            #Q := TRUE; //  ""
	            #TimeACC := #udiPT; //  
	        END_IF;
	    END_IF;
	ELSE //    -      
	    #Q := FALSE;
	    #TimeACC := 0;
	END_IF;
	
	#INPrv := #IN; //  
	
	ENO := #Q; // ENO         LAD  FBD
END_FUNCTION

Setelah itu, waktu eksekusi meningkat: waktu pemrosesan idle timer adalah 23 ms, dengan waktu penyaringan kerja 37-40 ms.

Kode fungsi ini tidak memeriksa nilai pengaturan timer yang tidak valid - nilai negatif (jika material dikonversi ke integer yang tidak ditandatangani, pengaturan akan terdistorsi) atau nilai yang lebih besar dari 4294,9 detik (pengaturan waktu akan meluap dan mendistorsi). Anda harus mengontrol nilai nilai PT dalam kode, atau mempercayakan tugas untuk memeriksa rentang pengaturan waktu (dari 0 hingga 4294,9 detik) ke sistem operator tingkat atas. Memeriksa rentang dengan menggunakan program PLC meningkatkan waktu pemrosesan menjadi sekitar 45-46 ms (dan, secara umum, cara yang paling benar adalah dengan mengatur waktu timer tidak dalam format REAL, tetapi dalam format UDINT dalam milidetik dan melakukan omong kosong).

Proyek aplikasi dengan penghitung waktu untuk lingkungan TIA Portal Langkah 7 versi 16 tersedia di sini .

All Articles