I'm trying to talk to an arduino via a rs485 serial link. I have a usb to serial rs485 adapter plugged in my pc and a max485 in the arduino side. To get started i simply uploaded a sketch that send back what it receives.
#include <SoftwareSerial.h>
#define SSerialRX 10 //Serial Receive pin
#define SSerialTX 11 //Serial Transmit pin
#define SSerialTxControl 3 //RS485 Direction control
#define RS485Transmit HIGH
#define RS485Receive LOW
#define Pin13LED 13
SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX
void setup()
{
pinMode(Pin13LED, OUTPUT);
pinMode(SSerialTxControl, OUTPUT);
digitalWrite(SSerialTxControl, RS485Receive);
RS485Serial.begin(300);
}//--(end setup )---
void loop()
{
if (RS485Serial.available()){
delay(100);
char x = RS485Serial.read();
digitalWrite(Pin13LED, HIGH);
digitalWrite(SSerialTxControl, RS485Transmit); // Enable RS485 Transmit
Serial.write(x);
RS485Serial.write(x);
Serial.flush();
delay(10);
digitalWrite(SSerialTxControl, RS485Receive); // Disable RS485 Transmit
digitalWrite(Pin13LED, LOW);
delay(200);
}
}//--(end main loop )---
Then, to test the connection, i run a python script in the pc that writes a character to the serial port and listens to the response:
import serial
import time
PORT1 = "/dev/ttyUSB0"
try:
rs485 = serial.Serial(PORT1, 300)
while True:
print 'loop'
rs485.write('r')
time.sleep(0.5)
data = rs485.read()
if data == '\0':
print 'null'
else:
print data
time.sleep(1)
except:
rs485.close()
The first time I launch the script it happens something like this:
giulio#giulio-vaio:~$ python rs485io.py
loop
r
loop
r
loop
^C
If i try to launch again the script, it writes nothing more than:
giulio#giulio-vaio:~$ python rs485io.py
loop
null
loop
null
loop
null
^C
It starts working again only if i reboot my pc (with ubuntu by the way). If i unplug and plug again the usb to serial converter, nothing changes, if i reboot the arduino, same story. I tried the same configuration with a raspberry pi and the result is identical. Changing usb port doesn't work, upload again the same sketch in the arduino, nothing happens.
The led on the pin 13 blinks, so the arduino is receiving and sending something, the serial.read() function returns, so something is arriving, but is (after the first time) a null carachter '\x00'. In one positive case, after rebooting, I tried to let the script go on for a few time and everything went fine, until i hitted ctrl-c and started again the script.
This is dmesg after i plug in the serial converter:
[ 6116.508264] usb 1-2.1.3: new full-speed USB device number 27 using ehci-pci
[ 6116.617247] usb 1-2.1.3: New USB device found, idVendor=1a86, idProduct=7523
[ 6116.617257] usb 1-2.1.3: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[ 6116.617264] usb 1-2.1.3: Product: USB2.0-Serial
[ 6116.617694] ch341 1-2.1.3:1.0: ch341-uart converter detected
[ 6116.621498] usb 1-2.1.3: ch341-uart converter now attached to ttyUSB0
I don't know what to do after this, any help would be appreciated.
EDIT :
the pc doesn't need to be rebooted, it works if i unload and then load again the module ch341, the one that handles the usb converter.
I added two lines at the top of the code:
subprocess.Popen("modprobe -r ch341".split()).wait()
subprocess.Popen("modprobe ch341".split()).wait()
I know it doesn't really solve the problem, but it works.
EDIT 2 :
Looking at the documentation http://lxr.free-electrons.com/source/Documentation/serial/serial-rs485.txt , I tried to send an ioctl signal to the driver, using this code in c (i'm not good with C, so please forgive me)
#include (all the libraries needed)
/* Driver-specific ioctls: */
#define TIOCGRS485 0x542E
#define TIOCSRS485 0x542F
/* Open your specific device (e.g., /dev/mydevice): */
int main(){
const char *file1 = "/dev/ttyUSB0";
const char *file2 = "output_cprog.txt";
int fd = open (file1,O_WRONLY);
if(fd < 0){
printf("%s: %s\n","error opening ttyusb",strerror( errno ) );
}
int fq = open(file2,O_WRONLY);
if( fq < 0){
printf("%s: %s\n","errore apertura file",strerror( errno ));
}
struct serial_rs485 rs485conf;
// Enable RS485 mode:
rs485conf.flags |= SER_RS485_ENABLED;
// Set logical level for RTS pin equal to 1 when sending:
rs485conf.flags |= SER_RS485_RTS_ON_SEND;
// or, set logical level for RTS pin equal to 0 after sending:
rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
// Set rts delay before send, if needed:
rs485conf.delay_rts_before_send = 10;
// Set rts delay after send, if needed:
rs485conf.delay_rts_after_send = 10;
int ioc = ioctl (fd, TIOCSRS485, &rs485conf);
if(ioc < 0){
printf("%i\n",ioc);
printf("ioctl error: %s\n", strerror( errno ));
}
char *character = "f\n";
write(fd,character,2);
char *buffer;
buffer = (char *) malloc(10);
read(fd, buffer, 1);
write(fq, buffer, 1);
printf("received character: %s\n",buffer[0]);
if( close(fd) < 0){
printf("%s: %s\n","error closing port",strerror( errno ));
}
if (close(fq) < 0){
printf("%s: %s\n","error closing file",strerror( errno ));
}
return 0;
}
but compiling and running the program what i see is only this:
giulio#giulio-vaio:~$ ./ioctlRS485.o
-1
ioctl error: Inappropriate ioctl for device
received character: (null)
I think, by looking at the driver https://github.com/torvalds/linux/blob/master/drivers/usb/serial/ch341.c that it doesn't have the appropriate function to handle an ioctl at all.
Related
I want to send multibyte integers,(eg. 1000,10000, etc) from raspberry pi to arduino. It can either be in the form of int or string(will convert it into integer on arduino's side) through i2c. Now, I am able to send data but only till 255, If I try to send 1000, the output on ARduino serial terminal will be 232 and not 1000. I tried to search over the internet for like 4-5 hours, but no luck. Can someone please guide me?
import smbus
import time
bus = smbus.SMBus(1)
address = 0x04
a=1000
#a=str(a)
def writeString(a,b,c,d):
bus.write_i2c_block_data(address, a, [b, c, d])
return -1
while True:
try:
writeString(1000,a,5,0)
time.sleep(1) #delay one second
except KeyboardInterrupt:
quit()
Arduino:
#include <Wire.h>
int data [4];
int x = 0;
void setup() {
Serial.begin(9600);
Wire.begin(0x04);
Wire.onReceive(receiveData); //callback for i2c. Jump to void recieveData() function when pi sends data
}
void loop () {
delay(100); //Delay 0.1 seconds. Something for the arduino to do when it is not inside the reciveData() function. This also might be to prevent data collisions.
}
void receiveData(int byteCount) {
while(Wire.available()) { //Wire.available() returns the number of bytes available for retrieval with Wire.read(). Or it returns TRUE for values >0.
data[x]=Wire.read();
x++;
}
Serial.println("----");
Serial.print(data[0]);
Serial.print("\t");
Serial.print(data[1]);
Serial.print("\t");
Serial.print(data[2]);
Serial.print("\t");
Serial.println(data[3]);
// Serial.print("----");
}
I2C sends and receives BYTES. 1000 in hex is 0x3E8. 232 in hex is 0xE8. Only the low byte is sent.
Hello,
so I have bought a ZS-040 HC-05 Arduino Bluetooth module and I want to change its name. I've learned, that you have to do that in AT Mode. I followed all instructions at http://www.martyncurrey.com/arduino-with-hc-05-bluetooth-module-at-mode/ I succesfully entered the AT Mode (Red LED is Blinking every 2 Seconds), but when I enter AT into the Serial Monitor, i get nothing.
This is my Arduino Code (preaty much exactly the same as described in that article)
#include <SoftwareSerial.h>
SoftwareSerial BTserial(2, 3); // RX | TX
char c = ' ';
void setup()
{
Serial.begin(9600);
Serial.println("Arduino is ready");
Serial.println("Remember to select Both NL & CR in the serial monitor");
BTserial.begin(38400);
}
void loop()
{
if (BTserial.available())
{
c = BTserial.read();
Serial.write(c);
}
if (Serial.available())
{
c = Serial.read();
BTserial.write(c);
}
}
Everything is connected as described in Method 1 (Other Methods doesn't work for me). I've set the Serial Monitors Baud to 9600 and to Both NL and CR.
If someone has experiense with this problem and solved it, please help :)
Thank you all very much!
I struggled with this for a while.
Upload a blank sketch (void setup(){} void loop(){})
Attach bluetooth module RX to RX on the Arduino (pin0) and TX to TX (pin1)
Insert ground wire from Bluetooth to G on the Arduino and EN to 3.3v
Power the Arduino
Insert the VCC from Bluetooth into 5v while holding down the small button on the bluetooth.
Bluetooth should have a very slow blink now, indicating it is in command mode.
Open the serial monitor on your computer. Set the baud rate to 38400. You will be able to test the connection by typing 'at'. It should respond 'OK' - try typing 'at' a second time if the first time receives an error.
the reason why this connection works is because 0 and 1 pins are used by the serial monitor when communicating with the Arduino. No program is need because it is the default connection when the monitor is opened.
I hope this helps.
I am trying to talk to a Bosch Sensortec BNO055 sensor. I am using the shuttleboard. VDD and VDDIO are connected to 3.3V, on pin 17 and 18 Are SDA and SCL. These connected to a embedded linux board. An other sensor is on the same bus, I can see its values on the scope.
I have the following code:
BNO055_RETURN_FUNCTION_TYPE Bno055I2cBusWrite(u8 dev_addr, u8 reg_addr, u8* reg_data, u8 wr_len){
//According to https://www.kernel.org/doc/Documentation/i2c/dev-interface
int file = 0;
char filename[20];
snprintf(filename, 19, "/dev/i2c-%d", ADAPTER_NR);
if(open(filename, O_RDWR) < 0){ /*error*/ }
if(ioctl(file, I2C_SLAVE, dev_addr) < 0){ /*error*/ }
char buf[1 + wr_len];
buf[0] = reg_addr;
memcpy(&buf[1], reg_data, wr_len);
int written_bytes = 0;
if(write(file, buf, wr_len) != wr_len){
printf("Error BusWrite-write: %s.\n", strerror(errno));
exit(-1);
}
}
The first two if-statements are passed fine.
The write-operation fails. On the oscilloscope I see the correct device-address (which is then not acknowledged).
What I've done:
Added the device-address to buf (not covered in this code example).
Read and understood page 90-92 from the datasheet https://ae-bst.resource.bosch.com/media/products/dokumente/bno055/BST_BNO055_DS000_12~1.pdf
Soldered 1k8 ohm resistors to get steeper edges on clock and data
Made sure that the device address and the read/write bit are set correct
My sensor just does not acknowledges when its device address appears on the line.
What is exactly done by ioctl(file, I2C_SLAVE, dev_addr)? Does that send out the device-address on the I2C-bus?
Does the linuxkernel send the device-address by itself? I expect so.
Resuming:
Can someone point me in the right direction to let the sensor react?
Well... it just seemed that a wire to the scope interfered too much. And the device-address is sent by the driver when writing or reading, to answer my own question.
I have bluetooth module connected to AVR (Atmega32A) via UART. Some bytes that are transmit from bluetooth module to AVR are not properly recived.
For example the bytes that are properly transmit/recived (UTF-8):
Bluetooth module transmit byte X->recived byte X'
'w'->'w'
's'->'s'
'z'->'z'
'm'->'m'
bytes recived not properly:
'q'->'y'
'p'->'~'
'1'->'9'
Bluetooth connection settings:
Bps/Par/Bits: 115200 8N1
init UART:
#define F_CLK 16000000
#define BAUD 115200
uint16_t ubrr_value = (uint16_t) (((F_CLK)/(16 * BAUD)) - 1);
UBRRL = ubrr_value;
UBRRH = (ubrr_value>>8);
// 8 bit frame, async mode
UCSRC=(1<<URSEL) | (3<<UCSZ0);
//recive and transmit mode
UCSRB = (1<<TXEN) | (1 << RXEN);
transmit/recive byte by uart:
char USART_ReceiveByte()
{
while(!(UCSRA & (1<<RXC)));
return UDR;
}
void uart_sendRS(char VALUE)
{
while(!(UCSRA & (1<<UDRE)));
UDR = VALUE;
}
main loop:
while(1)
{
recivedByte = USART_ReceiveByte();
uart_sendRS(recivedByte);
}
i would be so glad to know why it does not work properly
EDIT: if i change the order there is result:
'y'->'y'
'~'->'~'
'9'->'9'
EDIT2: probably there is something wrong with setting UBRRL and UBRRH (ubrr_value = 7 in this case), does someone can confirm if it is proper and if the microcontroller can handle such a high BAUD?
#define F_CLK 16000000
#define BAUD 115200
uint16_t ubrr_value = (uint16_t) (((F_CLK)/(16 * BAUD)) - 1);
UBRRL = ubrr_value;
UBRRH = (ubrr_value>>8);
The problem here is that you are not initialising the UART properly. You need to set the U2X bit in UCSRA if you wish to use the baud rate as you wish it configured. If you are using avr-libc you may use the following code to properly compute the BAUD rate.
void uart0_init(void) {
# define BAUD 115200
# include <util/setbaud.h>
UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
# if USE_2X
UCSRA |= _BV(U2X);
# else
UCSRA &= ~_BV(U2X);
# endif
# undef BAUD
/* other uart stuff you may need */
}
If you look at the datasheet for your microcontroller, section 20.12, you will find a table with this information precomputed for you. Cheers.
I am using a UART on a single board computer (Olimex A13) and I am trying to send and receive data through the UART. On the send side I have no problems. The Olimex board sends data to the serial buss and it is received on an external PC that is running putty terminal.
When I try to go in the other direction (PC sends data to be received by the Olimex board) I am running into a weird problem. When I start to send data, initially no data shows up on the Olimex board (I have tried 2 methods... cat /dev/ttyS0 and setting up a receive C program. Both exhibit the same results).
If I send data for a while (seems to vary from less than 10 characters to something over 20) at some point the uart seems to "wake up" and now data appears on the Olimex board. Once the data transfer starts it will keep going as long as I want and at fast or slow data rates. If I break out of the receive program or end the cat /dev/ttyS0 process and try to start receiving again, I need to go through the same process of "kicking" the uart until it decides it wants to receive again.
I have put an oscilloscope on the RX pin leading into the UART. The data coming in is at good levels and the data appears here from the very first send so the data is not being blocked initially and then arriving at the RX pin at some time later. So I am currently assuming that the issue is with a UART setting of some kind. Does anyone know of a UART setting that could possibly explain this behavior?
Below is the receive program that I am running. I don't think that there is an issue with it because I see the same behavior when I do a cat /dev/ttyS0. Any help here would be appreciated.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#define BAUDRATE B115200
#define MODEMDEVICE "/dev/ttyS0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
main()
{
int fd,c, res;
struct termios oldtio,newtio;
char buf[255];
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {perror(MODEMDEVICE); return(-1); }
tcgetattr(fd,&oldtio); /* save current port settings */
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
/* set input mode (non-canonical, no echo,...) */
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
newtio.c_cc[VMIN] = 1; /* blocking read until 5 chars received */
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
while (STOP==FALSE) { /* loop for input */
res = read(fd,buf,255); /* returns after 5 chars have been input */
buf[res]=0; /* so we can printf... */
printf("String:%s - Character Count:%d\n", buf, res);
if (buf[0]=='z') STOP=TRUE;
}
tcsetattr(fd,TCSANOW,&oldtio);
}
Sawdust made these comments....
"sends data to the serial buss" -- RS232 is not a "buss". "When I
start to send data" -- Your writing style is confusing. What kind of
data is sent to the Olimex? For the cat /dev/ttyS0 test, how did you
set up the serial port, or was it in an unknown mode? bzero(&newtio,
sizeof(newtio)); -- That is a dangerous way to setup the termios
structure. newtio.c_cflag = BAUDRATE... That is not the proper way to
set the baud rate; you need to use the cfset[io]speed() functions. You
write of a "kick", yet you don't mention doing anything explicit
ok, RS232 is not a buss, I misspoke....
The data I am sending is a stream of characters that are typed on Putty terminal.
For the /dev/ttyS0 test the settings are the same as are set in the c program. I verified this using stty.
I copied this code from another post. I was not sure what bzero did. If you could expand on "dangerous" that would be great. Or better if you have a better way to do what bzero does?
I will update the way to set baud rate.. but send is working perfectly and I verified using stty that baudrate was indeed 115200.
As far as "kicking" I mean that I need to send a number of bytes of data to the uart before any appear on the console. Others have mentioned a FIFO that may be an issue here but the first characters that are sent are lost. For example if I were to send the string of characters abcdefg.... I could type up until k and then l would appear on the console, and then any future characters after l would also appear in the console. If I were to go through the same process again after starting the receive program (or cat /dev/ttyS0) the point where the receive starts appearing could be in a different place (i.e. at h or n).