C# ile Seri Port İletişim

Başlatan vitruvius, 19 Nisan 2011, 19:11:41

RcALTIN

isis de denerken max232 kullanmanıza gerek yok, compim'e direkt bağlantı yapın. yalnız compim rx = pic rx ve compim tx = pic tx şeklinde bağlayın orada aslında compim'in receive ve transmit ettiği bacakları gösteriyor, yani terslik oluyor; sarı yanması da bu yüzden oluyor.
KİMSEYİ ENGELLEDİĞİM YOK, ÖZEL İLETİ DEVRE DIŞI !

vitruvius

Merhaba, dediğiniz gibi yapınca oldu. Pazartesi elemanları alıncaya kadar kodları geliştirme fırsatım olacak. Size ve diğer arkadaşlara çok teşekkür ederim.

vitruvius

Şimdi de bir led'i sürekli yakıp söndürmeye çalıştım ama bir türlü sonsuz döngüye sokamadım. d4 pini ilk başta yanıyor tabiki döngüde değil farkındayım ama döngüye sokunca da alt satıra geçmiyor program. d7 ve d0 pini ise sadece butona bastığım zaman işliyor. Şöyle bir kod denedim:

#include <16f877.h>
#device ADC=10
#fuses XT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
#use delay (clock=4000000)
#define use_portb_lcd TRUE
#use fast_io(d)
#include <lcd.c>
#use rs232 (baud=9600,rcv=PIN_C7, xmit=PIN_C6, parity=N, stop=1) //rs 232 için

void veri()
{
char x[80];
gets(x);
printf(lcd_putc,"\f%s",x);  //LCD'yi temizle ve x string ifadesini LCD'de göster
output_high(pin_d0); //Kırmızı Işık Yandı
delay_ms(500);
output_low(pin_d0); //Kırmızı Işık Söndü
delay_ms(500);
return;
}

void main()
{
setup_psp(PSP_DISABLED);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_CCP1(CCP_OFF);
setup_CCP2(CCP_OFF);
set_tris_d(0x00);
output_d(0x00);

output_high(pin_d4); //Kırmızı Işık Yandı
delay_ms(500);
output_low(pin_d4); //Kırmızı Işık Söndü
delay_ms(500);

lcd_init();

while(1)
{
output_high(pin_d7); //Kırmızı Işık Yandı
delay_ms(500);
output_low(pin_d7); //Kırmızı Işık Söndü
delay_ms(500);
veri();
}
}

50Cal

Program muhtemelen, veri () fonksiyonundaki gets() satırında takılıp kalıyordur. Yanlış hatırlamıyorsam gets() karşıdan veri alma işini bitirene kadar programı orda bekletiyor. Ve C programınız ile proteusu doğru şekilde haberleştiremiyorsanız, gets satırında takılır kalır.
Tabi sorunu bulmanın en kolay yolu debug'tır. Simulasyon yapmaya başladıktan bir süre sonra pause yapıp programın hangi satırda kaldığı görülebilir.

C#'ta yazılan program ile proteusun haberleştiğinden emin misiniz? Bu bağlantıyı ne şekilde yaptınız?

vitruvius

Pause olayını bilmiyordum teşekkür ederim. Dediğiniz gibi gets ()'te kalmış, o yüzden C#'ta butona bastığım zaman ledler yanıyor. Program haberleşiyor, yani textboxa bir şey yazıp butona bastığım zaman lcd ekranda görebiliyorum. Devre bağlantım şu şekilde:



Nasıl bir çözüm önerirsiniz? Teşekkürler.

50Cal

Bilgisayardan bir string gönderdiğinizde bunu pic tarafında seri iletişim kesmesi ile alabilirsiniz, daha sağlıklı olur. Getc() ile karakterleri tek tek alıp sırayla bir stringe atayabilirsiniz, yada gets() ile bütün olarak da alablirsiniz. Bu kesmede de dikkat edilecek en önemli olay, kesmeye girince kesmeleri disable edip, kesme çıkışında kesmeleri aktif etmektir(sonsuz döngüde aktif edilebilir / while(1) ). Ben de seri iletişimle yeni yeni uğraşıyorum, ezbere konuşursam yanlış bilgi verebilirim.
Serdar Çiçek'in kitabı varsa oradan bakabilirsiniz. Yoksa da netten, kitaptaki uygulamalara ait proteus ve ccs dosyalarını indirip uygulamaları simulasyon üzerinde inceleyebilirsiniz. Temel ccs konuları üzerine çok güzel bir kaynaktır, tavsiye ederim.

50Cal

Kitaptaki örneğin fazlalıklarını attım, bilgisayardan gelen stringi almak için kullanılacak yöntem bu şekilde:
char   klavye[80];  // klavye isminde 80 üyeli bir dizi tanımlanıyor

#int_rda   // RX ucuna veri gelince meydane gelen kesme
void serihaberlesme_kesmesi ()
{
   disable_interrupts(int_rda); // int_rda kesmesini pasif yap
   
   gets(klavye); // String ifadeyi al ve "klavye" adlı dizi değişkenine aktar.
}


   // void main()
   enable_interrupts(GLOBAL);  // Aktif edilen tüm kesmelere izin ver

   while(1) // Sonsuz döngü
   {
      enable_interrupts(int_rda); // int_rda kesmesi aktif
   }

vitruvius

Merhaba Serdar Çiçek'in kitabı var, bahsettiğiniz örneği inceledim. Aşağıdaki gibi bir kod yazdım. Şimdi durumumu özetlersem program çalıştığı zaman d7 pinindeki led yanıp sönüyor, textboxtan bir metin girdiğim zaman girdiğim metin bir karakterden fazla ise program donuyor. Pause yapıp baktığımda gets(x)'te beklediğini görüyorum. Eğer tek karakter girersem onu lcd'de görebiliyorum ve d7 pinim yanıp sönmeye devam ediyor. Fakat o tek harfi silip yenisini yazıp butona bastığımda ekrandaki harf değişmiyor, d7 pinindeki led yanıp sönmeye devam ediyor. gets() ile birden fazla karakteri alamayıp o tek karakteri de niye değiştiremiyorum? Teşekkürler.

#include <16f877.h>
#device ADC=10
#fuses XT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
#use delay (clock=4000000)
#define use_portb_lcd TRUE
#use fast_io(d)
#include <lcd.c>
#use rs232 (baud=9600,rcv=PIN_C7, xmit=PIN_C6, parity=N, stop=1) //rs 232 için



#int_rda
void kesme ()
{
char x[80];
disable_interrupts(int_rda);
output_high(pin_d0); //Kırmızı Işık Yandı
delay_ms(500);
gets(x);
printf(lcd_putc,"\f%s",x);  //LCD'yi temizle ve x string ifadesini LCD'de göster
output_low(pin_d0); //Kırmızı Işık Söndü
delay_ms(500);
return;
}

void main()
{
setup_psp(PSP_DISABLED);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_CCP1(CCP_OFF);
setup_CCP2(CCP_OFF);

set_tris_d(0x00);
output_d(0x00);

lcd_init();

enable_interrupts(GLOBAL);

while(1)
{
enable_interrupts(int_rda);
output_high(pin_d7); //Kırmızı Işık Yandı
delay_ms(500);
output_low(pin_d7); //Kırmızı Işık Söndü
delay_ms(500);
kesme ();
}
}

50Cal

Koddaki hatalar:
1) x dizisi kesme içinde tanımlanmış onu global tanımlayın. Bu haliyle kesme fonksiyonu çıkışında dizi silinir.

2) kesme içerisinde gecikme(delay) kullanmak kesmenin askıya alınmasına yol açıyor, yani kesmenin en önemli işlevi olan "kesme" yalan oluyor. İllaki kesme içerisinde delay kullanmak isterseniz aşağıdaki mesajımı ve konuyu incelemeniz faydalı olur.
https://www.picproje.org/index.php/topic,28463.msg196433.html#msg196433

3) lcd komutlarının içerisinde de delay komutu yer aldığından aynı soruna, printf(lcd_putc.. komutu da sebep olur.
Yani lcd komutlarını da kesme içerisinde kullanmayın.
Gecikmeleri, lcd'ye yazdırma işlerini ana döngü içerisinde halledin.
[Kitaptaki örnekte de lcd komutu kesme içerisinde kullanılmış, o da soruna yol açabilir. Kod çalışmazsa ilk şüpheleneceğiniz satır o olmalı]

Ve böyle durumlarda, çalıştığından emin olduğunuz bir kodu bir kere çalıştırıp kendi sisteminizde, devrenizde çalışıp çalışmadığını kontrol edin. Eğer düzgün çalışıyorsa, onun üzerinde oynamalar yapıp her değişiklik sonrası simulasyon yaparak nelerin değiştiğini gözlemlemek, daha kolay ilerlemenizi sağlar. Temel noktalarda hata yaparak kaybedilecek zamanı bolca denemeye ve farklı şeyler öğrenmeye ayırmış olursunuz.

vitruvius

Dediğiniz gibi yaptım, birden fazla karakter alabiliyorum. Ancak textboxtaki yazıyı değiştirip tekrar butona bastığım zaman yeni x'i göstermiyor lcd'de. Bir de esas derdime adım adım gitmeye çalıştığım için yeni geldim. Bu led'lerin yanma sürelerini textbox ile kontrol etmek istiyorum.

delay_ms(x); yazdığım zaman sabit bir değer girilmeli hatası veriyor. Bu x'i dizi olarak tanımladığım için mi oluyor? Yada C#'ta double olarak tanımlamaya çalıştım string'i sayı olarak algılamaz diye ama yine delay_ms(x) denemem olmadı. Teşekkürler.

50Cal

#40
Kodun son halini eklememişsiniz. Debug yaparak dizi içerinin nasıl değiştiğini takip ederseniz ilk sorunun yanıtını bulabilirsiniz.

Gecikme konusunda da delay kullanmak yerine timer içerini kontrol ederek bir gecikme koyulabilir. Timer kesmesine gerek yok sadece timerı aktif edip içeriğini gerekli yerde sıfırlayıp, içerik istenen süre kadar artmış mı diye kontrol ederek gecikme koyulabilir.

Ayrıca anladım kadarıyla pc den pice bir sayı göndermek istiyorsunuz. Bu durumda öncelikle x dizisinin içeriğininden, gönderilen sayıyı oluşturmanız gerekli. Yoksa ne delay fonksiyonu içerisinde ne de başka bir yerde kullanmak istediğiniz sayıyı değil bir dizi rakamı kullanmış olursunuz.

vitruvius

Alıntı yapılan: 50Cal - 02 Mayıs 2011, 11:54:04
Ayrıca anladım kadarıyla pc den pice bir sayı göndermek istiyorsunuz. Bu durumda öncelikle x dizisinin içeriğininden, gönderilen sayıyı oluşturmanız gerekli. Yoksa ne delay fonksiyonu içerisinde ne de başka bir yerde kullanmak istediğiniz sayıyı değil bir dizi rakamı kullanmış olursunuz.

Evet yapmak istediğim şey o. Dediğinizden yola çıkarak başka bir dizi tanımladım. For döngüsü içinde x'in birinci karakterini getc ile alıp ikinci dizimin birinci karakterine atadım. Sonra 3 tane değişken tanımlayıp bunlara ikinci dizimin sırasıyla karakterlerini tek tek atadım. Yani ben böyle düşündüm, lcd'ye de herhangi bir değişkeni yazdırmak istedim doğru mu yapıyorum diye ancak hep 0 görüyorum. Kodum şu şekilde:

#include <16f877.h>
#device ADC=10
#fuses XT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
#use delay (clock=4000000)
#define use_portb_lcd TRUE
#use fast_io(d)
#include <lcd.c>
#use rs232 (baud=9600,rcv=PIN_C7, xmit=PIN_C6, parity=N, stop=1) //rs 232 için

char x[20];
char sayi[4];
int i;
int k;
int y1, y2, y3;


#int_rda
void kesme ()
{
disable_interrupts(int_rda);
for(i=0,k=0;i<4 && k<4;i++,k++)
{
x[i]=getc();
putc(sayi[k]);
}
y1=sayi[1];
y2=sayi[2];
y3=sayi[3];
return;
}

void main()
{
setup_psp(PSP_DISABLED);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_CCP1(CCP_OFF);
setup_CCP2(CCP_OFF);

set_tris_d(0x00);
output_d(0x00);

lcd_init();


enable_interrupts(GLOBAL);
enable_interrupts(int_rda);

while(1)
{

output_high(pin_d7); //Kırmızı Işık Yandı
delay_ms(500);
output_low(pin_d7); //Kırmızı Işık Söndü
delay_ms(500);
kesme ();
printf(lcd_putc,"\f%d",y1); //İlk basamağa bakalım
delay_ms(800);
printf(lcd_putc,"\f%s",x);  //LCD'yi temizle ve x string ifadesini LCD'de göster
}
}

ferdem

50Cal arkadaşın da dediği gibi seri veriyi sonsuz döngü içerisinde kontrol ederek değil de bu iş için ayrılmış donanımı kullanarak kesme ile almalıyız, bu işlemin en sağlıklı yolu kesme ile almaktır, son mesajınızda kesme fonksiyonu yazmışsınız ancak program tam olmamış, örnek koda bakabilirsiniz:
https://www.picproje.org/index.php/topic,32476.msg232425.html#msg232425
Program kesme fonksiyonuna veri geldiği zaman otomatik olarak gider, sonsuz döngüde çağrılmasına gerek yoktur. Kesmenin özelliği bu, sadece gerektiği zaman kapınızı çalar, sürekli kontrole gerek bırakmaz.

Yapmak istediğinize çok benzer bir çalışma var, bakmanızda fayda olabilir: Hobi Servo Sürelim (Bilgisayar Kontrollü) .

Seri kesmesinde enable-disable işlemleriyle bizim uğraşmamıza gerek kalmıyor, kesmeye girdiğimizde GIE 0 oluyor(kesmeler otomatik kapatılıyor), veriyi okuduğumuzda donanım RCIF i 0 a çeker ve kesmeden çıkarken yine donanım tarafından GIE 1 e çekilir. Yukarıdaki örnek koda bakılabilir.

İyi çalışmalar herkese, saygılarımla.

vitruvius

Merhaba öncelikle verdiğiniz örnek için çok teşekkür ederim, çok güzel bir örnek dakikalarca oynadım. Lakin kafamı çok karıştırdı, moralimi de bozdu biraz çünkü mantığını anlamadım.

Şimdi C#'taki kısımda anlamadığım send(200)'ün bir anlamı var mı, yoksa sadece motor belli olsun diye mi yazdık? Bir de send(Byte.Parse(trackBar1.Value.ToString())); ın tam olarak ne iş yaptığını anlamadım. Değer neyse direkt onu mu gönderiyor? Ben kendi programımda send(Byte.Parse(textBox1.Text.ToString())); bunu denedim ama bunu double'a convert etmem gerekmez miydi? Bir de 249'dan fazla değer girdiğim zaman hata veriyor. Bunun sebebini araştırırken okumuştum sanırım bitlerle ilgisi var. Parça parça böl öyle oku deniyordu galiba ama o zaman da bir şey anlamamıştım. Buffer'ı sormayacağım bile =) Onu araştırmam lazım.

CCS C kısmında ise anlamadığım şey; textboxtan 123 girdiğimi düşünürsek bx=getc(); komutunda bx'in 123 olması mı beklenir? Ben öyle düşünüp aşağıdaki gibi kod yazdım ve 250'den küçük değer girdiğim zaman sonuç alabiliyorum ancak lcd'ye yazdıramadım aldığım değeri. #fuses'te INTRC_IO unknown keyword hatası veriyor bu arada. Bir de d7 pinimdeki led sürekli yanıyor, herhangi bir kod yazmama rağmen. Bunun sebebi ne olabilir? Teşekkür ederim.

C#'ta yeni yazdığım kod:

namespace Trafik_isigi_deneme1
{
    public partial class Form1 : Form
    {
        public void send(byte data)
        {
            if (serialPort1.IsOpen)
            {
                byte[] buffer = { 0 };
                buffer[0] = data;
                serialPort1.Write(buffer, 0, 1);
            }
            else
            { MessageBox.Show("Port Açık Değil!"); }
        }
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            comboBox1.DataSource = System.IO.Ports.SerialPort.GetPortNames();
            comboBox1.SelectedItem = 1;
        }

        private void button1_Click(object sender, EventArgs e) //Başlat
        {
            if (!serialPort1.IsOpen)
            {
                serialPort1.PortName = comboBox1.SelectedItem.ToString();
                serialPort1.Open();
            }
        }

        private void button2_Click(object sender, EventArgs e) //Durdur
        {
            if (serialPort1.IsOpen)
                serialPort1.Close();
        }
     

        private void button3_Click(object sender, EventArgs e) //Gönder
        {
            
            send(Byte.Parse(textBox1.Text.ToString()));
        }

    }
}



CCS C'de yeni yazdığım kod:

#include <16F877.h>
#fuses XT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
#use delay(clock=4000000)
#define use_portb_lcd TRUE
#include <lcd.c>
#use rs232(baud=9600, xmit=PIN_C6, rcv=pin_C7,uart1)
#use fast_io (a)
#use fast_io (b)
#byte INTCON=0x0B
#byte PIE1=0x8C

long s1=1000; //farkı anlamak için süre
long dt; //kesme ile gelen data


void main()
{
INTCON=0b11000000; //global ve peripheral kesmeler aktifmiş
PIE1=0b00100000; //uart kesmesi ayarlanmış
set_tris_c(0b10000000);
set_tris_d(0x00); //tümüyle çıkış olsun
output_high(pin_d0); //calisma için
lcd_init();

while(1)
{
printf(lcd_putc,"\f%s",dt); 
      output_high(pin_d5);
      delay_ms(s1);
      output_low(pin_d5);
      delay_ms(s1);           
}
}

#INT_RDA
void data()
{
dt=getc();
s1=dt;
}

vitruvius

Sonuç alıyorum demiştim ama yanlış alıyormuşum.
Alıntı YapCCS C kısmında ise anlamadığım şey; textboxtan 123 girdiğimi düşünürsek bx=getc(); komutunda bx'in 123 olması mı beklenir?
ve aynı şekilde
send(Byte.Parse(textBox1.Text.ToString()));
girdiğim sayıyı direkt yollar mı? Bu soruların cevabını evet olarak düşünüp kodlama yapıyorum.

3 textbox'tan 3 led'i kontrol etmeye çalışıyorum. İncelediğim motor örneğinde 3 trackbar'la 3 motor kontrol ediliyordu. Anladığım kadarıyla hangi trackbar'dan bilgi geldiğinin anlaşılması için send(200); v.b. değerler gönderilip bu değerler CCS C'de yorumlanıyordu. Bende her textbox'ım için bir değer göndermeyi düşündüm ki, hangi led'in süresini hangi değerden hesaplanacağı belli olsun. Bu arada mili saniye cinsinden çalıştığım için değeri de 1000 ile çarptım. Yalnız led'lerimin yanıp sönmesini kontrol edemedim. Yardımlarınız için teşekkür ederim.

C#'ta yazdığım kod:

//Verileri Gönder
        private void button9_Click(object sender, EventArgs e)
        {
            {
                send(100);
                send(Byte.Parse(textBox1.Text.ToString()));
            }
            {
                send(101);
                send(Byte.Parse(textBox2.Text.ToString()));
            }
            {
                send(102);
                send(Byte.Parse(textBox3.Text.ToString()));
            }
        }


Bu send (101) (102) (103) işlemlerini peşpeşe yazarsam bir sıkıntı olur mu?

CCS C'de yazdığım kod:

#include <16F877.h>
#fuses XT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=pin_C7,uart1)
#use fast_io (a)
#use fast_io (b)
#byte INTCON=0x0B
#byte PIE1=0x8C

long s1,s2,s3; //sürelerimiz
long dt; //kesme ile gelen data
int led=1;  // veri hangi led için gelmiş


void main()
{
INTCON=0b11000000; //global ve peripheral kesmeler aktifmiş
PIE1=0b00100000; //uart kesmesi ayarlanmış
set_tris_c(0b10000000);
set_tris_d(0x00); //tümüyle çıkış olsun
output_high(pin_d0); //calisma için

while(1)
{
      output_high(pin_d5);
      delay_ms(s1);
      output_low(pin_d5);
      output_high(pin_d6);
      delay_ms(s2);
      output_low(pin_d6);
      output_high(pin_d7);
      delay_ms(s3);
      output_low(pin_d7);
                 
}
}

#INT_RDA
void data()
{
dt=getc();
if (dt==100)
{led=1;}
if(dt==101)
{led=2;}
if(dt==102)
{led=3;}

if(led==1)
{s1=1000*dt;}
if(led==2)
{s2=1000*dt;}
if(led==2)
{s3=1000*dt;}
}