2012-07-26 17 views
11

मैं एक Arduino के साथ संवाद करने के लिए वास्तव में एक सरल सी ++ एप्लिकेशन लिखने की कोशिश कर रहा हूं। मैं Arduino एक चरित्र भेजना चाहता हूं कि यह तुरंत वापस भेजता है। Arduino कोड है कि मैं एक ट्यूटोरियल से ले लिया इस तरह दिखता है:सीरियल कनेक्शन पर दो-तरफा सी ++ संचार

void setup() 
{ 
    Serial.begin(9600); 
} 

void loop() 
{ 
    //Have the Arduino wait to receive input 
    while (Serial.available()==0); 

    //Read the input 
    char val = Serial.read(); 

    //Echo 
    Serial.println(val); 
} 

मैं आसानी से जीएनयू स्क्रीन का उपयोग Arduino के साथ संवाद कर सकते हैं, इसलिए मुझे पता है कि सब कुछ बुनियादी संचार के साथ ठीक काम कर रहा है:

$ स्क्रीन /dev/tty.usbmodem641 9600

मैं इस तरह दिखता है (टूटी हुई) सी ++ कोड:

#include <fstream> 
#include <iostream> 
int main() 
{ 
    std::cout << "Opening fstream" << std::endl; 
    std::fstream file("/dev/tty.usbmodem641"); 
    std::cout << "Sending integer" << std::endl; 
    file << 5 << std::endl; // endl does flush, which may be important 
    std::cout << "Data Sent" << std::endl; 
    std::cout << "Awaiting response" << std::endl; 
    std::string response; 
    file >> response; 
    std::cout << "Response: " << response << std::endl; 

    return 0; 
} 

यह ठीक संकलित, लेकिन जब यह चल रहा है, कुछ रोशनी Arduino पर फ्लैश और टर्मिनल बस पर लटका हुआ है:

उद्घाटन fstream

कहाँ मैं गलत हो रहा हूँ?

+2

कोशिश (http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio/reference/serial_port.html)। यदि आपका चालक एफटीडीआई है तो आपको [बॉड रेट] सेट करना होगा (http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio/reference/serial_port_base__baud_rate.html)। – Arpegius

+0

धन्यवाद। मुझे इसका एक डेमो मिला कि मैं कल देखूंगा। । । http://www.college-code.com/blog/2008/boost-asio-serial_port-demo – learnvst

+3

आपका कोड Arduino के लिए हार्डवेयर प्रवाह नियंत्रण का उपयोग करने का इंतजार कर रहा है। मैं शर्त लगा रहा हूं कि आपका Arduino हार्डवेयर प्रवाह नियंत्रण नहीं करता है। आपको धारावाहिक बंदरगाह पर नियंत्रण रखना होगा, आप मानक I/O लाइब्रेरी को ऐसा नहीं कर सकते क्योंकि यह नहीं जानता कि यह टर्मिनल की तरह कैसा लगता है। –

उत्तर

0

आपको यह जांचना चाहिए कि क्या आपके पास /dev/tty.usbmodem641 तक पहुंच है या नहीं। लिनक्स में सामान्य तरीका उपयोगकर्ता को adduser के साथ उचित समूह में जोड़ना है।

वैसे, मुझे पता है कि सीरियल पोर्ट तक पहुंचने के लिए, /dev/ttyS3 तक /dev/ttyS0 (COM1 के लिए) खोलने की आवश्यकता है। उदाहरण के लिए देखें this example in C

2

जब आप सीरियल पोर्ट खोलते हैं, तो Arduino रीसेट करता है। Arduino Uno के लिए, रीसेट और ग्राउंड के बीच 10   μF संधारित्र जोड़ना इससे रोकता है। विवरण के लिए this देखें। ध्यान दें कि चिप को दोबारा लिखने के लिए आपको हर बार संधारित्र को हटाना होगा।

आपको सीरियल पोर्ट को सही तरीके से कॉन्फ़िगर करना होगा, लेकिन आपको पहले हार्डवेयर समस्या को हल करने की आवश्यकता है।

+0

तब सरल कंसोल पहुंच के साथ यह कैसे ठीक काम करता है? उदाहरण के लिए '$ स्क्रीन /dev/tty.usbmodem641 9600' – learnvst

8

तीन अंक हैं:

पहले: आप लिनक्स पक्ष पर सीरियल पोर्ट (TTY) को प्रारंभ नहीं है। कोई भी यह नहीं जानता कि यह किस राज्य में है।

अपने प्रोग्राम में ऐसा करने से आपको tcgetattr(3) और tcsetattr(3) का उपयोग करना होगा। आप इस साइट पर, Arduino साइट या Google पर इन कीवर्ड का उपयोग करके आवश्यक पैरामीटर पा सकते हैं।

stty -F /dev/tty.usbmodem641 sane raw pass8 -echo -hupcl clocal 9600 

विशेष रूप से याद आ रही clocal आप TTY खोलने रोक सकती हैं: लेकिन बस त्वरित परीक्षण के लिए मैं इस आदेश जारी करने से पहले आप अपने खुद के आदेश फोन प्रस्ताव करते हैं।

दूसरा: जब डिवाइस खुला होता है, तो आपको कुछ भी भेजने से पहले थोड़ा इंतजार करना चाहिए। डिफ़ॉल्ट रूप से Arduino रीसेट करता है जब सीरियल लाइन खोला या बंद हो जाता है। आपको इसे ध्यान में रखना होगा।

-hupcl भाग अधिकांश समय इस रीसेट को रोक देगा।लेकिन कम से कम एक रीसेट हमेशा जरूरी है, क्योंकि -hupcl तभी सेट किया जा सकता है जब टीटीई पहले से ही खुला हो और उस समय Arduino को पहले ही रीसेट सिग्नल प्राप्त हुआ हो। तो -hupcl भविष्य में रीसेट को "केवल" ही रोक देगा।

तीसरा:कोई आपके कोड में त्रुटि प्रबंधन है। कृपया प्रत्येक आईओ ऑपरेशन के बाद टीटीई पर कोड जोड़ें जो त्रुटियों की जांच करता है और - सबसे महत्वपूर्ण हिस्सा - perror(3) या इसी तरह के कार्यों का उपयोग करके सहायक त्रुटि संदेशों को प्रिंट करता है।

2

मुझे boost::asio का उपयोग करके एक सरल मिनीकॉम प्रकार क्लाइंट बनाने के तरीके के बारे में जेफ ग्रे द्वारा एक अच्छा उदाहरण मिला। मूल code listing can be found on the boost user group। यह मूल पोस्ट में वर्णित जीएनयू स्क्रीन उदाहरण में Arduino के साथ कनेक्शन और संचार की अनुमति देता है।

कोड उदाहरण (नीचे) निम्नलिखित लिंकर झंडे के साथ जुड़े होने की

-lboost_system-एमटी -lboost_thread-एमटी

की जरूरत है ... लेकिन फेरबदल का एक सा के साथ, कुछ बूस्ट पर निर्भरता की नई सी ++ 11 मानक सुविधाओं के साथ प्रतिस्थापित किया जा सकता है। जब मैं इसके चारों ओर घूमता हूं तो मैं संशोधित संस्करणों को पोस्ट करूंगा। अभी के लिए, यह संकलित और एक ठोस आधार है। को बढ़ावा देने [asio सीरियल पोर्ट] के साथ

/* minicom.cpp 
     A simple demonstration minicom client with Boost asio 

     Parameters: 
       baud rate 
       serial port (eg /dev/ttyS0 or COM1) 

     To end the application, send Ctrl-C on standard input 
*/ 

#include <deque> 
#include <iostream> 
#include <boost/bind.hpp> 
#include <boost/asio.hpp> 
#include <boost/asio/serial_port.hpp> 
#include <boost/thread.hpp> 
#include <boost/lexical_cast.hpp> 
#include <boost/date_time/posix_time/posix_time_types.hpp> 

#ifdef POSIX 
#include <termios.h> 
#endif 

using namespace std; 

class minicom_client 
{ 
public: 
     minicom_client(boost::asio::io_service& io_service, unsigned int baud, const string& device) 
       : active_(true), 
        io_service_(io_service), 
        serialPort(io_service, device) 
     { 
       if (!serialPort.is_open()) 
       { 
         cerr << "Failed to open serial port\n"; 
         return; 
       } 
       boost::asio::serial_port_base::baud_rate baud_option(baud); 
       serialPort.set_option(baud_option); // set the baud rate after the port has been opened 
       read_start(); 
     } 

     void write(const char msg) // pass the write data to the do_write function via the io service in the other thread 
     { 
       io_service_.post(boost::bind(&minicom_client::do_write, this, msg)); 
     } 

     void close() // call the do_close function via the io service in the other thread 
     { 
       io_service_.post(boost::bind(&minicom_client::do_close, this, boost::system::error_code())); 
     } 

     bool active() // return true if the socket is still active 
     { 
       return active_; 
     } 

private: 

     static const int max_read_length = 512; // maximum amount of data to read in one operation 

     void read_start(void) 
     { // Start an asynchronous read and call read_complete when it completes or fails 
       serialPort.async_read_some(boost::asio::buffer(read_msg_, max_read_length), 
         boost::bind(&minicom_client::read_complete, 
           this, 
           boost::asio::placeholders::error, 
           boost::asio::placeholders::bytes_transferred)); 
     } 

     void read_complete(const boost::system::error_code& error, size_t bytes_transferred) 
     { // the asynchronous read operation has now completed or failed and returned an error 
       if (!error) 
       { // read completed, so process the data 
         cout.write(read_msg_, bytes_transferred); // echo to standard output 
         read_start(); // start waiting for another asynchronous read again 
       } 
       else 
         do_close(error); 
     } 

     void do_write(const char msg) 
     { // callback to handle write call from outside this class 
       bool write_in_progress = !write_msgs_.empty(); // is there anything currently being written? 
       write_msgs_.push_back(msg); // store in write buffer 
       if (!write_in_progress) // if nothing is currently being written, then start 
         write_start(); 
     } 

     void write_start(void) 
     { // Start an asynchronous write and call write_complete when it completes or fails 
       boost::asio::async_write(serialPort, 
         boost::asio::buffer(&write_msgs_.front(), 1), 
         boost::bind(&minicom_client::write_complete, 
           this, 
           boost::asio::placeholders::error)); 
     } 

     void write_complete(const boost::system::error_code& error) 
     { // the asynchronous read operation has now completed or failed and returned an error 
       if (!error) 
       { // write completed, so send next write data 
         write_msgs_.pop_front(); // remove the completed data 
         if (!write_msgs_.empty()) // if there is anthing left to be written 
           write_start(); // then start sending the next item in the buffer 
       } 
       else 
         do_close(error); 
     } 

     void do_close(const boost::system::error_code& error) 
     { // something has gone wrong, so close the socket & make this object inactive 
       if (error == boost::asio::error::operation_aborted) // if this call is the result of a timer cancel() 
         return; // ignore it because the connection cancelled the timer 
       if (error) 
         cerr << "Error: " << error.message() << endl; // show the error message 
       else 
         cout << "Error: Connection did not succeed.\n"; 
       cout << "Press Enter to exit\n"; 
       serialPort.close(); 
       active_ = false; 
     } 

private: 
     bool active_; // remains true while this object is still operating 
     boost::asio::io_service& io_service_; // the main IO service that runs this connection 
     boost::asio::serial_port serialPort; // the serial port this instance is connected to 
     char read_msg_[max_read_length]; // data read from the socket 
     deque<char> write_msgs_; // buffered write data 
}; 

int main(int argc, char* argv[]) 
{ 
// on Unix POSIX based systems, turn off line buffering of input, so cin.get() returns after every keypress 
// On other systems, you'll need to look for an equivalent 
#ifdef POSIX 
     termios stored_settings; 
     tcgetattr(0, &stored_settings); 
     termios new_settings = stored_settings; 
     new_settings.c_lflag &= (~ICANON); 
     new_settings.c_lflag &= (~ISIG); // don't automatically handle control-C 
     tcsetattr(0, TCSANOW, &new_settings); 
#endif 
     try 
     { 
       if (argc != 3) 
       { 
         cerr << "Usage: minicom <baud> <device>\n"; 
         return 1; 
       } 
       boost::asio::io_service io_service; 
       // define an instance of the main class of this program 
       minicom_client c(io_service, boost::lexical_cast<unsigned int>(argv[1]), argv[2]); 
       // run the IO service as a separate thread, so the main thread can block on standard input 
       boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service)); 
       while (c.active()) // check the internal state of the connection to make sure it's still running 
       { 
         char ch; 
         cin.get(ch); // blocking wait for standard input 
         if (ch == 3) // ctrl-C to end program 
           break; 
         c.write(ch); 
       } 
       c.close(); // close the minicom client connection 
       t.join(); // wait for the IO service thread to close 
     } 
     catch (exception& e) 
     { 
       cerr << "Exception: " << e.what() << "\n"; 
     } 
#ifdef POSIX // restore default buffering of standard input 
     tcsetattr(0, TCSANOW, &stored_settings); 
#endif 
     return 0; 
} 
संबंधित मुद्दे