putc() nin nasıl çalıştığını çözemedim?

Başlatan CaFFeiNe, 12 Ocak 2006, 18:59:13

CaFFeiNe


#include <16F628.h>
#fuses XT, NOWDT, PUT, NOPROTECT, NOBROWNOUT, MCLR, NOLVP, NOCPD
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_B0, rcv=PIN_B1)

void put_to_a(char c)
{
  putc(c);
}

char get_from_a()
{
  return(getc());
}

#use rs232(baud=9600, xmit=PIN_B2, rcv=PIN_B3)

void put_to_b(char b)
{
  putc(b);
}

main()
{
  char c;
  put_to_a("Online\n\r");
  put_to_b("Online\n\r");
  while(TRUE)
  {
    c=get_from_a();
    put_to_b(c);
    put_to_a(c);
  }
}


http://picproje.org/upload/Mevcutdosyalar/rs232.zip

bu CCS nin referans manuelinin son sayfalarındaki bir kod ve devresi
merak ettiğim şu, koda bakarsanız
void put_to_a(char c)
{
  putc(c);
}

putc(c); fonksiyonuna "Online\n\r" değeri gönderiliyor ve doğru bir şekilde çalışıyor fakat ben bunun gibi birşey yaptığımda;
void put_to_a(char c)
{
  putc(c);
  putc("Online\n\r");
}

hata veriyor neden acaba?

Petek

Siz orada yapamazsınız. Çünkü portlara ait putc fonksiyonlarınızı yeniden tanımlıyorsunuz.

Aslında bu çok saçma bir mantık ama CCS hazretleri öyle buyurmuşlar...

Burada fopen gibi birşey yapmaları gerekirdi.
“Önyargıları yıkmak atomu parçalamaktan zordur” A.Einstein

SpeedyX

Önceden bende buna anlam verememiştim, sanırım #use rs232 tanımının altında tanımladığı putc içerek fonksiyon, üstte belirtilen pinlerden haberleşiyor ve diğeride kendi üzerinde tanımlanan pinlerden haberleşiyor.
Ben bunun yerine stream özelliğini kullanıyorum, sanırım pek farkı yok.

#use rs232(baud=9600,xmit=PIN_B2,rcv=PIN_B1,stream=bir)
#use rs232(baud=9600,xmit=PIN_B4,rcv=PIN_B3,stream=iki)

...
...

printf(bir,"deneme1");

printf(iki,"deneme2");

CaFFeiNe

hımm

printf("deneme");

yapıncada oluyor problem yok teşekkürler
şimdi ilk sorumu şu hale getiriyorum
printf() fonksiyonu ile string yazıyoruz putc() ile tek karakter yazıyoruz (helpten anladığım) peki bu örnekte amcam nasıl putc() ile Online stringini yazmış?

optech

Ben CSS de yeni sayilirim ama dusuncemi soylemek istiyorum.

putc() fonksiyonu tanim olarak tek karakter icin tanimlanmis ve put_to_a() ve put_to_b() fonksiyonlari icinde dizideki her karakter icin birer defa cagriliyor ve hata vermiyor ama putc() icinde putc("abcd") seklinde kullanilinca hata veriyor.

Bir soru: karakter beklerken
char get_from_a() 
{ 
  return(getc()); 
}
ve
c=get_from_a();
yerine sadece
c=getc();
kullansaydin olmazmiydi diye kafama takilmadi değil. Bir de hangi porttan alacagini nasil ayarliyoruz?

Cift seri port icin SpeedyX'in kullandigi yontem cok hos. Yeni bir sey ogrendim. :) Yine ayni soru: veri alirken stream olayi nasil oluyor?

Son olarak bu sistem icin 4MHz az değil mi? 9600 de seri veri geldiginde veri kaybi olabilirmis gibi geliyor bana....

Burada yazdiklarim sadece birer fikirdi. Yanlisimiz varsa affola. Su an hala assembly kullaniyorum ama CSS ye ilgiliyim.

SpeedyX

çoklu alım ve gönderim için gets(); ve puts(); kullanılıyor.

stream ile alım şöyle oluyor;

deger = fgetc(stream);

yada

deger = fgets (string, stream);

son olarak 9600 örnek olarak yazmıştım, farklı bir hızda olabilir. (57600)

optech

Simdi aklima geldi... Peki bu iki yontemden hangisinin kod verimliligi (yani program hafizada kapladigi yer) daha iyidir.

Stream ozelligimi yoksa her port icin ayri ayri fonksiyon tanimlama mi?

Acaba kayda deger bir fark var midir?

CaFFeiNe

@optech

haklısın fakat bu kodları ben yazmadım CCS nin manuelinde son sayfalarda olan kodlar bunlar sadece deneme yapıyordum kendi kendime
4Mhz 9600 baudda gerçek devrede problem yaparmı bilmiyorum ama simülasyonda problem gözükmüyor

işte sorun burada put_to_a() fonksiyonunda nasıl her karakter için çağırılacakki? (CCS nin karanlık sayfalarımı yoksa :))

SpeedyX

Alıntı yapılan: "CaFFeiNe"4Mhz 9600 baudda gerçek devrede problem yaparmı bilmiyorum ama simülasyonda problem gözükmüyor
gerçek devrede sorun yapmıyor, 2 defa denedim bir sorun görmedim o hızda.

Alıntı yapılan: "CaFFeiNe"işte sorun burada put_to_a() fonksiyonunda nasıl her karakter için çağırılacakki? (CCS nin karanlık sayfalarımı yoksa :))
büyü var orda :) bende merak ettim açıkçası.

Petek

Alıntı yapılan: "CaFFeiNe"@optech

haklısın fakat bu kodları ben yazmadım CCS nin manuelinde son sayfalarda olan kodlar bunlar sadece deneme yapıyordum kendi kendime
4Mhz 9600 baudda gerçek devrede problem yaparmı bilmiyorum ama simülasyonda problem gözükmüyor

işte sorun burada put_to_a() fonksiyonunda nasıl her karakter için çağırılacakki? (CCS nin karanlık sayfalarımı yoksa :))
4 MHz 9600 için problem değil. 19200 için de değil. Daha yukarısını denemedim.

putc, lcd_putc gibi komutlar tek bir karakter de gönderebiliyor, bir string de. Onda sorun yok. Ama formatlı rakam yazdıracaksanız bunlarla yapamıyorsunuz. printf kullanacaksınız. Orada

printf(put_to_a, "deneme %lu", ddd);

gibi. put_to_a hangi porta yazdıracağınızı gösteriyor. Aslında bu kısım biraz uydurukça. Şu an itibariyle SpeedyX hocamın metodu en doğrusu. Bu yönteme alışmak lazım. Yoksa ARM7 için Keil kullanmaya başladığımızda çuvallayacağız. Biraz başladım ve CCS yi unutmaya karar verdim ;)
“Önyargıları yıkmak atomu parçalamaktan zordur” A.Einstein

Petek

Alıntı yapılan: "optech"Simdi aklima geldi... Peki bu iki yontemden hangisinin kod verimliligi (yani program hafizada kapladigi yer) daha iyidir.

Stream ozelligimi yoksa her port icin ayri ayri fonksiyon tanimlama mi?

Acaba kayda deger bir fark var midir?
Kod verimliliği açısından bir fark olmayacaktır. Sonuçta birisi emulasyon. Belki fark stack kullanımında ortaya çıkabilir bakmak lazım.

Her iki portta emulasyon UART kullansa bu durumda stream veya farklı fonksiyonlar bir şey değiştirmeyecek. Her ikisi için de aynı işlemleri yapmak zorunda. Yani bir portun pinlerinden hangisini set yada reset edeceği variable olarak tanımlanamıyor. Dolayısıyle her iki stream için de o fonksiyonları içinde tanımlayıp kullanacak. Birden fazla donanım uart modülü olsa iş çok kolay olurdu. İşin zahmetli kısmını donanım üstlendiği için portun birine stream1 diğerine stream2 denirdi ve bilgi ikisinden birine kolayca yönlendirilebilirdi. Biraz uzun oldu, karıştı mı?
“Önyargıları yıkmak atomu parçalamaktan zordur” A.Einstein

optech

* 4MHz 9600 de  16F628 icin RB1 ve RB2 pinlerini (yani RS232 icin donanim kontrollu olan pinler) kullanmayinca problem olabilecegini dusundum. Cunku bunu bir uygulamamda yapmistim. Donanim kontrollu pinlerin disinda 2 pin kullanmistim ve 9600 de seri veri (hızlı) yolladigimda FIFO hatasina sebep olmuştu. Yani 2 byte olan pic'in fifo'su bosalmadan 3 byte ardindan 4. gelince sonsuz dongu icinde ayni karakter (en son gonderilen) gorunuyordu. 8 MHz ye cikarinca duzelmisti ki bunu simulasyonda da gormustum.

* Formatli yollamak derken ne anlama gelir bu @Petek? putc(); fonsiyonunu
putc("asdf");
seklinde kullandim olmadi. putc() ile string gonderme derken bunu kasdetmedin mi?

* Iki yontem icinde derleme yaptim ikisinde de %9 rom %4 ram kapladigini derleyiciden gordum. Yalniz bir de derlenen hex dosyalarini disassembly ettim ve asm olarak gordukten sonra program hafizada kapladiklari yere baktim. Fonksiyon olarak tanimlayinca 186byte, stream ozelligiyle 177byte gordum.

* Fonksiyon olusturma yondemiyle derlenen kodu asm kod olarak cevirdikten sonra biraz inceledim.
void put_to_a(char c) 
{ 
  putc(c); 
}
seklinde olusturulmus fonksiyon icin bir lookup table olusturulmus.  Bu tabloya bakarak tanimlanan pinden(TX) cikis vermis. Her karakter icin bir putc(); cagirmis. Tabloda 0x00 i gorunce donguden yani put_to_a(); fonksiyonundan cikmis. Demekki CSS de boyle bir mantik var herhangi bir fonksiyon icinde tek karakterlik fonksiyonlar cagirabiliyorsun ve tanimladigin fonksiyona string gonderebiliyorsun. Bunu taniyip ayarlarini yapabiliyor. Yada bu durum sadece putc() gibi ozel fonkiyonlar icin gecerli. Dogru mu????  Bu arada putc() den cikarken retlw 0x00 seklinde cikmis. Yani bu durumda putc() fonksiyonu bir bytelik veri gonderen bir alt program olarak tanimlamis.

*2 tane USART modulu olan PICler var ama C'yi ozel yapan da bu tip ozellikleri olsa gerek, istedigin pini rx tx olarak kullanabiliyorsun. Bunu assembly'de yapmak ne isterdi bilmiyorum. Hem de iki port icin!!!!!!!!

Petek

Tek bir mesajda hepsine cevap zor olacak. O nedenle parçalar halinde gönderilse iyi olacak.

Alıntı yapılan: "optech"* 4MHz 9600 de  16F628 icin RB1 ve RB2 pinlerini (yani RS232 icin donanim kontrollu olan pinler) kullanmayinca problem olabilecegini dusundum. Cunku bunu bir uygulamamda yapmistim. Donanim kontrollu pinlerin disinda 2 pin kullanmistim ve 9600 de seri veri (hızlı) yolladigimda FIFO hatasina sebep olmuştu. Yani 2 byte olan pic'in fifo'su bosalmadan 3 byte ardindan 4. gelince sonsuz dongu icinde ayni karakter (en son gonderilen) gorunuyordu. 8 MHz ye cikarinca duzelmisti ki bunu simulasyonda da gormustum.
Burada bir yanlış yorumlama yapmışsın. 16F628 iç şemasına bakarsan 2 baytlık FIFO yapısı sadece donanım uartına aittir. Başka pinleri tx ve rx tanımlarsan bu 2 baytlık FIFO'yu kullanamazsın. Yani CCS porttan ne aldıysa anında herhangi bir registerindedir bu bilgi. Gönderme de aynı şekilde. Sen peşpeşe 2 tane gönder desen de göndermez. Bu konu ile ilgili ikinci husus, donanım uart modülünde baud rate generator vardır ve farklı frekanslarda belirli hata oranlarında çalışır. Bir de maksimum değeri vardır, onun üstünde çalışamaz (datasheette bunlar tablolalanmış). Yazılım emulasyonunda hata oranı çok daha düşüktür. Hatta diyebilirim ki donanım uartı ile çıkamadığın hızlara da ulaşırsın. Ben 4800 bpslik Jal seri emulasyonunu 9600 e çevirmiştim ve arada 9600 için delay rutinlerini yazmak gerekiyordu. Hız (rate) arttıkça hem delay rutinim daha kolay oluşturulabiliyordu ve hem de daha hassas delay oluşturabiliyordum. Baoud rate generatorda olmayan esnekliğe emulasyonda sahip olabiliyorsun.

Alıntı Yap
* Formatli yollamak derken ne anlama gelir bu @Petek? putc(); fonsiyonunu
putc("asdf");
seklinde kullandim olmadi. putc() ile string gonderme derken bunu kasdetmedin mi?
...

Formatlı yazdırma örneği verdim,
printf(put_to_a, "deneme %6lu", ddd);
printf(put_to_a, "deneme %5lu", ddd); gibi.

putc("asdf"); bu neden olmadı? put_to_a fonksiyonu tanımladıysan put_to_a("asdf") ı dene. putc de nereye yazacağını anlayamamış olabilir.
“Önyargıları yıkmak atomu parçalamaktan zordur” A.Einstein

optech

Yazilimla yapilan seri port iletisiminde FIFO kullanilmadigini CSS ile cok muhatap olmamama ragmen tahmin ediyordum. Ama demek istedigim donanim kontrollu yazilim yaparken gordugum FIFO hatasinin aynisini emulasyon olarak kullandigim durumda da gordum ve crystal hizini arttirinca cozume ulastim. Donanim kontrollu kullanirken yazilimla kontrol etmeseniz bile 2 byte a kadar veri FIFO ya geliyor. Sonra muhakkak bir reg icine alinmali yoksa sonsuz dongu halinde ayni veriyi almak zorunda kaliyorsunuz. Overrun durumuydu galiba bu. Bazi islemler yapilarak tekrar kullanilabiliyor. Yazilim kontrollu kullanirken bu durum olamaz. Gelen veri neyse odur. Goremezsen kacar gider. Yanlis miyim? Peki acaba ben niye ayni hatayi gormustum? Bu hata zannediyorum datasheet icindeki tablolarda gosterilen sekilde bir veri hatasi değil?

Alıntı Yapputc, lcd_putc gibi komutlar tek bir karakter de gönderebiliyor, bir string de. Onda sorun yok. Ama formatlı rakam yazdıracaksanız bunlarla yapamıyorsunuz. printf kullanacaksınız. Orada

printf(put_to_a, "deneme %lu", ddd);

putc string gonderebiliyor derken putc("asdf"); değil mi? Formatli derken de %lu nedir. Dedigim gibi cok iyi bilmiyorum C'yi...

put_to_a("asdf") oluyor ama mantiken nasil oluyor onu tam anlamamistim. Onceki mesajima ragmen hala tam anlamis değilim. Sadece demekki boyle oluyor diyebildim.

Petek

Alıntı yapılan: "optech"Yazilimla yapilan seri port iletisiminde FIFO kullanilmadigini CSS ile cok muhatap olmamama ragmen tahmin ediyordum. Ama demek istedigim donanim kontrollu yazilim yaparken gordugum FIFO hatasinin aynisini emulasyon olarak kullandigim durumda da gordum ve crystal hizini arttirinca cozume ulastim.
Programın o hali duruyorsa bakabiliriz. İnterrupt kullanıyorduysan onları disable etmemiş olabilirsin. CCS nin 40 gün 40 gece süren interrapta geçiş ve geri dönüş merasimi nedeniyle de zamanlamayı kaçırmış olabilirsin. Bu durmda overrun değil frame error oluşur :)
Alıntı YapDonanim kontrollu kullanirken yazilimla kontrol etmeseniz bile 2 byte a kadar veri FIFO ya geliyor. Sonra muhakkak bir reg icine alinmali yoksa sonsuz dongu halinde ayni veriyi almak zorunda kaliyorsunuz. Overrun durumuydu galiba bu. Bazi islemler yapilarak tekrar kullanilabiliyor.
Evet rxreg ti sanırım ismi, bu registere bilgi geldiğinde içeriğini başka bir registere aktarmak gerek. Yoksa seri shift registeri 8 biti (yada stop biti alındığında) aldığı anda rxrege transfer eder. rxreg içeriği dolu ise overrun hatası meydana gelir.
Alıntı YapYazilim kontrollu kullanirken bu durum olamaz. Gelen veri neyse odur. Goremezsen kacar gider. Yanlis miyim? Peki acaba ben niye ayni hatayi gormustum? Bu hata zannediyorum datasheet icindeki tablolarda gosterilen sekilde bir veri hatasi değil?
Doğru. Emulasyonda gelen bilgiyi kaçırmamak için ya master/slave çalışmak (bizim emulasyonlu taraf master olacak:)) yada alma pinlerini interuptı olan bir porttan (b portu oluyor :)) seçip, alma işlemini interruptta yapmak (ki stack kullanımı açısından çok risklidir) gerekir.
Alıntı Yapputc string gonderebiliyor derken putc("asdf"); değil mi? Formatli derken de %lu nedir. Dedigim gibi cok iyi bilmiyorum C'yi...

put_to_a("asdf") oluyor ama mantiken nasil oluyor onu tam anlamamistim. Onceki mesajima ragmen hala tam anlamis değilim. Sadece demekki boyle oluyor diyebildim.
Formatlı yazdırma derken herhangi bir veya birkaç değişken içeriğini yazdırmaktan bahsediyorum. Bu durmda printf kullanmak gerekiyor. putc veya put_to_a ekrana değişken içeriğini basmaz.  put_to_c("asdf") ekrana tırnak arasındaki stringi yazdırıyor. Bunu ben de bilmiyorum. Bize kolaylık sağladıklarını düşünüyorlar herhalde.
“Önyargıları yıkmak atomu parçalamaktan zordur” A.Einstein