Can I use the USB port of the raspberry pi (model B+) for serial communication (RS232) - python-2.7

I need to interface an old machine (thermostream) to interface with the raspberry pi (model B+)
The thermostream device has a RS232 serial port and I want to connect it to the USB port of the raspberry pi using the RS232 serial to usb cable (where the usb end of the cable is inserted in the pi and the serial end is connected to the device). And I need to write the code in python.
IS this possible? If yes, how should I proceed? Any help is greatly appreciated.

Yes. First you need to install pyserial
Then, in Python, you can use the following function to create a serial object that connects to a port. The usb ports on the pi are dynamically assigned a name and those names can change. This function will enable you to loop through each port for the name. (might not work well with multiple devices attached). Check your connection settings on the device you wish to communicate with (baudrate, parity, stopbits etc) and modify the code to use those settings.
import serial
def serialConnect():
serlocations=['/dev/ttyACM', '/dev/ttyACM0', '/dev/ttyACM1','/dev/ttyACM2', '/dev/ttyACM3','/dev/ttyACM4', '/dev/ttyACM5','/dev/ttyUSB0','/dev/ttyUSB1','/dev/ttyUSB2','/dev/ttyUSB3', '/dev/ttyUSB4', '/dev/ttyUSB5', '/dev/ttyUSB6', '/dev/ttyUSB7', '/dev/ttyUSB8', '/dev/ttyUSB9', '/dev/ttyUSB10','/dev/ttyS0', '/dev/ttyS1', '/dev/ttyS2', 'com2', 'com3', 'com4', 'com5', 'com6', 'com7', 'com8', 'com9', 'com10', 'com11', 'com12', 'com13', 'com14', 'com15', 'com16', 'com17', 'com18', 'com19', 'com20', 'com21', 'com1', 'end']
for device in serlocations:
try:
ser = serial.Serial(
port=device,
baudrate=9600,
parity=serial.PARITY_ODD,
stopbits=serial.STOPBITS_TWO,
bytesize=serial.SEVENBITS
)
print device
return ser
except:
x=0
if device == 'end':
print "No Device Found"
ser = serialConnect()
if ser:
ser.write("TEST")
ser.timeout=5
for i in ser.readlines():
print i

Related

Setting up Serial USB communication between STM32 and PC with Mbed library

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);
}
}
}

Serial Communication in Raspberry pi 3 B+

I want to communicate between Raspberry pi 3 B+ and GSM GPRS A6. I tried and I am unable to send data to GPRS Module from Raspberry pi.
Now, I know that GPIO serial port is disabled by default in newer Operating Systems (in my case Raspbian Stretch), so I have enabled it by adding following line in config.txt file,
enable_uart=1
Here's my Code:
import serial
import time
port = "/dev/ttyS0"
COMM = serial.Serial(port, baudrate=115200)
while(1):
COMM.write("AT\r")
print (COMM.read(5))
This command is supposed to return "OK", but it does not and nothing is printed. I am using python 2.7.
Some people suggested me to send data using this method,
COMM.write('AT' + '\r')
I tried but it didn't help.
There is no problem with my GPRS module. It works file with arduino.
So, what am I doing wrong here?
Thanks in advance!
,
First , be sure to enable the Serial.
sudo raspi-config -> Interfacing Option -> Serial
Second , sudo nano /boot/cmdline.txt
Delete "console=serial,115200"
And Then
sudo nano /boot/config.txt
Add the end
dtoverlay=pi3-disable-bt
core_freq=250
While you use : Serial(/dev/ttyAMA0,9600)
try sending:
import serial
port = "/dev/ttyS0"
comm = serial.Serial(port, baudrate=115200)
while True:
comm.write('AT' + '\n\r')
msg = comm.readline()
print(msg)

How do I programatically remove a flash drive based on its device node name?

I have a Linux system with multiple USB flash drives plugged in, as /dev/sda1, /dev/sdb1, etc. I need to eject one of these from within my program -- something like EjectDrive("/dev/sdb1"); I then may need to programmatically re-insert the drive.
I know I can do this from the command line if I know the USB bus, port and device number. e.g. echo '2-1.3' > /sys/bus/usb/drivers/usb/unbind and then echo '2-1.3' > /sys/bus/usb/drivers/usb/bind
I'm not sure how to do this from C++, and be 100% sure I am using the correct bus, port and device for the specified drive.
This is an embedded platform with BusyBox v1.22.1, so udev is not available to me, and lsusb returns minimal information.
Yes it can be done using libusb (follow this link for libusb usage with C++). Now a few things to keep in mind -
1 - What is the device address? (You can get this using libusb API)
libusb_get_device_list (libusb_context *ctx, libusb_device ***list)
libusb_get_device_address (libusb_device *dev)
libusb_get_port_number (libusb_device *dev)
2 - Is the device connected to the root hub port or to a hub port? (This can be done by reading the parent device of the /dev/sdb1 or sda1)
libusb_get_parent (libusb_device *dev)
3 - If its connected to a hub, then do a control transfer to "clear" PORT_POWER feature of that port. That will turn off the port and the device will be disconnected. You can "set" PORT_POWER feature to turn on the port and the device will be connected again. Remember that you will not get any disconnect event which is as per the spec. (EHCI or XHCI)
int libusb_control_transfer ( libusb_device_handle * dev_handle,
uint8_t bmRequestType,
uint8_t bRequest,
uint16_t wValue,
uint16_t wIndex,
unsigned char * data,
uint16_t wLength,
unsigned int timeout
)
4 - If the device is connected to the root hub port directly, then please check if libusb supports clearing root hub port power. I am not sure about this. This also depends on the Host controller driver stack.
Please follow the link I mentioned at the top for example usage of these API's.

Lwip on mbed-os 5 doesn't make a proper ethernet connection

My goal is to send UDP packets from the microcontroller (nucleo board) to the PC - as simple as that. Update: I reached the goal successfully. I'll explain here how I did it, and the problems I stumbled upon initially. Many thanks to the StackOverflow community and people on LinkedIn ARM group to help me out!
1. SYSTEM OVERVIEW
My system is as follows:
1.1 Microcontroller side
Nucleo_F767ZI board with STM32F767ZI microcontroller. This board has an ethernet connector.
Mbed-OS 5 operating system.
lwip library (wich is part from the Mbed-OS 5 operating system).
1.2 PC side 🖳
Windows 10, 64-bit.
Free ethernet port (internet is through WiFi, that's why this ethernet port is unused).
Wireshark to see if the microcontroller actually sends out UDP packets. Interpretation of them will be done later on in Python. First I want to see packets in Wireshark.
1.3 Connections
Initially I connected the nucleo board directly to my computer, without a router or switch involved. Such a setup requires "static IP configuration". I would configure the PC to have IP address "192.168.1.10" and the microcontroller to have "192.168.1.20". I know this can work, because I've done it before with a PIC microcontroller.
But this situation is a little different. I got a little operating system running on the microcontroller: mbed-os v5. This operating system makes use of Lwip (Light-weight ip stack). Although it should be possible to configure a "static IP address", the software currently doesn't support it. More information can be found here: https://developer.mbed.org/questions/74145/EthernetInterfaceinit-mbed-os-5x-not-wor/. Because there is no way to configure a static IP address on the microcontroller, you need a DHCP server. The microcontroller connects to the network without an IP address, and broadcasts a packet with the question: "What IP address should I use on this network?". If the microcontroller doesn't get an answer, it will broadcast the question a few times, and eventually give up.
If there is a DHCP server connected to the network, it will receive the question and hand over a free IP address. So that is what you need. There are several ways to provide such a DHCP server:
Install a DHCP server on your Windows PC. This is the only way to keep switches and routers out of the picture. The nucleo board is connected directly to the PC. When the microcontroller broadcasts the question, the Windows PC hands over an IP address. After that, communication can start.
Throw a Raspberry PI into the game. The Raspberry PI should run a DHCP server. Connect the three devices (Windows PC, Raspberry PI and Nucleo board) to a switch.
Buy a simple router. Home routers have a DHCP server built-in. Connect the Windows PC and the Nucleo board to the LAN ports of this router.
I decided to go for the third option. The following figure shows the connections to my Netgear R7000 router:
2. ROUTER SETUP
The DHCP server inside the router will hand out IP addresses to all devices that connect to it. My router will hand out the IP address "192.168.1.2" to the first device, "192.168.1.3" to the second, and so forth all the way up to "192.168.1.254". But that's a bit problematic. How can the PC and the microcontroller know each others IP addresses? Perhaps there are more clever solutions, but I've figured out the following approach.
Each DHCP server has a table with "reserved IP addresses". In this table, you can add devices and assign a static IP address to them. So whenever that device asks for an IP address, the DHCP server takes a look in the table and hands over the one you've configured. But how does the DHCP server recognizes a device? It can recognize a device by its MAC-address. Every device has a globally unique MAC-address of 6 bytes.
This is how I've added my Windows PC and my microcontroller to the table:
STEP 1: Connect the computer to one of the LAN ports of the router. Switch the router on.
STEP 2: Make sure that all WiFi on your computer is disconnected. I've experienced lots of issues with this. (*)
STEP 3: Open a browser, and surf to "192.168.1.1". This is my routers home page. It could be different for your router.
STEP 4: Login (my routers default login is "admin" for the username and "password" for the password)
STEP 5: Add the Windows PC and the microcontroller board to the table. You have to look up their MAC-addresses first (**):
2.1 Disconnect all WiFi (*)
This should be a simple step, but Windows makes it hard. Windows can be quite stubborn and reconnect automatically to WiFi networks around, even if you've unchecked the connect automatically box! To force Windows to listen to you, you can use the cmd terminal. Open a cmd terminal with admin privileges. Next, type the following command to see all your WiFi profiles:
> netsh wlan show profiles
Apply the following command to those WiFi profiles that your PC is stubbornly connecting to:
> netsh wlan set profileparameter name="someWifiName" connectionmode=manual
Now you can disconnect from that WiFi network, and Windows won't reconnect automatically anymore.
2.2 Find the MAC address of your PC (**)
This is how I found the MAC-address of my computer. Keep in mind that a computer can have several MAC-addresses. The one for your ethernet port will be different to the one for your wireless connection! Type ipconfig /all in the Windows cmd terminal. I got the following output:
# Note: this is the correct item!
# --------------------------------
Ethernet adapter Local Area Connection:
Media State . . . . . . . . . . . : Media disconnected
Connection-specific DNS Suffix . :
Description . . . . . . . . . . . : Intel(R) Ethernet Connection (2) I219-LM
Physical Address. . . . . . . . . : C8-xx-xx-xx-xx-01 # Replaced some numbers by x for security :-)
DHCP Enabled. . . . . . . . . . . : Yes
Autoconfiguration Enabled . . . . : Yes
Make sure you're looking at the correct item in the list of connections. Ethernet adapter Local Area Connection is the correct one for my computer, because the network card description fits what is expected: Intel(R) Ethernet Connection (2) I219-LM. Before, I was looking at another item in the list, labelled Ethernet adapter Ethernet:
# Note: this is the wrong item!
# ------------------------------
Ethernet adapter Ethernet:
Media State . . . . . . . . . . . : Media disconnected
Connection-specific DNS Suffix . :
Description . . . . . . . . . . . : TAP-Windows Adapter V9
Physical Address. . . . . . . . . : 00-xx-xx-xx-xx-F7
DHCP Enabled. . . . . . . . . . . : No
Autoconfiguration Enabled . . . . : Yes
Mr. Joel C (see his answer below) notified me that the network card from that item is TAP-Windows Adapter V9. Apparently that is a virtual network card. That made me lose a lot of time. Thank you Mr. Joel C for helping me out!
Please make also sure that DHCP Enabled and Autoconfiguration Enabled are turned on!
2.3 Find the MAC address of your Nucleo board (**)
I found the MAC-address of my Nucleo board with the following code:
#include "lwip-interface/EthernetInterface.h"
//1. Make an ethernet object
EthernetInterface eth;
//2. Try to connect
eth.connect(); // <- This line will not work now,
// but at least it will help you to find out your
// own MAC-address.
//3. Print the MAC-address
logger.printf("Controller MAC Address is: %s\r\n", eth.get_mac_address());
The print output I got over my serial port is (some numbers I replaced by x for security):
Controller MAC Address is: 00:xx:xx:xx:xx:40
3. MICROCONTROLLER CODE
This is the code that runs on the microcontroller. My main.cpp file is inspired on the code found on the Mbed-os forum at https://forums.mbed.com/t/udp-receive-with-nucleo-f767zi/1806.
#include <string>
using std::string;
#include "mbed.h"
#include "lwip-interface/EthernetInterface.h"
static Serial logger(USBTX, USBRX);
static DigitalOut led1(LED1);
// IP addresses
#define IP_COMPUTER "192.168.1.10" // Make sure these IP addresses correspond to the
#define IP_NUCLEO "192.168.1.20" // table of 'reserved IP addresses' you have setup in
// your routers DHCP server!
// Ethernet settings
const int PORT_T = 50000;
const int PORT_R = 50001;
EthernetInterface eth;
static void udp_tx_thread_func();
static void udp_rx_thread_func();
static Thread udp_tx_thread;
static Thread udp_rx_thread;
int main()
{
// 1. Initialize the serial logger
logger.baud(115200);
logger.printf("\r\n\r\nApplication started\r\n");
// 2. Initialize and start the UDP connection
eth.connect();
logger.printf("Controller MAC Address is: %s\r\n", eth.get_mac_address());
logger.printf("Controller IP Address is: %s\r\n", eth.get_ip_address());
Thread::wait(200);
udp_tx_thread.start(udp_tx_thread_func);
udp_rx_thread.start(udp_rx_thread_func);
while (true)
{
led1 = !led1;
Thread::wait(500);
}
}
//------------------ Ethernet --------------------------------------------------
static void udp_tx_thread_func()
{
UDPSocket socket(&eth);
SocketAddress sock_addr(IP_COMPUTER, PORT_T);
static uint32_t out_buffer[3];
while(true)
{
Thread::wait(100);
// Send 3 values of 32-bit each
out_buffer[0] = 150500;
out_buffer[1] = 255300;
out_buffer[2] = 54;
int ret = socket.sendto(sock_addr, &out_buffer[0], 12); // 3 values of 32-bit equals 12 bytes
//logger.printf("sendto return: %d\r\n", ret);
}
}
static void udp_rx_thread_func()
{
UDPSocket socket(&eth);
SocketAddress sock_addr;
int bind = socket.bind(PORT_R);
logger.printf("bind return: %d\n", bind);
char buffer[256];
while(true)
{
//logger.printf("\nWait for packet...\n");
int n = socket.recvfrom(&sock_addr, buffer, sizeof(buffer));
buffer[n] = '\0';
//logger.printf("Packet from \"%s\": %s\n", sock_addr.get_ip_address(), buffer);
Thread::wait(500);
}
}
4. RESULTS
4.1 Wireshark results
In Wireshark I can see the UDP packets flowing in on the Local Area Connection! Huray!
4.2 Python code
The python code to catch the UDP packets looks like this:
import sys
import os
import socket
import dataprocessing.datastruct as datastruct
def main():
# 1. Configure the IP address
# -----------------------------
myAddr = ('192.168.1.10', 50000)
# 2. Create a UDP socket
# -----------------------
sock = None
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(1.5)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(myAddr)
print('UDPsock #: ' + str(sock.getsockname()))
sys.stdout.flush()
except Exception as e:
print('Could not bind to the UDP socket.')
print(e)
sys.stdout.flush()
while (true):
try:
data, address = sock.recvfrom(256) # buffer size is 256 bytes
bytedata = bytearray(data)
# Each 32-bit number is cut in 8-bit pieces. Bring them back together.
value_01 = bytedata[0] + 256*bytedata[1] + 65536*bytedata[2] + 16777216*bytedata[3]
value_02 = bytedata[4] + 256*bytedata[5] + 65536*bytedata[6] + 16777216*bytedata[7]
value_03 = bytedata[8] + 256*bytedata[9] + 65536*bytedata[10] + 16777216*bytedata[11]
print("Value 01: %d", value_01)
print("Value 02: %d", value_02)
print("Value 03: %d", value_03)
except socket.error as err:
print(err)
if __name__== '__main__':
print("")
print("Start UDP catcher")
print("-----------------")
main()
5. LET WIFI AND ETHERNET COEXIST
The UDP packets from the microcontroller flow in on your ethernet port (passing along the router). Meanwhile you might want to connect to some WiFi network for internet access. The problem is that any browser will try to get access through your ethernet port - ignoring the WiFi.
The solution is to make your browsers FIRST attempt to use the WiFi to reach an IP address, next attempt through the Ethernet port. This is done with the "Interface metric" in the Control Panel. Increase this number slightly:
The connection you have labelled Ethernet is actually a TAP connection (eg. a virtual ethernet card). Your actual ethernet connection is labelled Local Area Connection; that is the connection you will need to be configuring and watching with Wireshark, etc.
As to everything else Mbed-OS related, I personally have not dealt with it.

Why Serial Communications from Arduino stops after some time

I'm building a growbox/terrarium with arduino uno as the temperature controller. Simple sketch for arduino: if DS18B20 sensor giv less than 25'C than turn on relay, which the heating cable is connected to. Loop 30s, every time Serial.print(temperature) to the PC, where I'm collecting data and make timelapse photos. ---> Here is the problem.
After some time (from 15 min up to 4 hours). Serial communication with PC stops. When I'm trying to upload a new sketch to arduino I got an error msg:
avrdude: ser_open(): can't set com-state for "\.\COM3"
I need to unplug and plug in again USB cable (or turn it off and on in Windows Device Manager), also restart Python app that is collecting data. (Very unsatisfactory fix).
So my questions are:
1. Why?
2. How to fix it?
3. Or how to make some workaround, for example reset COM port from code (desirably python2.7)
PS. Example of what I'm doing and how it works(and do not works) here: Life of pepper
PS2. My goal is to make controllable habitate for plants, where I can see behaviours differs depending on the temp, day-duration, light-intensity, humidity.
Please help me :-) .
ARDUINO UNO SKETCH
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the A
rduino
#define ONE_WIRE_BUS 2
#define PIN_HEATING 6
float temperatura = 30.0;
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
void setup(void)
{
// start serial port
Serial.begin(9600);
// Start up the library
sensors.begin();
pinMode(PIN_HEATING, OUTPUT);
}
void loop(void)
{
delay(30000);
if(temperatura<25.0){
digitalWrite(PIN_HEATING, HIGH);
}
else{
digitalWrite(PIN_HEATING, LOW);
}
sensors.requestTemperatures(); // Send the command to get temperatures
// After we got the temperatures, we can print them here.
// We use the function ByIndex, and as an example get the temperature from the first sensor only.
temperatura = sensors.getTempCByIndex(0);
Serial.print("#");
Serial.print(temperatura);
}
PYTHON2.7 RECEIVING PART
import serial #pySerial
ser = serial.Serial()
ser.port = "COM3"
ser.open()
data = ser.read_all().split("#")
datasize = len(data)
if datasize>1:
temp = data[datasize-1]
tempstr = " / " + str(temp) + "'C"
else:
tempstr=" / ----- "
I've experienced a similar problem in the past where the serial port would become unresponsive. The solution in my case wasn't very intuitive but worked nonetheless. Here's what might help you too:
Make sure the USB port you're using to connect the arduino isn't shared with other devices (for example using a USB multipoint hub). If you're using a desktop with multiple USB ports (usually found at the back of the desktop case), unplug all other USB devices (keyboard, mouse etc) and reconnect them to a different USB. Use the fastest USB port available available on your computer (USB 3.0 if present) and have it dedicated for communication with the arduino. The reason the communication port goes unresponsive sometimes is because of the momentary fluctuations in the voltage and/or current if you have several devices connected to it.
Make sure you have a stable power supply for you computer, voltage drifts due to heavy loading can sometimes cause PC peripherals to disconnect/reconnect.
If this doesn't work, try this quick software fix. Just before the delay(30000) statement in your code, add the following:
if(!Serial) { //check if Serial is available... if not,
Serial.end(); // close serial port
delay(100); //wait 100 millis
Serial.begin(9600); // reenable serial again
}
This might at least ensure continued operation operation of your application with out requiring your intervention.
So in my case the problem was solved by connecting my computer through proper surge supressor, formerly i had connectected it to wall with a simple cable, and I have old 2 wire, non-grounded, electric installation in my flat.