Merhaba arkadaşlar, PureBasic kısaca PB, 1600+ komuta sahip modern ve kullanımı kolay bir programlama dilidir. PB ile konsol, form uygulamaları veya 2D/3D oyun geliştirebilirsiniz. Windows için 82 MB boyutu olan 64-bit kurulum dosyasını indirebilirsiniz. Kurulum, diskte 300 MB civarında bir yer kaplıyor. Kurulumu yaptıktan sonra, hemen kod yazmaya başlayabilirsiniz. İndirme sayfasını açınca göreceksiniz, Linux, Mac OS ve Raspberry Pi sürümleri de vardır. Yani isterseniz, yazdığınız kod, hem Windows da hem de Linux de çalışabilecektir. Kurulum dosyası size PB IDE yi kuracaktır. IDE, programı yazmak, derlemek (compile) veya hata ayıklamak (debug) için kullanılan editör veya yazılım geliştirme ortamıdır.
Neden bir dil öğreneyim ki ?
Hem profesyoneller, hem de elektronik veya yazılım meraklıları, bir bilgisayar dilinin, etiket yazıcı, arduino, plc gibi çevredeki cihazlarla haberleşebilme olanaklarını incelerler. Bu bağlamda, PB, ethernet (TCP/IP, UDP), seri port komutlarını içinde barındırmaktadır. Bunların yanı sıra PB, e-posta gönderme, http isteği (request) yollama, rest api kullanımı, web soket kullanımı gibi özel işlevleri de destekler. Hele ki, benim gibi endüstriyel otomasyon işlerinde çalışıyor veya bu alanda çalışmayı hedef olarak belirlemişseniz, bir programlama dili öğrenmek sizi birkaç adım öne taşıyacaktır.
İşiniz gereği, bir tartı ile, bir plc ile, bir HMI ile veya bir SQL sunucu ile haberleşme gereksinimi duyulan projelere dahil olmuş olabilirsiniz. Bu noktada gidip bilgisayar yazılımını sizin adınıza geliştirecek birilerini bulmanız gerekir. Kimseye muhtaç olmadan programlama ile ilgili kendi işini kendisi görmek isteyenlere bu dili tavsiye ederim, öğrenmesi kolay, pratik ve iş bitirici..
Dil öğrenmek, tabii ki ilgi, merak ve keyif alma meselesidir aynı zamanda. Yani bir konudan hem keyif alıyorsunuz hem de o konu işinizle ilgiliyse, öğrenmek daha çekici hale geliyor haliyle.
Neden PureBasic ?
Özellikle programlamaya yeni başlayanlar için çok uygun bir seçim olduğunu söyleyebilirim. Profesyonel bir yazılımcı değilim ama programlama merakım, çocukluğumda bana alınan, oyun bilgisayarı Commodore 64 ile başlamıştı. Zaman içinde C#, Python, Java, Delphi, B4X gibi dilleri incelemiştim. PB’i görünce ilk görüşte aşk derler ya, öyle birşey oldu. PB IDE’de Basic dilinin komutları kullanıldığından öğrenmesi çok kolay. Arduino ile yazılım yapan arkadaşlar zaten temel komutlara aşina olduklarından hiç zorluk çekmeyecekler. Kolay olmasının yanısıra çok kapsamlı bir dil. İlk satırda bahsettiğim 1600+ komut bulunmasının nedeni, işimizi kolaylaştırmak. Temel komutları kavradıktan sonra örneğin bir veritabanı projesi yapmak için veritabanı ile ilgili komutları ve örnekleri incelemek gerekiyor. Diğer dillerde olduğu gibi şu kütüphaneyi buradan, bu kütüphaneyi şuradan indirme durumları yok yani. İhtiyacınız olan herşey PB’nin içinde zaten mevcut durumda.
Diyelim ki bir arkadaşınız, sizden bana şöyle bir program yapar mısın diye istekte bulundu. Programı yazdıktan ve test ettikten sonra, Compiler > Create Executable.. menüsünü seçin. Bir tane exe dosya oluşacaktır. İşlem tamam.. Bu minik dosyayı usb hafızada arkadaşınıza verdiniz. Arkadaşınız, exe dosyayı çift tıklayarak çalıştırdı, kurulum filan olmayacak, program direk çalışacak. PB, harici hiçbir kütüphaneye bağımlı olmadığından, exe dosyanın arkadaşınızın bilgisayarında direk çalışması gayet doğal bir olaydır.
PB geliştirme ortamı da taşınabilir (portable) durumdadır. Diskte, Program Files altında bulunan PureBasic dizinini, usb hafızaya kopyalayın. Ve istediğiniz bilgisayara takıp, program geliştirmeye usb hafıza ile devam edin. Örneğin, PB forum sitesinden birinin yazdığı kaynak kodu kopyalayın. IDE de New butonuna basın, boş sayfa açılsın. Ardından kodu yapıştırın ve Run butonuna basın. Program otomatik olarak derlenip, çalışacaktır.
PB, prosedürel bir dildir. Başka bir deyişle Java gibi nesne yönelimli (OOP) değildir. Bu özellik de programlamaya yeni başlayanlar için büyük bir avantajdır. Java öğrenirken, bu nesne olaylarını kavramakta gerçekten zorlandığımı hatırlıyorum. Neyse ki, PB öyle değil. Hangi satırın ne zaman çalışacağını tahmin etmeniz çok kolay şöyle ki yazdığınız program, yukarıdan aşağıya doğru sırayla satır satır çalışır. Tabii ki yazdığınız prosedür (alt program) tanımlandığı anda değil çağırıldığı anda çalışır.
Basit bir form örneği
;Bu komutla her değişkenin tanımlanmasını zorunlu tutuyoruz
EnableExplicit
;Değer almayan ve geriye değer döndürmeyen bir prosedür
;Butona tıklayınca çağırılır
Procedure MesajGoster()
MessageRequester("Bilgi", "Butona tıkladınız!", #PB_MessageRequester_Ok)
EndProcedure
;#PB ile başlayan sabitler PB içinde bulunan önceden tanımlanmış sabitlerdir
;Bunları Tools > Structure Viewer > Constants sekmesinde görebilirsiniz
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
;Debug ile hata ayıklarken, değişkenleri Debug penceresine yazdırabiliriz
Debug "FLAGS : " + #FLAGS
;Define ile değişkenleri tanımlıyoruz
;Örneğin Define.s değişkenin string olduğunu tanımlar
;Define dan sonra . koymazsak değişken integer olur
;Define.i diye tanımlarsak da integer olur
Define WindowWidth = 400, WindowHeight = 200, Event
;Pencere açılıyor
OpenWindow(0, 0, 0, WindowWidth, WindowHeight, "Merhaba Dünya", #FLAGS)
;ilk sayı Gadget numarası yani kimliği
ButtonGadget(1, 150, 80, 100, 30, "Tıkla")
;Repeat Until arasındaki kodlar tekrarlanır
;Until yanındaki koşul oluşana kadar
Repeat
Event = WaitWindowEvent()
If Event = #PB_Event_Gadget
Select EventGadget() ;Hangi Gadget'a tıklandı
Case 1 ;Gadget numarası 1 olan butona tıklandı
MesajGoster()
EndSelect
EndIf
Until Event = #PB_Event_CloseWindow ;Pencere kapata tıklanırsa
Yukarıdaki kodu kopyalayıp, IDE’de New ile açacağınız boş sayfaya yapıştırın ve Run butonuna basın.. Ctrl tuşu ile farenin tekerini kullanarak, veya Ctrl basılıyken + ve – ile yazdığınız kodları büyütüp küçültebilirsiniz. Ctrl + 0 ile ilk haline döner. Ctrl + A ile tüm kod seçilir ardından Ctrl + I ile format girintileri otomatik olarak düzenlenir. If – EndIf arasındaki satırların içeri girmesi gibi. Böylece kodlar daha okunaklı hale gelir.
Arduino ile Modbus RTU projesi
Modbus protokolü fabrikalarda, otomasyon işlerinde kullanılmaktadır. Proje için bir tane potansiyometre, bir Arduino Uno ve usb kablosuna ihtiyacımız var. Arduino’ya bağlı usb kablo, bilgisayarda seri port olarak tanınmaktadır. Pot’u çevirdiğimizde analog pin’den 0-1023 arasında değerler okunacaktır. Bu bilgi bilgisayarda çalışan PB kodu ile Arduino’dan modbus protokolü ile okunacaktır. PB’de birçok komut olmasına rağmen modbus ile ilgili komutlar yok malesef. C# da modbus kütüphanesi vardı, neyse ki PB’de kütüphanenin işini biz programlamayla yapabiliyoruz. Bunun için hemen forumda bir araştırma yapıyoruz. Google Chrome’da adres satırına “modbus site:https://www.purebasic.fr/english/” yazdığınızda forumda modbus geçen konular çıkacaktır. Forum 20 yıllık mesajları içeriyor. Yılların tecrübesinden faydalanıyoruz. Tabii kodları kendi ihtiyacımıza göre adapte etmek gerekiyor. Bunun için de dile biraz hakim olmanız gerekiyor. Hakim olmanız için de biraz çalışmanız gerekiyor. Burada infratec takma adıyla tecrübeli bir kullanıcı birşeyler karalamıştı sağolsun. Bu arada foruma üye olup, birşey sorarsanız, selamımı söylemeyi unutmayın lütfen.
Arduino’yu modbus slave (sunucu) olarak çalıştırıyoruz. Arduino kütüphanesini buradan indirebilirsiniz. Arduino bekliyor, PB sorgulama yaptığında, Arduino cevap veriyor.
#include <ModbusRTUSlave.h>
ModbusRTUSlave modbus(Serial);
uint16_t holdingRegisters[20] = {0};
uint16_t pot;
void setup() {
modbus.configureHoldingRegisters(holdingRegisters, 2);
modbus.begin(1, 9600, SERIAL_8N1); // slaveID = 1
}
void loop() {
pot = analogRead(A5);
holdingRegisters[0] = pot;
holdingRegisters[1] = pot * 10;
modbus.poll();
}
Arduino kodunda iki tane holdingRegister tanımlanıyor. İlkine pot değeri (0-1023), ikinciye bu değerin 10 katı yazılıyor. Herbiri modbus protokolünde word değeridir, yani 16-bit değerlerdir. Aşağıdaki PB kodunu çalıştırınca “Use Compiler Option ThreadSafe!” hatasını alacaksınız. Compiler > Compiler Options > Create threadsafe executable seçeneğini tıklayın. Programı tekrar çalıştırın, çalışacaktır. Program 2 saniyede bir Arduino’dan değerleri okuyup konsol ekranında gösterecektir. Bu esnada potu çevirince değerlerin değiştiğini görebilirsiniz.
Burada form ile değil konsol ile çalıştım. Formda pencere zamanlayıcısı (window timer) adında bir komut var. Ama konsol uygulamasında böyle bir komut yok. 2 saniyede bir okuma yaptırmak için thread komutlarından yararlandık. Burada da forumdan mk-soft sağolsun, varolsun. Ana program birşey yaparken, thread’e başka birşey yaptırabilirsiniz. Thread olayını diğer dillerde kullanmak çok zor diye bildiğimden o işlere hiç girmemiştim. PB’de ise çok daha kolay. Bu arada dosyayı diske kaydetmek için Belgelerim dizininde yeni bir dizin oluşturun. Programı kaydederken dosyaya .pb uzantısını vermeyi unutmayın.
; modbus RTU code from infratec
; https://www.purebasic.fr/english/viewtopic.php?t=85050
; console timer (thread) from mk-soft
; https://www.purebasic.fr/english/viewtopic.php?t=73927
EnableExplicit
CompilerIf Not #PB_Compiler_Thread
CompilerError "Use Compiler Option ThreadSafe!"
CompilerEndIf
Structure udtThread
ThreadID.i
Signal.i
Ready.i
EndStructure
Enumeration
#ModBus_FunctionCode_ReadCoils = $01
#ModBus_FunctionCode_ReadDiscreteInputs ; 2
#ModBus_FunctionCode_ReadHoldingRegisters ; 3
#ModBus_FunctionCode_ReadInputRegisters ; 4
#ModBus_FunctionCode_WriteSingleCoil ; 5
#ModBus_FunctionCode_WriteSingleRegister ; 6
#ModBus_FunctionCode_WriteMultipleCoils = $0F
#ModBus_FunctionCode_WriteMultipleRegisters
EndEnumeration
Global ModBus_RTU_Echo.i, Work.udtThread
Work\Signal = CreateSemaphore()
Procedure.u ModBus_CalcCRC(*Ptr, Len.i)
Protected CRC_Value.u
Protected i.i
CRC_Value.u = $FFFF
Len - 1 ; means Len = Len - 1
For i = 0 To Len
CRC_Value = (CRC_Value >> 8) ! PeekU(?ModBus_CRCTable + (PeekA(*Ptr + i) ! (CRC_Value & $FF)) << 1)
Next i
ProcedureReturn CRC_Value
EndProcedure
Procedure.i ModBus_CheckCRC(*Ptr, Len.i)
Protected Result.i, CalcCRC.u
Len - 2
CalcCRC = ModBus_CalcCRC(*Ptr, Len)
If CalcCRC = PeekU(*Ptr + Len)
Result = #True
EndIf
ProcedureReturn Result
EndProcedure
Procedure.u ModBus_BigEndian16(Value.u)
ProcedureReturn PeekA(@Value) << 8 | PeekA(@Value + 1)
EndProcedure
Procedure.i ModBus_RTU_ReadHoldingRegisters(Port.i, Address.i, StartRegister.i, RegCount.i, Array Registers.u(1))
Protected Result.i, *Buffer, i.i, Timeout.i, Size.i
Result = -1
*Buffer = AllocateMemory(128)
If *Buffer
PokeA(*Buffer, Address)
PokeA(*Buffer + 1, #ModBus_FunctionCode_ReadHoldingRegisters)
PokeU(*Buffer + 2, ModBus_BigEndian16(StartRegister))
PokeU(*Buffer + 4, ModBus_BigEndian16(RegCount))
PokeU(*Buffer + 6, ModBus_CalcCRC(*Buffer, 1 + 1 + 2 + 2))
PrintN("") : Print ("Request : ")
For i = 0 To 7
Print ( Hex(PeekA(*Buffer + i)) + "-" )
Next
;ShowMemoryViewer(*Buffer, 100) ; to see this memory in ram
;CallDebugger ; to stop program here
WriteSerialPortData(Port, *Buffer, 1 + 1 + 2 + 2 + 2)
If ModBus_RTU_Echo
ReadSerialPortData(Port, *Buffer, 1 + 1 + 2 + 2 + 2)
EndIf
i = 0
Timeout = 500
PrintN("")
Print ("Response : ")
Repeat
If AvailableSerialPortInput(Port)
ReadSerialPortData(Port, *Buffer + i, 1)
Print ( Hex(PeekA(*Buffer + i)) + "-" )
i + 1
; in case of an incorrect request from master, slave response has a different func.code than $03
If i = 5 And PeekA(*Buffer + 1) <> #ModBus_FunctionCode_ReadHoldingRegisters
Result = PeekA(*Buffer + 2) ; Result may be 1, 2, 3
Break
EndIf
Size = 1 + 1 + 1 + PeekA(*Buffer + 2) + 2
If i = Size : PrintN ( " " )
If ModBus_CheckCRC(*Buffer, Size)
RegCount - 1
ReDim Registers(RegCount)
For i = 0 To RegCount
Registers(i) = ModBus_BigEndian16(PeekU(*Buffer + 3 + 2 * i))
Next i
Result = 0 ; in case of successful response from slave
Else
Result = -2 ; in case of incorrect CRC from slave
EndIf
Break
EndIf
Else
Delay(1)
Timeout - 1
EndIf
Until Timeout = 0
If Timeout = 0
Result = -10 ; in case of timeout or no response from slave
EndIf
FreeMemory(*Buffer)
EndIf
ProcedureReturn Result
EndProcedure
OpenConsole("Modbus RTU Test with PureBasic")
EnableGraphicalConsole(1)
Procedure thWork(*Data.udtThread) ; *Data is a pointer, it points an address
Protected KeyPressed$
Repeat
KeyPressed$ = Inkey()
Delay(2000)
SignalSemaphore(*Data\Signal)
Until UCase(KeyPressed$) = "X" ; Wait until X is pressed
*Data\Ready = #True
SignalSemaphore(*Data\Signal)
EndProcedure
; set your COM port name as a second parameter of OpenSerialPort
If OpenSerialPort(0, "COM3", 9600, #PB_SerialPort_NoParity, 8, 1, #PB_SerialPort_NoHandshake, 1, 1)
PrintN ("Port is opened, wait a moment..")
Delay(3000) ; if I remove this, arduino send no response to request after restarting pc
Else
PrintN ("Failed : can not open port!")
Delay(3000)
End
EndIf
Dim Words.u(0)
Define i, Result, Quantity
; change Quantity to 0 to see a result of an incorrect request
Quantity = 2; holding registers quantity
Work\ThreadID = CreateThread(@thWork(), Work) ; @ means the address of procedure thWork()
Repeat
; change slaveID address 1 to 5 below to see timeout and no response from slave
Result = ModBus_RTU_ReadHoldingRegisters(0, 1, 0, Quantity, Words())
; we call the procedure and pass the values to the procedure
; Words() array passes by reference (address) to the procedure
; that's why it's name is not important for the procedure
PrintN ("")
PrintN ("Registers read from arduino with modbus RTU : ")
For i = 0 To ArraySize(Words())
PrintN ("Words(" + i + ") : " + Words(i))
Next
PrintN ("")
PrintN ("Result : " + Result ) : PrintN ("")
PrintN ("Press X to eXit")
WaitSemaphore(Work\Signal) ; program waits here until the signal comes back by SignalSemaphore
ClearConsole()
Until Work\Ready
End
; ModBus CRC16 data
DataSection
ModBus_CRCTable:
Data.u $0000, $C0C1, $C181, $0140, $C301, $03C0, $0280, $C241
Data.u $C601, $06C0, $0780, $C741, $0500, $C5C1, $C481, $0440
Data.u $CC01, $0CC0, $0D80, $CD41, $0F00, $CFC1, $CE81, $0E40
Data.u $0A00, $CAC1, $CB81, $0B40, $C901, $09C0, $0880, $C841
Data.u $D801, $18C0, $1980, $D941, $1B00, $DBC1, $DA81, $1A40
Data.u $1E00, $DEC1, $DF81, $1F40, $DD01, $1DC0, $1C80, $DC41
Data.u $1400, $D4C1, $D581, $1540, $D701, $17C0, $1680, $D641
Data.u $D201, $12C0, $1380, $D341, $1100, $D1C1, $D081, $1040
Data.u $F001, $30C0, $3180, $F141, $3300, $F3C1, $F281, $3240
Data.u $3600, $F6C1, $F781, $3740, $F501, $35C0, $3480, $F441
Data.u $3C00, $FCC1, $FD81, $3D40, $FF01, $3FC0, $3E80, $FE41
Data.u $FA01, $3AC0, $3B80, $FB41, $3900, $F9C1, $F881, $3840
Data.u $2800, $E8C1, $E981, $2940, $EB01, $2BC0, $2A80, $EA41
Data.u $EE01, $2EC0, $2F80, $EF41, $2D00, $EDC1, $EC81, $2C40
Data.u $E401, $24C0, $2580, $E541, $2700, $E7C1, $E681, $2640
Data.u $2200, $E2C1, $E381, $2340, $E101, $21C0, $2080, $E041
Data.u $A001, $60C0, $6180, $A141, $6300, $A3C1, $A281, $6240
Data.u $6600, $A6C1, $A781, $6740, $A501, $65C0, $6480, $A441
Data.u $6C00, $ACC1, $AD81, $6D40, $AF01, $6FC0, $6E80, $AE41
Data.u $AA01, $6AC0, $6B80, $AB41, $6900, $A9C1, $A881, $6840
Data.u $7800, $B8C1, $B981, $7940, $BB01, $7BC0, $7A80, $BA41
Data.u $BE01, $7EC0, $7F80, $BF41, $7D00, $BDC1, $BC81, $7C40
Data.u $B401, $74C0, $7580, $B541, $7700, $B7C1, $B681, $7640
Data.u $7200, $B2C1, $B381, $7340, $B101, $71C0, $7080, $B041
Data.u $5000, $90C1, $9181, $5140, $9301, $53C0, $5280, $9241
Data.u $9601, $56C0, $5780, $9741, $5500, $95C1, $9481, $5440
Data.u $9C01, $5CC0, $5D80, $9D41, $5F00, $9FC1, $9E81, $5E40
Data.u $5A00, $9AC1, $9B81, $5B40, $9901, $59C0, $5880, $9841
Data.u $8801, $48C0, $4980, $8941, $4B00, $8BC1, $8A81, $4A40
Data.u $4E00, $8EC1, $8F81, $4F40, $8D01, $4DC0, $4C80, $8C41
Data.u $4400, $84C1, $8581, $4540, $8701, $47C0, $4680, $8641
Data.u $8201, $42C0, $4380, $8341, $4100, $81C1, $8081, $4040
EndDataSection
Bu program 200 satır civarında oldu. Demo PB, 800 satıra kadar size herhangi bir kısıtlama yapmıyor. PB’yi tanımak ve öğrenmek için gayet yeterli bu satır sayısı sınırı bence. PB’i beğenirseniz, 79€ gibi bir ücreti var. Satın alırsanız ömür boyu, programı güncelleme hakkınız bulunuyor. PB, sürekli geliştirildiğinden yeni versiyonların çıktığını sıklıkla görebilirsiniz. Şuan V6.11 diye biliyorum.
Çok eski versiyonlarla yazılmış bazı programları çalıştırdığınızda bazı komutlar için “Deprecated” yani kullanımdan kaldırılmıştır hata mesajı alabilirsiniz. Bu komutları silerseniz, kod çalışabilecektir.
F5 tuşuna veya Run butonuna bastınız, ve karşınıza “Cannot execute the file with the internal debugger. Please try the standalone one.” gibi bir hata mesajı çıktı. Windows Defender, derlenen PB dosyasının Exe olmasını engelleyebilir. PB dosyanızı Belgelerim altında bir dizine kaydedip, o dizini Defender’ın kontrol etmemesini sağlayabilirsiniz.
Modbus programı iş başındayken konulu kısa filmi Youtube’dan izleyebilirsiniz..
PureBasic bilgi kaynakları
İnternette birçok bilgi bulabilirsiniz. Ama hepsi ingilizce veya başka dillerde malesef. Blog sayfamda PB ile ilgili birkaç yazı yazmıştım. 6 Haziran 2024 tarihinde başlayan yazılarıma bakabilirsiniz. Sadece PB projelerimi paylaşacağım yeni blog sayfam GitHub.IO ‘da, Arduino ve PB’i bir protokol olmadan normal seri port ile haberleştireceğiz, takipte kalınız..
İngilizce bir web sitesinin tamamını Türkçe’ye çevirmek için Google translate, bunun yanısıra paragrafları çevirmek için DeepL veya chatGPT kullanabilirsiniz.
En önemli kaynağınız PB’in yardım dosyalarıdır.. Editör veya IDE’de bir komuta tıkladıktan sonra F1 tuşuna basarsanız yardım sayfası açılacaktır. Burada örnek kodlar da olabilir. Yardım sayfasının aynısı internette de online olarak mevcut durumdadır.
Yine PB ile kurulan C:\Program Files\PureBasic\Examples dizinindeki örnek dosyalara bakabilirsiniz. PB Forumundan bahsetmiştim. Buraya üye olup birşey sorarsanız, cevap veriyorlar. Tanıştığınız kişilere direk mesaj da (PM) yollayabilirsiniz. Bana da PM yollayabilirsiniz. Vaktim oldukça yanıtlarım. Ayrıca forumda nasıl bir konuyu arayabileceğinizden bahsetmiştim.
Not : Forumda özellikle eski paylaşımlarda görebilirsiniz, sonunda alt çizgi olan tüm prosedürler veya komutlar Microsoft Win32 API fonksiyonlarıdır. PB yardım dosyasında bunları göremezsiniz.
GitHub da birçok kod örneği mevcut…
2006 Tarihinde yazılmış bir kitap var ücretsiz indirebilirsiniz. Kullanımdan kalkan komutları silin kodlar çalışacaktır. Forum üyelerinden, Kale takma adlı kullanıcı yazmış zamanında..
chatGPT ye PB ile istediğiniz bir programı yazdırabilirsiniz. “purebasic ile bir buton ve text box içeren program yazarmısın” dediğimde hemen yazdı. Ama dikkatli olun. Komut uydurabiliyor veya kullanımdan kalkmış komutları yazabiliyor. TextBoxGadget() diye bir komut uydurdu, öyle birşey yok PB’de. TextGadget() ve StringGadget() var.. Microsoft .NET’de form yaparken geçen controls, PB’de gadget olarak geçiyorlar.
Yine chatGPT gibi size kod yazabilen DeepSeek var. Ama sanki bu daha çok sallıyor komutları..
Bazı forum kullanıcılarının web siteleri veya forumda imzalarında kullandıkları linkler var.. Github sayfamda birkaçını paylaştım.
Diskte Program Files altında PureBasic\Examples\3D\Demos içinde bulunan Character.pb dosyasını çalıştırmayı unutmayın. 3D bir arkadaş çıkıyor ekrana, yön tuşları, boşluk tuşu ve fare ile yönlendirebilirsiniz.. Bol PureBasic’li günler dilerim..