C# ile Seri Port İletişim

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

ferdem

send fonksiyonunu byte göndermek için yazmıştım ve 123 ü 123 olarak gönderiyordu, bir byte tan daha büyük(>255) bir değer için deneme yapılırsa ne olur bilemiyorum.
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?
Hemen deneyebebilirsiniz; textboxa 123 yazalım, send(Byte.Parse(textBox1.Text.ToString())); ile gönderelim, PIC tarafında da:
#INT_RDA
void data(){
dt=getc();
if (dt==123)
output_toggle(pin_b0);
}

yazıp led toggle durumuna bakalım.Proteus ta da görebilirsiniz.
b0 ledi toggle olmadı o zaman hemen şunu deniyoruz:
#INT_RDA
void data(){
dt=getc();
if (dt==123)
output_high(pin_b0);
putc(dt);// 123 almadıysan ne aldın?, proteus ta virtual terminalden görebilirsiniz
}


Kesme fonksiyonunda "led" değişkenini aradan çıkarabilirsiniz(sadece bir defa if yazmanız yeterli görünüyor), ayrıca ledlerin sürelerinin ayarlanmasından önce ledleri on-off yapmayı deneyin, şöyle olabilir:

#INT_RDA
void data(){
dt=getc();
if (dt==100){
 output_toggle(led1); //define led1 pin_bx varsayilsin
} 
if(dt==101){
 output_toggle(led2);
}
if(dt==102){
 output_toggle(led3);
}

}


on-off çalıştıktan sonra süre olayında sorun çıkarsa tekrar yazarsınız. İyi çalışmalar dilerim.

vitruvius

Merhaba, sanırım mantığıma yatmadığı için bu kadar zorlanıyorum. Şimdi C#'ta:
//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()));
            }
        }


kodunu yazıyorum. Buradaki 100-101-102'yi yollamamın sebebi hangi textbox'tan bilginin geldiğini anlamaya çalışmak. Çünkü her textbox bir adet led'i kontrol edecek. Ama peşpeşe aralık vermeden byte göndermek sağlıklı olur mu, yani CCS C'de bunları anında alabilir miyim onu bilmiyorum?

Bu kısmını geçip CCS C'de kafama yatmayan ise;

#INT_RDA
void data()
{
dt=getc();
if (dt==100)
{
 output_toggle(pin_b0);
 dt=getc();
 s1=1000*dt;
} 
if(dt==101){
 output_toggle(pin_b1);
 dt=getc();
 s2=1000*dt;
}


Burada şunun olmasını umuyorum; (textbox1 için konuşursam) öncelikle bakıyorum ilk aldığım byte 100 mü? 100 ise diyorum ki 100 gelmiş demek ki textbox1'in içinden gelecek sıradaki byte. O zaman diyorum ki sıradaki byte'ı da getc ile alayım ve mili saniye cinsinden çalıştığım için 1000 ile çarpayım. (Bu arada bu sıradaki byte'ı tekrar alma bunu yazarken aklıma geldi ama aralara dt=getc() sıkıştırmasam da bir şey değişmiyor) Sonra bu saniye cinsine çevirdiğim sayıyı bir değişkene atayıp delay_ms'in içine yazıyorum.

Bu arada deneme amaçlı dediğiniz gibi virtual terminal bağlayıp ne aldığımı görmek istedim. Virtual terminal'de karakterler gördüm. Biraz araştırma yapınca bunların C#'ta gönderdiğim byte'lerın ASCII olarak yollandığını anladım. Yazılarla işim olmadığından gelen ASCII (sayısal bilgilerle) bilgileriyle işleme devam ettim.

Bahsettiğiniz on-off işini verdiğiniz örnek gibi araya  output_toggle(); komutunu ekleyerek yaptım bilmiyorum doğru mu yaptım.

Devreyi çalıştığımda ledlerin süreleri yine kontrolsüz ve çok hızlı yanıyor. C#'tan veri yollamasam da aynı şekilde oluyor. Devreyi çalışıtırırken de ISIS'te şu warning'i alıyorum: Simulation is not running in real time due to excessive CPU load.

CCS C'de yazdığım kod şu şekilde şu an:

#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

void main()
{
INTCON=0b11000000; //global ve peripheral kesmeler aktifmiş
PIE1=0b00100000; //uart kesmesi ayarlanmış
set_tris_c(0b10000000);
set_tris_b(0x00); //tümüyle çıkış olsun
output_b(0x00); //Sıfırlayalım

while(1)
{     
      output_high(pin_b0);
      delay_ms(s1);
      output_low(pin_b0);
      output_high(pin_b1);
      delay_ms(s2);
      output_low(pin_b1);
      output_high(pin_b2);
      delay_ms(s3);
      output_low(pin_b2);
      
}
}

#INT_RDA
void data()
{
dt=getc();
if (dt==100)
{
 output_toggle(pin_b0);
 dt=getc();
 s1=1000*dt;
} 
if(dt==101){
 output_toggle(pin_b1);
 dt=getc();
 s2=1000*dt;
}
if(dt==102){
 output_toggle(pin_b2);
 dt=getc();
 s3=1000*dt;
}

}

50Cal

#47
Öncelikle kendinizi zora soktuğunuzu görüyorum, henüz temeli oturmamış bir konuya fazladan eklemeler yapıyorsunuz ve bu şekilde işin içinden çıkmanız zorlaşıyor.
İlk olarak, birden fazla textboxtan gelen veriyi ayırma çalışmadan önce tek bir textboxtan gelen veriyi, sıfır hata ile alıp tek bir ledi ona göre yakıp söndürebilmelisiniz. Bunu sorunsuz yapabildikten sonra 3 değil 30 tane ayrı veri gönderilse kolayca ayrıştırılabilirler.

Dikkat edilmesi gerektiğini düşündüğüm bir kaç noktayı sıralayayım:

1) Öncelike 1 byte'tan büyük verilerle çalışmayın, textboxtan gönderilecek sayı şimdilik maks. 255 olsun. Yani nasıl pic tarafında birer byte şeklinde veri alıyorsak, c den de byte byte veri gönderilmeli, string şeklinde olmamalı.
2) Veri tipi olarak, hem c#'tan göndereceğiniz sayının atandığı değişkenin, hem de ccs'te verinin atanacağı değişkenin unsigned int(bir byte lık işaretsiz tamsayı) olmasına dikkat edin.
3) Gelen verinin ne olduğunu görmek için, sonsuz döngü içerisinde lcd ye yazdırmak en kolay debug yöntemi olacaktır. printf(lcd_putc,"\f%u",gelen verinin atandığı değişken)
4) C# tan gönderilen verinin karakter tipi olmadığından, sayısal değer olduğundan emin olun. örn textboxa 7 yazdığınızda iletilen veri 7 olmalı, 7 karakterinin ascii karşılığı değil.
5) C# ta her bir byte gönderimi arasına 10ms 20 ms gibi bir bekleme koyulursa, proteustaki "gerçek zamanlı sim. yapılamıyor" hatasının önüne geçilmiş olur. Aynı şekilde, ccs te sonsuz döngü içerisinde lcdye veriyi yazdırırken araya bir gecikme koyun ki hem görüntü titremesin hem o hataya yol açılmasın.
6) 3 ayrı textboxtan gelen veriyi almaya çalışırken kesme içerisinde tekrar getc ile veri beklemişsiniz. Bunun yerine tb1 tb2 tb3 şeklinde logic değişkenler(int1) tanımlayıp, bunların durumunu if kontrolleriyle gelen veriye göre değiştirirseniz daha sağlıklı olur. Bu konuyla şimdilik uğraşmayın, burası kolay kısmı. Siz tek textboxtan gelen veriyi sorunsuz alabilip ledi ona göre yaktırdıktan sonra o kısma bakarız.

Bir picten diğerine 1 bytelık sayı gönderdiğimde, alıcı picte gelen sayıyı aşağıdaki gibi alıyorum. Eğer bu kodu aynen denediğinizde, textbox'a yazılan sayıyı, lcd de göremiyorsanız, "C#'ta 8 bitlik bir sayı seri porttan nasıl gönderilir" onu araştırmalısınız. Kolay gelsin..
char veri;
unsigned int data=1;

#int_rda
void serihaberlesme_kesmesi ()
{
disable_interrupts(int_rda); // int_rda kesmesi pasif
veri=getc();
data=(unsigned int)veri;
}


   while(1) // Sonsuz döngü
   {
      enable_interrupts(int_rda); // int_rda kesmesi aktif
      printf(lcd_putc,"\f%u",data);    
      delay_ms(10);
   }


EKLEME:
Gözden kaçırmışım; zaten ferdem, C#'ta bir sayının, "sayı olarak" nasıl gönderileceğini yazmış ve kullanmışsınız. Tek yapılması gereken yukarıda verdiğim kodda olduğu gibi cast işlemiyle, gelen verinin, karakter tipinden sayı tipine çevrilmesi:

data=(unsigned int)veri;

vitruvius

Merhaba dediklerinizi uyguladım. CCS C'deki tüm değişkenleri unsigned int yaptım. Ancak C#'ta unsigned int yok galiba.

Şimdi şöyle hem virtual terminal hem de lcd bağladım. Lcd ekranda textbox'tan kaç girmişsem onu görüyorum sayı olarak. Virtual terminalde ise ascii karşılığı neyse onu görüyorum. Misal vermek gerekirse; textbox'tan 123 girdiğim zaman lcd'de "123", virtual terminal'de "d" yazıyor.

D portuna bağlı pinlerin kontrolsüz yanması sorunu kalktı ancak hala textbox'tan aldığım değeri delay_ms()'in içine yerleştiremedim. Textbox'tan 1 girdiğimde yavaş yanıyor, 10'da daha hızlı yanıyor, 11'de 1 girmişim gibi yanıyor..

CCS C'de denediğim 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 (d)
#byte INTCON=0x0B
#byte PIE1=0x8C

unsigned int s1; //sürelerimiz
unsigned int dt; //kesme ile gelen data
unsigned int veri;

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_d(0x00); //Sıfırlayalım
lcd_init();

while(1)
{     

printf(lcd_putc,"\f%u",veri);
delay_ms(10);
      output_high(pin_d0);
      delay_ms(s1);
      output_low(pin_d0);
      delay_ms(s1);      
}
}

#INT_RDA
void data()
{
dt=getc();
veri=(unsigned int)dt;
s1=1000*veri;

}



50Cal

Merhaba, yazdan beri c#'ı açmadım, veri tiplerinde farklılık var, doğru. Bir byte lık bir integer tanımlarsanız 127'nin üzerine çıkamazsınız diye öyle söylemiştim, çalışıyorsa sorun yok.
Virtual terminal de ascii karşılıklarını görürsünüz bu normal. Zaten lcd'den takip etmek daha kolay demem bundandı.
Delay_ms() fonksiyonunun 16bit'e kadar değer alabildiği yazıyor ccs helpinde, sorun neyden kaynaklanıyor göremedim. O 1000 çarpanını 10 yada 100e düşürüp denediğinizde durum ne?

Timer kullanımını öğrenip bu tip gecikmeleri timerla yapmalısınız. 10 snlik delay, programı öldürür. Öyle bir kod varken program led yakıp söndürmekten başka birşey yapamaz.

vitruvius

Zaten led yakıp söndürmesinden başka bir şey istemiyorum =) Ama led sayısı 20 civarında. Eğer kastınız veri alamaz ise o zaman sabaha kadar timer çalışırım =) Hımm, evet çarğanı 10'a düşürdüğümde daha mantıklı sonuçlar çıktı. En azından textbox'tan yolladığım değer arttıkça yanıp sönme yavaşlıyor. Şu var yalnız textbox'tan 100 yazdığımda bunu 10'la çarpıp 1 saniye beklemesi gerekir ama öyle bir bekleme yok. Timer'la bu işi halledebilir miyiz? Sabaha kadar çalışmayan kod deniyorum, en azından timer öğrenirim sabaha kadar. Teşekkürler.

vitruvius

Merhabalar, sorunumu şu an çözdüm. s1'i 8 bit üstü çalıştığım için unsigned long olarak tanımlamak gerekiyormuş. Şimdi textbox sayısını arttırıp deneyeceğim.

Onu hallettim diyelim seri iletişimsiz denemiştim başlarda projemi... O zaman bir sorunla karşılaşmıştım: Led sayımı arttırdığımda while içinde her led'in yanıp sönme komutlarını yazdığım zaman program yukarıdan aşağıya işliyor. Yani iki led'i aynı anda yakamıyorum. Şu var; trafik lambası yapacağımdan C# simulasyonunda 3'lü 3'lü (direk direk) gruplayıp öyle kodluyorum. if'lerle de on-off durumunu kontrol ettiğim zaman bütün if blokları birbirinden bağımsız zamanda çalıştığı için hem aynı anda birden fazla ışık yanıyor, hem de bir direğin durumunu on yada off yaptığım zaman anında tepki alıyorum. CCS C'de ise program yukarıdan aşağıya işliyor yani bir led sönmeden diğeri yanmıyor. C#'ta yaptığım gibi 3'lü 3'lü olarak birbirlerinden bağımsız gruplayıp nasıl kodlayabilirim? Timer kullanarak olur mu?

Herkese çok çok teşekkür ediyorum.

50Cal

Timer kullanmamak, bu uygulamada veri alımında sorun oluşturmaz çünkü veri kesme içerisinde alınıyor.
2. mesajdaki sorunun ilacı tam olarak, timer kullanımı.

vitruvius

Birden fazla textbox kullanma işini ferdem'in verdiği örneği inceleyerek şu şekilde yaptım ve çalışıyor:

C#:

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


CCS C:

#INT_RDA
void data()
{
dt=getc();
if(dt==100)
{
led=1;
}
if(dt==101)
{
led=2;}
if(dt<100){
if(led==1){
s1=1000*dt;}
if(led==2)
{s2=1000*dt;}
}
}


Şimdi timer kullanarak ledleri aynı anda yakma işim kaldı sanırım bir tek.. Nerde şu Serdar Çiçek'in kitabı  :)

Mantığını anlamak için soruyorum dt 100'den ne zaman küçük olur? Çünkü o kısmı yazmayınca çalışmıyor. Bir de hem diyoruz ki dt=101 ise hem de sonra aynı dt değişkenini textboxtan aldığımız değere atıyoruz. Yani bir değişkeni birden fazla bilinmeyene atıyoruz, burada sorun çıkmamasının sebebi C#'ın byte byte sırayla yollaması ve CCS C'nin de değerleri byte byte sırayla anında alması mıdır? Teşekkürler.

50Cal

Elinizdeki kitaptan temel konuları okumanız gerekiyor. Timer çalışmadan önce de kesme konusunu öğrenin mutlaka yoksa bir süre sonra herşey birbirine girebilir, temeli sağlam tutmaya bakın.

-c# tarafından gönderilen bytelar koddaki yazım sırasına göre gönderilir. önce 100, ardından ona ait süre(tb1), 101 ve ona ait süre(tb2).
-ccs'te ise pice her bir byte geldiğinde program kesmeye gider.

ilk byte geldi kesme oluştu..
ne geldi?
100
dt=100
led=1 yapıldı ve diğer ifler kontrol edildi..
dt=100 olduğu için diğer iflere girilmez ve kesme fonksiyonundan çıkar program..
hemen ardından c#, textbox 1 deki sayıyı gönderdi, veri pice geldi, program yine kesmeye girdi.
ne geldi?
sayı (sanırım bu sayı değerleri hep 100'ün altında, ki öyle olmalı bu kodun çalışması için)
dt=sayı
sayı<100 olduğundan aşağıdaki if grubuna girer program
led neydi? 1
if(led==1) koduna geçer ve dt değerini 1000 le çarparak s1 e atar.
dt son durumda sayı olduğu için istenen işlem yapılmış olur.

böyle devam eder..


vitruvius

Buradaki sorunu şu şekilde çözdüm:

while(1)
{     
   Counter1++;   
   
   delay_ms(1000);
   
   // 1. Direk  
   if(Counter1==1)
   { output_low(pin_b2); 
     output_high(pin_b0); }
   if(Counter1==Direk1_Kirmizi)
   { output_low(pin_b0);
     output_high(pin_b1); }
   if(Counter1==Direk1_Sari)
   { output_low(pin_b1);
     output_high(pin_b2); }
   if(Counter1==Direk1_Yesil)
   Counter1=0;}


Direk_1Kirmizi v.s. değerleri de kesme ile alıyorum. Şu an istediğim işi yapıyor. Herkese teşekkür ederim.

isovski

isiste kullandığınız rs232 portunun 2. ve 3. bacaklarını değiştirip 2. bacağı pic in RX konumuna getiriniz..