Forum: Diğer Konular RSS
Arduino firmata derlerken hata
erdem (Moderatör) #1
Üye Tem 2009 tarihinden beri · 1005 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: Arduino firmata derlerken hata
Uzun bir aradan sonra öncelikle merhaba :)

Hem size bir merhaba diyeyim, hem de bir soru sorayım dedim.

Arduino'nun firmata test programını derlemeye çalışıyorum.

Derlerken şu şekilde bir hata alıyorum.

firmata_test.cpp: In member function ‘virtual bool MyApp::OnInit()’:
firmata_test.cpp:669:93: error: conversion from ‘const char [13]’ to ‘const wxString’ is ambiguous
     MyFrame *frame = new MyFrame( NULL, -1, "Firmata Test", wxPoint(20,20), wxSize(400,640) );

Hata veren satır burası:

    MyFrame *frame = new MyFrame( NULL, -1, "Firmata Test", wxPoint(20,20), wxSize(400,640) );

MyFrame sınıfının kurucu işlevi de şu şekilde:

MyFrame::MyFrame( wxWindow *parent, wxWindowID id, const wxString &title,
    const wxPoint &position, const wxSize& size, long style ) :
    wxFrame( parent, id, title, position, size, style )
{
    /* ... */
}

typedef struct {
    uint8_t mode;
    uint8_t analog_channel;
    uint64_t supported_modes;
    uint32_t value;
} pin_t;
pin_t pin_info[128];

Bir de bu yapı nasıl bir yapıydı. Sanırım C bilgilerini biraz unutmuşum.

D için de firmata protokülünün gerçekleşmesini yazsak nasıl olur. Baktım diğer diller arasında Go bile var.

https://github.com/firmata/arduino

Artık javascript ile bile Arduino uygulamalarının çalıştırılabilmesi çok ilginç geldi.

var five = require("johnny-five");
var board = new five.Board();
 
board.on("ready", function() {
  console.log("Ready!");
 
  var led = new five.Led(13);
  led.blink(500);
});

Örneğin yukarıdaki javascript programı 13 numaralı kapıya bağlı ledi yarım saniye aralıklarla yakıp söndürüyor.

Detaylar için bu sayfaya bakabilirsiniz.

https://github.com/rwaldron/johnny-five
acehreli (Moderatör) #2
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4538 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
"Firmata Test" yerine wxString("Firmata Test") dener misin. Eğer olmazsa, önce title diye yerel bir değişken tanımlayıp sonra onu parametre olarak göndermeyi deneyebilirsin:
    wxString title("Firmata Test");
    MyFrame *frame = new MyFrame( NULL, -1, title, wxPoint(20,20), wxSize(400,640) );
typedef'li satırda olan şu: İsimsiz bir yapı türü tanımlanıyor ve hemen ona pin_t diye yeni bir isim veriliyor. (Yapının ismi pin_t olsaydı ve typedef kullanılmasaydı uzunca 'struct pin_t' yazmak gerekirdi. (C++ ve D'de ise 'struct' yazmak gerekmezdi.))

Ali
erdem (Moderatör) #3
Üye Tem 2009 tarihinden beri · 1005 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Şu şekilde düzeldi.

    MyFrame *frame = new MyFrame( NULL, -1, wxString::FromAscii("Firmata Test"), wxPoint(20,20), wxSize(400,640) );

Ama bir tane değil. Dün biraz düzeltmeye çalıştım ama liste çok uzun. Bu sayfada wxString sınıfı ile ilgili bilgiler var.

https://wiki.wxwidgets.org/WxString

Anladığım kadarıyla wxWidgets kütüphanesi ANSII kullanacak şekilde tekrar derleyince bu hata mesajları oluşmuyormuş. Bir de onu deneyeyim bakalım.

Denemek için serial kütüphanesini kullanan bir test programı yazdım.

#include <iostream>
#include "serial/serial.h"
#include <bitset>
#include <string>
 
using std::cout;
using std::string;
 
typedef serial::Serial SeriPort;
 
constexpr char onaltilik[] = {'0', '1', '2', '3', '4', '5', '6', '7',
                           '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
 
std::string onaltili(uint8_t * veri, int uzunluk)
{
  std::string s(uzunluk * 2, ' ');
  for (int i = 0; i < uzunluk; ++i)
  {
    s[2 * i]     = onaltilik[(veri[i] & 0xF0) >> 4];
    s[2 * i + 1] = onaltilik[veri[i] & 0x0F];
  }
  return s;
}
 
void baytYazdir(uint8_t bayt)
{
    uint8_t *gBayt = &bayt;
    cout << "Veri = " << onaltili(gBayt,sizeof(bayt)) << std::bitset<8>(bayt) << '\n';
}
 
std::ostream& operator<<(std::ostream& cikis, uint8_t bayt)
{
    return cikis << " " << std::bitset<8>(bayt) << " " << onaltili(&bayt,sizeof(bayt)) << '\n';
}
 
#define START_SYSEX             0xF0 // MIDI Sysex iletisinin başlangıcı
#define END_SYSEX               0xF7 // MIDI Sysex iletisinin sonu
#define REPORT_FIRMWARE         0x79 // aygıt sürücüsü yazılımının adı ve sürümünü raporla
 
int main()
{
    SeriPort seriPort("/dev/ttyACM0", 57600, serial::Timeout::simpleTimeout(5000));
    cout << "Seri port açık mı ?\n";
    if (seriPort.isOpen())
    {
        cout << "Evet\n";
 
        serial::Timeout timeout = seriPort.getTimeout();
 
        uint8_t alinan[3];
 
        uint8_t  * okunan = alinan;
 
        seriPort.waitReadable();
        for (int i = 0; i < 10; ++i)
        {
 
            seriPort.read(okunan,3);
 
            cout << "alinan[0]" << alinan[0];
            cout << "alinan[1]" << alinan[1];
            cout << "alinan[2]" << alinan[2];
        }
 
        // aygıt sürücüsü yazılımı bilgilerini iste
        uint8_t gonderilen[3];
        gonderilen[0] = START_SYSEX;    // MIDI Sysex iletisinin başlangıcı
        gonderilen[1] = REPORT_FIRMWARE;// aygıt sürücüsü yazılımının adı ve sürümünü raporla
        gonderilen[2] = END_SYSEX;      // MIDI Sysex iletisinin sonu
 
        cout << "gonderilen[0] " << gonderilen[0];
        cout << "gonderilen[1] " << gonderilen[1];
        cout << "gonderilen[2] " << gonderilen[2];
 
        seriPort.write(gonderilen, 3);
 
        // 13 numaralı ledi yak
        gonderilen[0] = 0x91;
        gonderilen[1] = 0x20;
        gonderilen[2] = 0x00;
 
        cout << "gonderilen[0] " << gonderilen[0];
        cout << "gonderilen[1] " << gonderilen[1];
        cout << "gonderilen[2] " << gonderilen[2];
 
        seriPort.write(gonderilen, 3);
        seriPort.close();
    }
 
    else
        cout << "Hayır\n";
}

Bu program 13 numaralı ledi yakıyor. Ama dikkat ederseniz rastgele bir for döngüsüyle verileri okuyoruz. Aslında seri port üzerinde veri olduğu sürece okumaya devam et gibi bir komut kullanmak gerekiyor sanırım.

Coolterm programı ile verilere baktığınızda F0 ve F7 arasındaki verileri okumamız gerekecek.

[Resim: http://www.erdem.tk/resim/CoolTerm_0%20-_050.png]

Bunun içinde alınan baytları işlemek gerekecek anladığım kadarıyla. Haberleşme protokolüne baktığımızda komutlar 8 bit, veriler 7 bit oluyormuş.

İkili G/Ç mesajı    0x90    port    LSB(bitler 0-6)    MSB(bitler 7-13)

Yalnız ben bu bitlerin sıralamasını tam anlamadım. Örneğin 0x91 20 00

Burada 0x91'den sonra bitlerin sıralaması Boş 0 1 2 3 4 5 6 ve Boş 7 8 9 10 11 12 13 şeklinde mi yoksa Boş 6 5 4 3 2 1 0 ve Boş 13 12 11 10 9 8 7 şeklinde mi.

D için bu protokolü yazmayı denesek nasıl olur  :-)

Ya da belki siz söylerseniz D topluluğu içinden yazmayı düşünenler çıkabilir. Ama sanırım D için bir de seri port kütüphanesi gerekecek.

Program çıktısını da buraya ekledim.
Bu mesaj erdem tarafından değiştirildi; zaman: 2016-11-22, 11:17.
acehreli (Moderatör) #4
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4538 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
erdem:
Yalnız ben bu bitlerin sıralamasını tam anlamadım. Örneğin 0x91 20 00

Burada 0x91'den sonra bitlerin sıralaması Boş 0 1 2 3 4 5 6 ve Boş 7 8 9 10 11 12 13 şeklinde mi yoksa Boş 6 5 4 3 2 1 0 ve Boş 13 12 11 10 9 8 7 şeklinde mi.

0x90 yazmak istediğini varsayıyorum. Bu gibi konularda bayt içindeki bitlerin sırası değişmez. Ama tabii senin bitleri nasıl numaraladığın da önemli. :) Ben LSB'ye 0, MSB'ye de 13 diyeceğim. Veri 13 12 11 10 9 8 7 6 5 4 3 2 1 0 bitlerinden oluşuyorsa, ilk bayta 6 5 4 3 2 1 0 değeri, ikinci bayta da 13 12 11 10 9 8 7 değeri gelir.

İkinci baytın bitleri 7 bit sağa öteleyerek elde edildiğini söylemeye herhalde gerek yok: (veri >> 7) & 0b0111_1111). Veya D'deki >>> işleci ile: (veri >>> 7).

Ali
erdem (Moderatör) #5
Üye Tem 2009 tarihinden beri · 1005 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Bilmiyordum ama onu da buldum Allah 'ın izniyle  ;-)

void ikiliKapiyaGonder(uint8_t portNumarasi, uint16_t portBilgileri)
{
    cout << "İkili Mesaj Gönder = " << uint8_t(DIGITAL_MESSAGE | (portNumarasi & 0xF));
    cout << "Port Bilgileri = " << uint8_t((uint8_t)portBilgileri % 128);
    cout << "Tx 7-13 bitleri =" << uint8_t(portBilgileri >> 7);
}

Program içinden çağırırken de şöyle çağırıyorum.
        uint16_t portBilgileri = 0x0020;
        ikiliKapiyaGonder(1, portBilgileri);

Programın çıktısı da şu şekilde:
İkili Mesaj Gönder =  10010001 91
Port Bilgileri =  00100000 20
Tx 7-13 bitleri = 00000000 00

Port bilgilerini de şuradan öğreniyoruz.

[Resim: http://www.erdem.tk/resim/arduinoportlari.png]

Şimdi sırada işleve 13 gönderdiğimizde portBilgileri = 0x0020 oluşturmak kalıyor. Bunun için benim aklıma gelen örneğin 0000_0001 değerini işleve gelen değer kadar sola kaydırmak; örneğin 0 göndermişse yok, 1 göndermişse 1 sola kaydırmak olabilir.
 
Arduino Uno üzerinde 16 tane ikili çıkış kapısı var. Ama benim asıl merak ettiğim örneğin yeni modellerde 32 tane ikili çıkış kapısı varsa o zaman 4 tane port oluyor. Bu durumda ne yapabiliriz.
acehreli (Moderatör) #6
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4538 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Belirli bitin değerini 1 yapmak için dediğin yöntem olur. Biraz daha hızlı olabilen bts() de var:

    https://dlang.org/phobos/core_bitop.html#.bts

Ayrıca, belki derleyici de aynı eniyileştirmeyi yapacaktır ama % 128 yerine & 0b_0111_1111 (veya & 0x7f) yazmanı öneririm. Bölme işlemi bit işleminden daha yavaş olacaktır. (Tabii ki farketmeyeceksin bile ama yine de bile bile yavaş işlemi seçmeye gerek yok. :) )
Ali
erdem (Moderatör) #7
Üye Tem 2009 tarihinden beri · 1005 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Ben de C++ çözümünü yazdım  ;-)

inline void birYap(uint16_t * dizi, int bit)
{
    asm("bts %1,%0" : "+m" (*dizi) : "r" (bit));
}

Peki çıkış akımına verileri 16'lı olarak yazdırmak istediğimizi düşünelim.

constexpr char onaltilar[] = {'0', '1', '2', '3', '4', '5', '6', '7',
                              '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
 
std::string onaltili (uint8_t * veri)
{
    int uzunluk = sizeof (*veri);
    std::string s (uzunluk * 2, ' ');
 
    for (int i = 0; i < uzunluk; ++i)
    {
        s[2 * i]     = onaltilar[(veri[i] & 0xF0) >> 4];
        s[2 * i + 1] = onaltilar[veri[i] & 0x0F];
    }
    return s;
}
 
template <typename Tur>
string onaltiliGoster(Tur deger)
{
    const int uzunluk = sizeof(deger);
    std::string s;
 
    s += (std::bitset<8 * uzunluk>(deger)).to_string() + string(" ");
 
 
    vector<uint8_t> baytlar;
    uint8_t * bayt = (uint8_t *)&deger;
 
    for (int i = 0; i < uzunluk; ++i)
        baytlar.push_back(bayt[i]);
    reverse(baytlar.begin(), baytlar.end());
    for (auto i = baytlar.begin(); i != baytlar.end(); ++i)
        s += onaltili(&(*i));
 
    s +='\n';
 
    return s;
}
 
std::ostream& operator<<(std::ostream& cikis, uint8_t bayt)
{
    return cikis << " " << std::bitset<8>(bayt) << " " << onaltili(&bayt) << '\n';
}
 
int main()
{
        /* ... */
        uint16_t deger = 0X0000;
        cout << onaltiliGoster(deger);
        birYap(&deger, 13);
        cout << onaltiliGoster(deger);
}

Bu durumda sizce çıkış akımına verileri yukarıdaki gibi bir işlevin mi göndermesi uygun olur yoksa çıkış akımına farklı görev yükleyebilirmiyiz.

Sadece template <typename Tur> şeklinde şablon olanağını kullanmaya çalıştığımda bu sefer cout<<'a giden tüm verileri bu işleve gönderiyor.

Çıkış akımında sadece işaretsiz tamsayılarla çalış şeklinde şablon kullanılabiliyor mu acaba.

Bunun dışında 0b_0111_1111 yazım biçimi C++'de ya da ek derleyici olanağı olarak kullanılabiliyor mu.

Sizce gelen iletileri nasıl okutalım. İletinin başını ve sonunu gösteren gösterge kullanarak mı yoksa bir vektör'e mi atalım. Bu konuda da fikirlerinizi merak ediyorum.
acehreli (Moderatör) #8
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4538 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
C++'tan bu soruları hemen cevaplayamayacak kadar kopmuşum. :)

Hatırladığım kadarıyla, uint8_t'nin genel olarak nasıl yazdırıldığını değiştirmek istemediğine göre öyle bir yükleme tanımlaman doğru değil. Onun yerine akım düzenleyici türler kullanılıyordu. Manipulator mı deniyordu? Bunlar kullanıldıktan sonra akımı tekrar eski haline sokuyordu. Ne kadar unutmuşum... :)

Ben nedense D yazıyorsun diye düşünüp 0b söz dizimini önermişim. C++ 14'e de "binary literal" diye geldi.

Ali
Doğrulama Kodu: VeriCode Lütfen resimde gördüğünüz doğrulama kodunu girin:
İfadeler: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Özel Karakterler:
Bağlı değilsiniz. · Şifremi unuttum · ÜYELİK
This board is powered by the Unclassified NewsBoard software, 20100516-dev, © 2003-10 by Yves Goergen
Şu an: 2017-12-16, 16:36:25 (UTC -08:00)