My project is currently nothing more than getting my feet wet in serial communications without using the built-in arduino serial console.
Method: Send serial using POSIX compliant C++ to arduino.
Expected result: Arduino reads sent serial data, and displays it on an 16x2 LCD.
Actual result: When using the arduino IDE serial console the result works exactly as expected. When sending the data from my c++ program the arduino reads different characters every time, usually non-english characters.
Things i've tried to fix it:
I've been trying to fix this for more than a week before asking for help. I've spent more than 24 hours looking up the problem, and can' t seem to make it work.
I've tried the current method, I tried using libserial, I've tried using other people's "working" code. I was able to get it to work when I made a terminal version, the port configuration of which is in the current code, but not working. I've tried introducing delays when opening the port (I have a capacitor in the arduino to prevent it from resetting when the port opens - confirmed working.) I've researched the basics of serial communication, the settings, and different methods of sending it, but nothing is working.
The program does use a wxwidgets interface, which I wont include in the code for brevity's sake. It's worth noting that I've tried closing the port after every send, as well as just closing it when the program terminates. Neither seems to matter.
C++ Program:
#include "wx_pch.h"
#include "ArduinoInterfaceMain.h"
#include <wx/msgdlg.h>
#include <iostream>
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <fstream>
#include <string.h>
#include <wx/combobox.h>
//#include "arduino-serial-lib.h"
#define PORT "/dev/ttyACM0"
#define BAUD 9600
using namespace std;
int fd;
int openPort(){
int fd = open(PORT, O_RDWR | O_NOCTTY | O_NDELAY);
if(fd == 1){
// printf("failed to open port \n");
}
struct termios config;
if(!isatty(fd)){
// cout << "Not a real terminal";
}
if(tcgetattr(fd, &config) < 0){
// cout << "tcgetattr: fd < 0";
}
config.c_iflag &= ~(IGNBRK | BRKINT | ICRNL | INLCR | PARMRK | INPCK | ISTRIP | IXON);
//~(Turn off processing | Convert break to null byte | No CR->NL | No NL->CR | Ignore Parity Errors | Dont strip high bit | no flow control);
config.c_oflag = 0;
config.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
config.c_cflag &= ~(CSIZE | PARENB);
config.c_cflag |= CS8;
config.c_cc[VMIN] = 1;
config.c_cc[VTIME] = 0;
if(cfsetispeed(&config, B9600) < 0 || cfsetospeed(&config, B9600) < 0){
// cout << "Problem setting Baud to 9600";
}
if(tcsetattr(fd, TCSAFLUSH, &config) < 0){
// cout << "Problem setting attributes to fd";
}
return(fd);
}
int closePort(int fd){
return close(fd);
}
int transmit(int fd, string str){
int len = str.size();
int n = write(fd, &str, len);
if (n!=len){
perror("transmit():Couldn't write full string");
return -1;
}
}
void ArduinoInterfaceFrame::OnbtnSendTestClick(wxCommandEvent& event)
{
fd = openPort();
usleep(10000);
//char dummystring = 'x';
string dummystring = "he";
int a = transmit(fd, dummystring);// need function to generate this string from options!
lblResponse->SetLabel(wxT("sent"));
//closePort(fd);
}
I also tried this, based on the tutorial i found here.
/* struct termios toptions;
int fd;
fd = open(PORT, O_RDWR | O_NOCTTY | O_NDELAY);
//fd = open(PORT, O_RDWR | O_NONBLOCK );
if (fd == -1) {
perror("serialport_init: Unable to open port ");
return -1;
}
//int iflags = TIOCM_DTR;
//ioctl(fd, TIOCMBIS, &iflags); // turn on DTR
//ioctl(fd, TIOCMBIC, &iflags); // turn off DTR
if (tcgetattr(fd, &toptions) < 0) {
perror("serialport_init: Couldn't get term attributes");
return -1;
}
speed_t brate = BAUD; // let you override switch below if needed
switch(BAUD) {
case 4800: brate=B4800; break;
case 9600: brate=B9600; break;
case 19200: brate=B19200; break;
case 38400: brate=B38400; break;
case 57600: brate=B57600; break;
case 115200: brate=B115200; break;
}
cfsetispeed(&toptions, B9600);
cfsetospeed(&toptions, B9600);
// 8N1
toptions.c_cflag &= ~PARENB;
toptions.c_cflag &= ~CSTOPB;
toptions.c_cflag &= ~CSIZE;
toptions.c_cflag |= CS8;
// no flow control
toptions.c_cflag &= ~CRTSCTS;
//toptions.c_cflag &= ~HUPCL; // disable hang-up-on-close to avoid reset
toptions.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
toptions.c_oflag &= ~OPOST; // make raw
// see: http://unixwiz.net/techtips/termios-vmin-vtime.html
toptions.c_cc[VMIN] = 0;
toptions.c_cc[VTIME] = 0;
//toptions.c_cc[VTIME] = 20;
tcsetattr(fd, TCSANOW, &toptions);
if( tcsetattr(fd, TCSAFLUSH, &toptions) < 0) {
perror("init_serialport: Couldn't set term attributes");
return -1;
}
return fd;*/
And the code on the Arduino. Remember that when I send data from the IDE console it works 100%.
#include <LiquidCrystal.h>
LiquidCrystal lcd(12,11,5,4,3,2);
//int intMenu, intSubmenu, intChoice, intEnd = -1;
char buffer[6];
void setup(){
lcd.begin(16, 2);
lcd.print("Booted");
Serial.begin(9600);
pinMode(13, OUTPUT);
}
void loop() {
if(Serial.available()){
delay(10);
// if(Serial.peek() == '<'){
//Serial.read(); // Erase <
//delay(10);
for(int n=0; n<5; n++){ //Get Data
buffer[n] = Serial.read();
delay(10);
}
lcd.setCursor(0,1);
for(int i=0;i<5;i++){
lcd.print(buffer[i]);
Serial.println(buffer[i]);
}
//}
}
}
A lot of the code has commented-out code. This is just the result of different attempts having different results. I've removed a lot of commented code, but obviously that wont affect the outcome.