Ok, so I have 3 devices.
an AVR Butterfly microcontroller, set up with USART
A Bifferboard, running Debian, using a custom made program for serial.
A Desktop machine running Br#y's.
So I'm trying to make the Bifferboard send serial to the AVR, But the AVR never receives the signal, (we've checked the wires). But if i connect the AVR to the desktop box, and send with Br#y's it receives just fine.
If I connect the Bifferboard to the Desktop, Br#y's receives just fine.
Heres the code for the Bifferboard.
#include "string2num.h" //a custom header
#include <cstdlib>
#include <iostream>
#include <SerialStream.h>
using namespace LibSerial;
//using namespace std;
int main(int argc, char*argv[])
{
if (argc<2)
{
std::cout<<argv[0]<<" requires the device name eg \'dev/tty0\' as a parameter\nterminating.\n";
return 1;
}
SerialStream theSerialStream(argv[1]); //open the device
if(!theSerialStream.IsOpen()) //did the device succesfuilly open
{ //open faile
std::cerr<<"Open " << argv[1] << " failed\n Terminating.\n";
return 1; //exit failure
}
theSerialStream.SetVMin(0);//no min number of characters to send
theSerialStream.SetVTime(0);// don't wait betwenn characters
theSerialStream.SetBaudRate( SerialStreamBuf::BAUD_19200);
theSerialStream.SetCharSize(SerialStreamBuf::CHAR_SIZE_8); //8
theSerialStream.SetParity(SerialStreamBuf::PARITY_NONE);// N
theSerialStream.SetNumOfStopBits(1);// 1
theSerialStream.SetFlowControl(SerialStreamBuf::FLOW_CONTROL_NONE);
std::cout<<"Ready for serial trasmission. Press Ctrl+C to quit\n";
//insert basic instructions here
while (1)
{
char input[BUFSIZ];
std::cin>>input;
char* values=getAllValues(input); //DECODE any formatting (this function is in the custom header)
std::cout<<"about to transmit: " << values << "\n";
theSerialStream << values;
free(values);
}
theSerialStream.Close();
return 0;
}
I've also tried using minicom from Bifferboard - it can talk to the desktop windows machine, but not the the AVR.
(We've checked the wires)
This still sounds like a cabling problem. If Br#y's can communicate with both, then it doesn't seem to be a configuration issue. You should throw a logic analyzer or oscilloscope on the receive pin (and probably probe other pins) of the AVR and see what's happening electrically when yo try to send data from the Bifferboard.
I'd bet that you see the data on some other pin. But I wouldn't bet a whole lot, because serial RS232 connectivity is such a touchy thing.
It's a long shot, but are all the serial ports running at the same voltage levels? I see the bifferboard has a 3.3V UART, whereas the AVR has a level convertor. The desktop port may be more flexible about voltage.
I'll throw out another "long shot" possibility. Depending on the transciever chip being used on a board it may not be able to produce its own negative supply voltage (typically via a charge pump) for RS232 levels. Some chips will "steal" their negative supply from the other side of the line, and that works great if you're talking to something like a PC. If both sides take that approach, however, it doesn't work out so great. Tranceivers like MAX232 (plus external caps and resistors) will generate their own negative supply, but chips like the DS275 don't.
Related
I'm developing a C++ interface to communicate with na Arduino UNO which is running some code.
To communicate with the Arduino, i'm using boost asio library. My application works well at a baud rate of 9600bps. Now, i wanted to communicate faster with the arduino, so, i tried to communicate at 115200bps, 57600bps, etc, without success.
At 115200bps, it seems that boost::write is sending two non-desirable bytes (both the same, with value ASCII 240 - this only happens for the first data transaction, so if i unplug and plug again the Arduino, this bytes will be sent during the first communication ). At this baud rate i can read the data that is being sent by Arduino (which is wrong for the first data communication, but is correct for the next ones).
At 57600bps, those 2 wrong bytes are not sent, but data is not read from arduino (it seems that write is not sending nothing).
The code to write to the serial is fairly simple, is just the boost::write and the code to read from the serial is just a loop and a boost::read of one byte (communications are synchronous just to test if everything was okay, which is not for higher baud rates than 9600bps).
The write function:
void sendMessage(char *c, unsigned int size) {
serial.write(c, size);
return;
}
The read function:
void readMessage(void) {
char c;
uint8_t count = 0;
for (;;)
{
boost::asio::read(serial, boost::asio::buffer(&c, 1));
cout << "Received char: " << static_cast<unsigned int>(c) << endl;
if (count == 3 ){
return;
}
count++;
}
return;
}
I know that the problem is not in the side of the arduino (that's why i posted the question here and not in the arduino stackexchange) because, using realterm and sending the exact same bytes that i send using boost, i get the proper reply from the Arduino for every baud rate (9600, 57600 and 115200bps).
If anyone can help, i would be appreciated, since at this moment i don't know which is the problem (and i'm a beginner to boost).
Best regards
Edit
At 74880 bps, I recieve four times the byte with value 252.
I hava an STM32 f401RE. I am using Mbed library for setting up a conexion from STM32 to PC. I want to send via serial a char sequence to the board. As an answer i expect a blinking LED. E.g: led1 results in LED ON, led2 results in LED OFF.
The problem is that i don't know how to set the port for the connection.
#include "mbed.h"
#include "USBSerial.h"
//Virtual serial port over USB
USBSerial serial;
int main(void) {
while(1)
{
serial.printf("I am a virtual serial port\r\n");
wait(1.0);
}
}
You can use the USBSerial interface to emulate a serial port over USB. You can use this serial port as an extra serial port or as a debug solution. It also communicates between Mbed and a computer.
I would like to do all the above(even thogh i don't know what does emulate a serial port over USB. What is that Virtual USB?).
I see that USBSerial constructor takes
USBSerial (bool connect_blocking=true, uint16_t vendor_id=0x1f00, uint16_t product_id=0x2012, uint16_t product_release=0x0001). And i think i need to modify some of this adresses. The problem is that on Windows the ports are represented in Device Manager with COMxx and on Linux like ttyACMxx. How would i transform this in hexa adresses - is this what i have to do?
You should not have to transform anything or mess with the USB product_id or vendor_id, an mbed serial port should show as any other serial port so if it doesn't for you it means you are having driver issues.
On most recent Linux distros the device should show something similar to the following kernel messages:
cdc_acm 5-2:1.1: ttyACM0: USB ACM device
usbcore: registered new interface driver cdc_acm
cdc_acm: v0.26:USB Abstract Control Model driver for USB modems and ISDN adapters
On Windows, you will probably need to install drivers. After you do that, the serial port should show as mbed Serial Port (COMx) on your Device Manager. There are many places you can get troubleshooting help, see here, for instance.
The fact that you are getting nothing on both Windows and Linux makes one wonder if you are using the right cable (some USB cables work only for charging and are no good for your purposes, and some others simply fail after a while). I would first make sure your cable works with other devices (obviously not for charging only). There is also the possibility your board went (or came from the factory) bad, but that's quite unlikely.
I just found this approach and it is working. The thing that i don't understand is why on my pc i get this message: b'Hello World!\n'
#include "mbed.h"
Serial pc(USBTX, USBRX); // tx, rx
int main() {
pc.baud(9600);
while(1)
{
pc.printf("Hello World!\n");
wait(0.1);
}
}
Ignore that 'b'. Your device is not seeing that 'b'. It is just being printed by serial terminal utility. Also I would like to mention what I got from your question is, you want to send some data from PC to board over Serial and if device receives that data, it should start blinking the LED. If that is correct, use the code below:
#include "mbed.h"
Serial pc(USBTX, USBRX); // tx, rx
DigitalOut led(LED1); // If blinking doesn't work with LED1, Check the pin map for your board and pass the LED pin instead of LED1
char token = 'a'; // This is the character that you should send to trigger blinking
bool startBlinking = false;
int main() {
pc.baud(9600);
while(1)
{
if (pc.getc() == token) {
startBlinking = true;
}
if (startBlinking) {
led = 1;
wait(0.2);
led = 0;
wait(0.8);
}
}
}
I'm developing a Windows application that has to communicate (both input and output) with an Arduino through its serial port. I'm using boost::asio for portability reasons and I want to keep using it. What happens is that the first time I run my application it works perfectly, but if I run it a second time, no data comes from the Arduino anymore and the application stucks on the read operation. The only way to recover is to unplug and replug the Arduino USB cable from the computer.
This behavior is Windows-specific. The same code works perfectly on Linux.
The compiler is Visual Studio 2017 Community Edition.
Here is an example code to reproduce the issue:
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <vector>
int main() {
boost::asio::serial_port port(ioctx, "COM3"); // "/dev/ttyACM0" on Linux
port.set_option(boost::asio::serial_port::baud_rate(9600));
port.set_option(boost::asio::serial_port::character_size(8));
port.set_option(boost::asio::serial_port::stop_bits(boost::asio::serial_port::stop_bits::one));
port.set_option(boost::asio::serial_port::parity(boost::asio::serial_port::parity::none));
port.set_option(boost::asio::serial_port::flow_control(boost::asio::serial_port::flow_control::none));
char c = 'e';
auto const s = boost::asio::write(port, boost::asio::buffer(&c, 1));
std::cout << "sent " << s << " bytes" << std::endl;
boost::asio::streambuf response;
boost::asio::read_until(port, response, "\r\n");
std::istream response_stream(&response);
std::string line;
std::getline(response_stream, line);
std::cout << line << std::endl;
port.close(); // last-ditch effort to get it working
}
Here is an Arduino sketch (got from the Arduino website):
int incomingByte = 0; // for incoming serial data
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600bps
}
void loop() {
// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
// say what you got:
Serial.print("I received: ");
Serial.println(incomingByte, DEC);
}
}
Is there a way to restore the correct state of the connection? Am I missing something?
After having learned a couple of things, here is the solution:
Arduino uses its USB communication for both burning the sketch and performing data transmission back and forth the PC. The boot sequence foresees that for 2 seconds (for new Arduino versions and standard boot loader) the communication towards the boot loader is active. After that time, the sketch is executed.
Windows API allows to set all connection parameters at once via the SetCommState function and to retrieve them in a similar fashion with the GetCommState one. That is the method the set_option function uses to set the parameters, but it happens that calling GetCommState-SetCommState multiple times in a row slows down the process a lot (maybe by resetting the Arduino multiple times).
I ended writing the following function:
#include <Windows.h>
#include <chrono>
void init_arduino(boost::asio::serial_port& port, std::chrono::milliseconds const& sleep = 2000)
{
DCB dcbSerialParams = { 0 };
GetCommState(port.native_handle(), &dcbSerialParams);
// this is the optimal way to set the whole serial port configuration
// just in one shot.
dcbSerialParams.BaudRate = CBR_9600;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
//Setting the DTR to Control_Enable ensures that the Arduino is properly
//reset upon establishing a connection
dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE;
SetCommState(port.native_handle(), &dcbSerialParams);
PurgeComm(port.native_handle(), PURGE_RXCLEAR | PURGE_TXCLEAR);
// Wait for Arduino to boot the sketch
Sleep(sleep.count());
}
and using it to replace the port.set_option( lines in the question example.
I also set the flow control to DTR_CONTROL_ENABLE instead of the original none in order to reset the Arduino upon connection.
USB serial adaptors can have device driver bugs and hardware problems. The fact that you have to unplug and plug the device to get it working again is indicative of a device driver bug.
Look for an updated driver. It will probably a Prolific or FTDI chipset, make sure you get the driver from the chip maker. See Prolific or FTDI
If it is a flow control related hardware problem you can wire together the DTR, DSR and CD pins, and wire together the RTS and CTS pins on the RS-232 connector on the USB adaptor. I have seen USB adaptors where this is necessary, despite setting no flow control in software.
I'm working on a program to take readings from a proximity sensor using Arduino UNO. While I can get the readings just fine using Arduino's build-in Serial Monitor, somehow I cannot open the same port from MS VC++.
Following is (one part of) the program:
int main(void)
{
/*used for port"COM13"*/
HANDLE hCom=INVALID_HANDLE_VALUE;
char input[30];
string ss,ss1,ss2,ss3,ss4;
/*Open "COM13"*/
hCom=CreateFile("COM13",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
if(hCom==INVALID_HANDLE_VALUE)
{
printf("can't open file");
}
/*Communication Setting*/
DCB dcb;
memset(&dcb,0,sizeof (DCB));
dcb.DCBlength=sizeof (DCB);
dcb.BaudRate=CBR_9600;
dcb.ByteSize=8;
dcb.Parity=NOPARITY;
dcb.StopBits=ONESTOPBIT;
SetCommState(hCom,&dcb);
while(1)
{
//using the data string inputs, printout the readings, process it etc...
}
}
When I try to debug it, I'll get this error:
and I got can't open file from debug windows showing there is problem during port opening.
Some additional infos:
Why VC++? I'm also using OpenCV and some mathematical computation in the same program so it is easier for me to work in VC++
I've also tested my UNO program with TeraTerm for data readings with no problem (=no problem with my UNO)
I've tested above program with another microcontroller(non-Arduino) with no problem.
I'll upload my UNO program if needed.
Thanks in advance!
From the MSDN page on CreateFile:
To specify a COM port number greater than 9, use the following syntax:
"\.\COM10". This syntax works for all port numbers and hardware that
allows COM port numbers to be specified.
What's the problem in given code? Why it is not showing the output for rs232 when we connect it by the d-9 connector with the short of pin number 2 & 3 in that?
#include <bios.h>
#include <conio.h>
#define COM1 0
#define DATA_READY 0x100
#define SETTINGS ( 0x80 | 0x02 | 0x00 | 0x00)
int main(void)
{
int in, out, status;
bioscom(0, SETTINGS, COM1); /*initialize the port*/
cprintf("Data sent to you: ");
while (1)
{
status = bioscom(3, 0, COM1); /*wait until get a data*/
if (status & DATA_READY)
if ((out = bioscom(2, 0, COM1) & 0x7F) != 0) /*input a data*/
putch(out);
if (kbhit())
{
if ((in = getch()) == 27) /* ASCII of Esc*/
break;
bioscom(1, in, COM1); /*output a data*/
}
}
return 0;
}
Well, the code looks alright. Have you really connected the remaining pins correctly in the plug, see serial and pin connections.
Nothing obvious stands out from your code as the cause. Check all your bases as you are dealing with hardware/software. The following Microsoft article has a different implementation using _bios_serialcom (from bios.h) which might be a good reference point for you.
http://support.microsoft.com/kb/39501
Suggestions for where to go from here:
I would also suggest replacing the literals (eg 0x08) using the constants predefined for Baud rate, Parity (eg _COM_NOPARITY) to make the code more readable in your question.
Check that the Com port is actually open, as its a assumption which is unchecked in your code example above.
Also check up on the pin connections for the DB9. To connect two computers/devices you will need to null modem it, eg pin 2 to pin 3 at the other end, plus the Signal Ground. Make sure you are disabling/not looking for DTR.
If the other computer/device is setup then I would suggest first running HyperTerminal (Programs->Accessories->Communication) and connect to your COM 1 and check you can see characters from the other device. If not its most likely related to your cable.
Hope that helps.
Before checking with your code always check your serial communication with a terminal program. I don't have much experience with Windows environment but in Linux you have programs like cutecom or gtkterm where you can send/receive data from serial port. We extensively used these programs for serial communication in Linux, they are great for debugging potential problems with serial port interface (both h/w & s/w as well). So, before suspecting your code check with a terminal emulator program.
Hey, I am not an expert on Win32, but it seems to be easier to use another article as a source (the one mentioned here before looks outdated):
http://msdn.microsoft.com/en-us/library/ms810467
This is old too, dated around 1995, but it looks still effective. The NT architecture is very restrictive when it comes to grant access to hardware, for example, to send bytes to a PC paralell port one needs to rely on workarounds dll written by open source developers.
I'm assuming from your comment about "pin 2 & 3" that you've connected a loopback cable, so you're expecting to see anything you type come up on the screen (and stop doing so when you disconnect the cable).
I think there's a bug in the code: the if (kbhit()) is inside the if (status & DATA_READY).
That means you only check the keyboard if there is some input ready to receive from the serial port - which there won't be, because you haven't sent it anything yet! Try moving the test and see if it improves matters.
(Here is some similar serial port code that puts the if (kbhit()) test outside the DATA_READY check. It doesn't claim to work, but provides some evidence that this might be the source of the problem...)