Weird bug in i2c between Arduino and Raspberry Pi 4B - string

I have a weird bug when I'm sending data from Arduino Mega via I2C to Raspberry Pi 4B.
Arduino Mega is working as slave and Raspberry Pi as master. Raspberry Pi request data from Arduino and it sends a string of letters and numbers that look like this(no newline on the end):
xxE5xNx
but Raspberry Pi receives:
xxE5xN#
For sure that's not a issue with wiring, because I tested sending and receiving of 1000 packets without any error.
This bug does not happen when I change 'E', '5' or 'N' to another character or delete first two characters. When changing any of 'x' to another character bug still exists. Why?
Minimal code for reproducing:
Arduino Mega(slave):
#include <Wire.h>
String s = "xxE5xNx";
void i2cRequest(){
Wire.print(s);
}
void setup() {
Wire.begin(0x01);
Wire.onRequest(i2cRequest);
}
void loop() {}
Raspberry Pi 4B(master):
from smbus2 import SMBus
bus = SMBus(1)
data = bus.read_i2c_block_data(0x01, 0, 32)
text = ""
for m in data:
if(m != 255): text += chr(m)
print(text)

Related

Issue with sending a string from raspberry pi to arduino using i2c

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.

Bluetooth HC-05 Stop receiving data

i faced a problem with Arduino Uno and HC-05 Bluetooth.
i will be thankful if anyone could help me.
my problem is that: After uploading program to Arduino Uno successfully and sending commands from (Robotic arm app that was created by android studio) to Bluetooth HC-05, At first the Hc-05 receives data without any problem but after some movements to the arms the HC-05 stop receiving data from app and also Tx & Rx LEDs on Arduino don't work. if i restart Arduino it will work at first and then the same problem will happen.
#include <Servo.h>
Servo arm1;
Servo arm2;
Servo arm3;
Servo arm4;
Servo arm5;
char c = ' ';
String strData = "";
void setup() {
arm1.attach(3);
arm2.attach(5);
arm3.attach(6);
arm4.attach(9);
arm5.attach(10);
arm1.write(0);
arm2.write(0);
arm3.write(0);
arm4.write(0);
arm5.write(90);
Serial.begin(9600);
}
void loop() {
if (Serial.available() > 0) {
while (Serial.available() > 0) {
c = ((byte)Serial.read());
if (c == '?') {
String strDegree = strData.substring(6, strData.length());
int intDegree = strDegree.toInt();
if(strData.indexOf("arm1") >= 0)
arm1.write(intDegree);
if(strData.indexOf("arm2") >= 0)
arm2.write(intDegree);
if(strData.indexOf("arm3") >= 0)
arm3.write(intDegree);
if(strData.indexOf("arm4") >= 0)
arm4.write(intDegree);
if(strData.indexOf("arm5") >= 0)
arm5.write(intDegree);
Serial.println(strData);
strData = "";
break;
}
else {
strData += c;
}
delay(1);
}
}
}
i am waiting to hear something from you.
Best regards.
I hope it's not too late to help: D
Your code is good (Assuming the application you have is also correct)
I think the problem is in the hardware. I think that during the motion of the robot arm motor, there is a significant voltage drop on the arduin and that is why the connection is lost.
Try connecting the HC-05 to a separate power supply (VCC - 3.3-5V, HC-05 GND - Arduino GND - GND external power) and I think your problem will be solved.
I wonder what robot arm you use to integrate with the Arduino? I found a site where there are many robotic arms, but none are compatible with Arduino.

Raspberry pi receives numbers from arduino

I am experimenting with connecting Raspberry Pi to Arduino, and when I set a loop to receive info from Arduino Uno serial, it only receives:
'118537\r\n'
That is when I try to serial print 'Hi'
Here is my arduino code:
void setup(){
Serial.begin(9600);
}
void loop(){
Serial.println('Hi');
delay(2000);
}
Here is my python 3.2 code:
import serial
ser = serial.Serial('/dev/ttyACM0')
while True:
print(ser.readline())
This prints: '118537\r\n' every 2 seconds.
How can I get the original 'Hi' every 2 seconds?
For those of you who want to know, it was the fact that I used ' instead of " in the string, changing:
Serial.println('Hi');
to
Serial.println("Hi");
eta: the reason why '118537\n\n' is printed out is because 'Hi' is a literal array of two bytes rather than a "string" and therefore the compiler uses the function for printing an int. In fact, the hex code of H is 48 and the hex code of i is 69, and the hexadecimal value of 0x4869 is exactly 118537 in decimal notation.

ZS-040 (HC-05) Bluetooth module doesn't respond to AT

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.

Serial connection return NULL after first call

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.

Resources