Serial communication on STM32F303 using HAL - Rx not working - serial-port

I am using an STM32F303RE Nucleo board connected to my own PCB to do RS-232 serial communications, and I can't figure out why this code doesn't work in certain circumstances.
I'm using HAL functions (HAL_UART_Transmit and HAL_UART_Receive) for my communications, using the USB connector on the Nucleo for usart2 and a 9-pin RS-232 serial port on my own PCB for usart1. Both usart configurations have been set up by HAL.
When I communicate (using a Putty terminal) using only the USB connection (usart2), the code works perfectly. When I use usart1 for Tx and usart2 for Rx, still no problems. When I use usart2 for Tx and usart1 for Rx, it also works fine.
The problem is when I try to use usart1 (which is my RS-232 cable) for both Tx and Rx. My processor transmits the initial data fine, but when it's time to receive the data, nothing makes it into the received data register. I have some code to simply echo back any received data on the transmit line, and nothing comes through in this configuration. Once again - the code works fine in every other configuration of usart1 and usart2 for both sending and receiving, but no Rx when I try to do it all on usart1 (RS-232)
Here is the relevant section of code I'm using. COMTYPE is set to either &huart1 or &huart2 (in the problem case, it's set to &huart1)
Main loop (received data used for switch statement in menu system):
HAL_UART_Transmit(COMTYPE, prompt, sizeof(prompt), TIMEOUT);
cmd_size = UART_getstr(command);
cmd_num = parse_menu_input(command, cmd_size);
converted = (uint8_t)cmd_num + '0';
// error parsing command for menu selection
if(cmd_num == -1){
HAL_UART_Transmit(COMTYPE, parse_error, sizeof(parse_error), TIMEOUT);
}
else{
menu_switch(cmd_num);
}
}
Function containing Rx function and echo back (Tx) function:
int UART_getstr(uint8_t* command){
int x = 0; // tracker for buffer pointer
int chars = 0;
uint8_t buffer; // single char storage for UART receive
while(1){
// get single char from UART_Receive
HAL_UART_Receive(COMTYPE, &buffer, 1, HAL_MAX_DELAY);
// echo back function
HAL_UART_Transmit(COMTYPE, &buffer, sizeof(char), TIMEOUT);
// write value of received char to "command" array
command[x] = buffer;
// increment the number of valid chars
chars++;
// stop adding chars to command after [Enter] pressed
if(command[x] == '\r'){
chars--;
break;
}
// correct for storing DELETE as char in buffer
if(command[x] == 0x7F){
command -= 1;
chars -= 2;
}
else{
x++;
}
}
command[x] = '\0';
// return length of command buffer
return chars; }
I don't understand why the exact same code would work in 3 out of 4 circumstances, but not the 4th. I've checked the serial cable, and the rest of the RS-232 hardware functions fine when being used ONLY for Tx or ONLY for Rx. But the Rx seems blocked by something when trying to use RS-232 for both.
EDIT: Adding UART initialization code (generated by HAL):
/* USART1 init function */
static void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
/* USART2 init function */
static void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}

Related

Two xbees ( Router At) connected to Xbee(coordinator)

I have been working on a project which involves xbees. My set-up is simply one Xbee ( coordinator Api mode ) connected to an Arduino as a master unit. This master unit recieves data from multiple Xbees ( slaves ) that are only powered up by a battery and reading data from there ADC pin17. ADC values are transmitted to the master xbee to display it on the serial terminal. The slaves Xbee are configured as ( Router AT mode ). I've bee doing this between two xbees only : 1 master and 1 slave. I have a code that reads the mac address of the sending Xbee and then displays the sent ADC value which is transmitted. All of that was ok until I added another slave, I really need help since I can't associate each mac address with the right ADC value. Neither my code is capable of reading from both alternatively; at some point it stops reading from a one. If any advice on how to recognize data coming from multiple xbees on the same network, I will be grateful.
Here's my code :
#include <XBee.h>
#include <SoftwareSerial.h>
SoftwareSerial myserial(5,6);
float distance;
uint8_t myaddress[10];
XBee xbee = XBee();
uint8_t shCmd[] = {'S','H'};
uint8_t slCmd[] = {'S','L'};
AtCommandRequest atRequestSH = AtCommandRequest(shCmd);
AtCommandRequest atRequestSL = AtCommandRequest(slCmd);
AtCommandResponse atResponse = AtCommandResponse();
void getMyAddress(){
xbee.send(atRequestSL);
if(xbee.readPacket(5000)){
xbee.getResponse().getAtCommandResponse(atResponse);
if (atResponse.isOk()){
for(int i = 0; i < atResponse.getValueLength(); i++){
myaddress[i] = atResponse.getValue()[i];
}
}
}
delay(100);
}
void setup(){
Serial.begin(1200);
myserial.begin(1200);
xbee.begin(myserial);
}
void loop() {
getMyAddress();
for(int i=0; i < 10; i++) {
Serial.print(myaddress[i], HEX);
Serial.print(" ");
}
Serial.print("\n");
if (myserial.available() >= 21) { //
if (myserial.read() == 0x7E) {
for (int i = 1; i<19; i++) { // Skip ahead to the analog data
byte discardByte = myserial.read();
}
int analogMSB = myserial.read(); // Read the first analog byte data
int analogLSB = myserial.read(); // Read the second byte
int analogReading = analogLSB + (analogMSB * 256);
distance = ((analogReading *1.0) / 1023.0)* 3.3;
Serial.println(distance);
}
}
}
In the code where you're skipping data to get to the analog value, you'll find the MAC address of the device sending the data.
if (myserial.read() == 0x7E) {
for (int i = 1; i<19; i++) { // Skip ahead to the analog data
byte discardByte = myserial.read();
}
You should be taking a closer look at that data before processing it -- ensure that it's an I/O sample by looking at the frame type, check the frame length, check the checksum at the end of the frame, etc. The library you're using appears to have functions for processing AT commands and responses, perhaps it also has functions for the I/O Sample frame type.
This Digi support page explains I/O sampling and documents the various fields in the IO Data Sample Received frame (type 0x92).

Initializing Xbee S1 by an Arduino mini pro

I am trying to configurate my XBee module by an Arduino pro mini that is connected to my computer by de FTDI basic from sparkfun.
I already can write and send data from the Xbee to another Xbee module by the Arduino.
My problem is that I want to configure the Xbee by the arduino. I am sending ‘+++’ with the arduino to my Xbee and want to receive the ‘OK’ from the Xbee with the serial monitor from the arduino editor. The problem is that I can send it but never receive and ‘OK’, and when I am trying to configure the Xbee the configuration never happened. So I cant reach the Xbee command line.
uint8_t pinRx = 0, pinTx = 1; //Initialise pins on the Arduino
char GotChar;
long BaudRate = 4800;
int incomingByte=0;
SoftwareSerial mySerial( pinRx , pinTx ); //Initialise SoftwareSerial
void init_USB()
{
Serial.begin(BaudRate);
Serial.println("Start");
mySerial.begin(BaudRate);
}
void init_XBee()
{
Serial.begin(9600);
int check = 0;
while(T_XBEE_CONTROLLER_CheckOK() == 0)
{
Serial.println("CheckOK");
Serial.write("+++");
delay(2000);
}
Serial.println("ATCH 8\r");
delay(2000);
Serial.write("ATID 1234\r");
delay(2000);
Serial.write("+++");
delay(2000);
Serial.write("ATPL 0\r");
delay(2000);
Serial.write("+++");
delay(2000);
Serial.write("ATAP 2\r");
delay(2000);
}
int T_XBEE_CONTROLLER_CheckOK()
{
char ch[2];
ch[0] = 0x00;
while(! ((ch[0] == 'O' ) && (ch[1] == 'K') ))
{
ch[0] = mySerial.read();
ch[1] = mySerial.read();
if((ch[0] != 'O') && (ch[1] != 'K') && (ch[2] != '\r'))
{
Serial.println("FAILED");
return 0;
}
Serial.println("SUCCES");
return 1;
}
return 0;
}
it is a stupid answer but first of all, you should check that your Xbee is configured as AT device instead of API device. If it is API mode, the module wont understand the messages.
To do that you just have to use X-CTU application and read the configuration of the module, and change it to AT device.
Hope that helps.
Thanks for the response and the help, and also sorry for the late response.
I already solved the problem. The problem was the function write(). If you want to reach the command mode from the XBee you should only send "+++". If there is some kind of character behind the "+++" you can't reach the command line. The function write put a (for me) unknown character behing the "+++". So that's the problem for not reaching the command line.
To resolve this problem just use the function print("+++"). After using this function it is possible to reach the command line.
You have to read from the serial right after you send the +++ command, because this is where the xbee writes 'OK'. Also a better way to respect the guard times is to wait for a reply, and test to see if it is 'OK'.
Here is my code, I don't remember if it was working the last time I checked but I will just paste it here and you can modify it as you like. All it does is broadcast A1, B2, C3, etc.
There's a lot of commenting out where I was experimenting, but the regular comments are informative. Make sure you go through it step by step, it's quite simple when you get your head around it. Don't forget to change the destination address low to 0xFFFF if you want to broadcast.
In the end you'll come to the same realisation I did that AT mode is not suitable for configuring the xbee by writing programs.
For example I had an xbee constantly transmitting the number '2', and when another xbee was entering command mode using this code, it would receive the number 2 from the remote xbee when it should have received the 'OK' message from the local xbee, thus the program didn't acknowledge it being in command mode and breaking. When entering command mode you'd think an xbee would turn it's receiver off, but that's not the case so you can easily get into trouble.
If you want to do it the right way, have a look at API mode. I have series 1 xbee's so I'm implementing the Digimesh protocol, which so far I haven't seen anyone online do, but it's almost identical to the Zigbee so it's easy. If you'd like I can give you my code for that which can serve as a simple example.
/*
unicast_configure
Configure an XBee for unicast transmission and transmit
some characters to test
*/
#include <SoftwareSerial.h>
// Pins on Bees Shield:
SoftwareSerial xbee(2, 3); // TX, RX
boolean configured;
char c = 'A';
boolean configureRadio() {
// Set the data rate for the SoftwareSerial port:
xbee.begin(9600);
// Put the radio in command mode:
Serial.write("Entering command mode\r");
delay(1000);
while(xbee.available()>0) {xbee.read();}
xbee.write("+++");
while(xbee.available()>0) {xbee.read();}
//delay(1000);
//while(xbee.available() > 0) {Serial.write(xbee.read());}
String ok_response = "OK\r"; // The response we expect
// Read the text of the response into the response variable
// This satisfies the guard time by waiting for the OK message
String response = String("");
while (response.length() < ok_response.length()) {
if (xbee.available() > 0) {
response += (char) xbee.read();
}
}
Serial.println("response1: " + response);
// If we got received OK, configure the XBee and return true:
if (response.equals(ok_response)) {
Serial.println("Enter command mode successful");
// Restore to default values:
Serial.println("Restoring default values before making changes");
xbee.write("ATRE\r");
Serial.println("Setting addr high");
xbee.write("ATDH0\r"); // Destination high
//while(xbee.available() > 0) {Serial.write(xbee.read());}
Serial.println("Setting addr low");
xbee.write("ATDL1\r"); // Destination low-REPLACE THIS
//while(xbee.available() > 0) {Serial.write(xbee.read());}
Serial.println("Setting MY address");
xbee.write("ATMYFFFF\r");
// Apply changes:
Serial.println("Applying changes");
xbee.write("ATAC\r");
/*
///////////////////////////////////////////////
// Write to non-volatile memory:
// Use similar technique as above to satisfy guard time
Serial.write("Saving\r");
xbee.write("ATWR\r");
String response2 = String("");
//while (xbee.available() > 0) {Serial.write(xbee.read());}
while (response2.length() < ok_response.length()) {
if (xbee.available() > 0) {
response2 += (char) xbee.read();
}
}
Serial.println("response2: " + response2);
if (response2.equals(ok_response)) {
Serial.println("Save successful");
}
else { Serial.println("Save not successful");
return false;
}
// And reset module:
Serial.println("Resetting");
xbee.write("ATFR\r");
///////////////////////////////////////////////
*/
Serial.write("Exit command mode\r");
xbee.write("ATCN\r"); // Exit command mode
//while(xbee.available() > 0) {Serial.write(xbee.read());}
Serial.write("Finished\r");
return true;
} else {
return false; // This indicates the response was incorrect
}
}
void setup() {
Serial.begin(9600); // Begin serial
configured = configureRadio();
}
void loop() {
// Test transmission:
if (configured) {
xbee.print(c);
Serial.print(c);
c = c + 1;
if (c > 'Z') { c = 'A'; }
}
else {
Serial.println("Not configured (in loop)");
delay(5000);
Serial.println("Retrying configuration");
configured = configureRadio();
}
delay(1500);
}

Plug n' Play usb switch

I'm currently developing a hardware electronics application and I want to be able to easily toggle my circuit with a USB cable. All I want to do is have an arduino or other device that I can just plug into any computer, run a small application and toggle one wire to 5v. This would be extremely practical for lots of small applications.
Question:
-I want a small device that I can plug into any computer and toggle a 5v wire with a small application to control electronics. How do I do this?
If your MCU doesn't have USB frontend you can use assembler, eg. http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20%28AVR%29_eng.htm This allows to implement simple USB1.1 low-speed device. If you need high-speed your MCU should have USB engine built-in and then you probably find proper application note for USB from MCU's manufacturer.
Let's notice that depends on your device class you need or not to write your own driver. You can use HID, serial or CDCACM class. Finally you can just use FTDI's bridge chip http://www.ftdichip.com/
I've got some code for that over here. I use a simple transistor IRFU5305 where i attach one lead to a pin of the arduino and the other 2 bridge the power line of the usb.
Depending if you're using n or p channel transistor you may need to adjust the code.
ArduinoCode:
String inputString = ""; // a string to hold incoming data
boolean stringComplete = false; // whether the string is complete
void setup()
{
pinMode(8, OUTPUT);
Serial.begin(9600);
// reserve 20 bytes for the inputString (input is max 20 chars long)
inputString.reserve(20);
Serial.print("waitingforinput");
digitalWrite(8,true);
}
void loop()
{
if (stringComplete)
{
Serial.println(inputString);
inputString.trim();
if(inputString=="F8")
{
digitalWrite(8,true);
}
else if(inputString=="T8")
{
digitalWrite(8,false);
}
inputString = "";
stringComplete = false;
}
delay(500);
}
void serialEvent()
{
while (Serial.available())
{
Serial.println("inputreceived");
char inChar = (char)Serial.read();
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n')
{
stringComplete = true;
Serial.println(inputString);
}
}
}
Pythoncode:
import serial
import time
import os
ARDUINOPORT = os.getenv('ARDUINOPORT', None)
def send_string_to_arduino(cmd):
"""sends a certain command string to the arduino over Serial"""
print ARDUINOPORT
ser = serial.Serial()
ser.port = ARDUINOPORT
ser.baudrate = 9600
ser.parity = serial.PARITY_NONE
ser.bytesize = serial.EIGHTBITS
ser.stopbits = serial.STOPBITS_ONE
ser.timeout = 10
ser.xonxoff = False
ser.rtscts = False
ser.dsrdtr = False
ser.open()
time.sleep(2)
ser.readline()
ser.write(cmd+"\n")
ser.close()
def switch_pin_on(pinnumber):
"""switches the pin with pinnumber(int) of the connected Arduino on"""
cmd = "T"+str(pinnumber)
print cmd
send_string_to_arduino(cmd)
return
def switch_pin_off(pinnumber):
"""switches the pin with pinnumber(int) of the connected Arduino off"""
cmd = "F"+str(pinnumber)
print cmd
send_string_to_arduino(cmd)
return
def set_arduino_port(comport):
"""sets to which comport the arduino is connected to, comport should be a string ("COM2")"""
global ARDUINOPORT
ARDUINOPORT = comport
return
if __name__ == '__main__':
set_arduino_port("COM17")
switch_pin_off(8)
switch_pin_on(8)

Transmitting a single character over UART from pic16f887 to a PC terminal(Putty, Hyperterminal, etc..)

I am trying to transmit a character "a" from pic16f887 and see the result on the terminal, but all I get is a question mark(using USART terminal), or nothing at all(Putty, Hyperterminal). I am not so great with C, as I'm only a beginer, but I really need to get this working for my school project.. I have tried many codes I've found over the internet, and I did manage to receive a character from the terminal and, lets say, turn on a LED, but I just can't manage to make it send anything. And I have a strong feeling its somewhere in the code.. Im using MPLAB and Hi-Tech C compiler to build the project. Here it is:
unsigned char cUART_char;
unsigned char cUART_data_flg;
void init_uart(void);
void UART_putc(unsigned char c);
void InterruptHandlerLow ();
void main()
{
TRISA = 0;
PORTA = 0;
TRISB = 0;
PORTB = 0;
TRISD = 0;
PORTD = 0;
ANSELH = 0;
init_uart();
while (1)
{
if (cUART_data_flg==1)
{
UART_putc(cUART_char);
cUART_data_flg=0;
}
}
}
void InterruptHandlerLow ()
{
if (RCIF==1)//is interrupt occured by EUSART receive?,
//then RCREG is full we have new data (cleared when RCREG is read)
{
if(RCSTA&0x06) //more efficient way than following commented method to check for reception error
//if(RCSTAbits.FERR==1 || RCSTAbits.OERR==1 )
{
CREN=0; //Overrun error (can be cleared by clearing bit CREN)
cUART_char=RCREG; //clear Framing error
CREN=1;
}
else
{
cUART_char = RCREG; // read new data into variable
cUART_data_flg = 1; // new data received. so enable flg
}
}
}
void init_uart(void) // init UART module for 9600bps boud, start bit 1, stopbit 1, parity NONE
{
// init data receive flag to zero (no data)
TRISC7=1; //Make UART RX pin input
TRISC6=0; //Make UART TX pin output
SYNC = 0; // enables for asynchronous EUART
SPEN = 1; // enables EUSART and sets TX (RC6) as output; ANSEL must be cleared if shared with analog I/O
CREN = 1;
TX9 = 0; // 8bit mode
RX9 = 0;
TXEN = 1; // enables Transmitter
BRGH = 1; // baud rate select
BRG16 = 0;
SPBRG = 25; //baud rate select 9600#4Mhz
SPBRGH = 0;
RCIE=1; // receive interrupt enable
GIE=1; // global interrupt enable
PEIE=1 ; // Peripheral Interrupt Enable bit
}
void UART_putc(unsigned char c)
{
TXEN=0;// disable transmission
TXREG=0x61; // load txreg with data
TXEN=1; // enable transmission
while(TRMT==0) // wait here till transmit complete
{
}
}
Please if someone sees a problem (or more) in this code, help me to crack this ;)
Oh and I am transmitting when pressing a button connected to a TX pin (RC6)..

RS232 communication in MPlab

I am using MPlab to read data from a pic micro controller. I am using pic18F87J11.
The data that I want to read is on pin 3 of the DB9 of the RS232, and my RS232 is connected to the pic micro controller.
Can anyone help me or give me a simple sample code to do that??
Thank you,
//
// Designed by www.MCUExamples.com
// rasika0612#gmail.com
// Serial communications example. Echo data comes to serial port
// using serial receive interrupt.
//
#include <p18f4520.h>
#pragma config OSC = HS // 20MHz Crystal, (HS oscillator)
#pragma config PBADEN = OFF // PORTB<4:0> pins are configured as digital I/O on Reset)
#pragma config WDT = OFF // watch dog timer off
#pragma config LVP = OFF // Low voltage program off
unsigned char cUART_char;
unsigned char cUART_data_flg;
void init_uart(void);
void UART_putc(unsigned char c);
void InterruptHandlerLow ();
void main()
{
init_uart(); // init UART module
while (1) // infinite loop which handles ncoming data as they arrive
{
if (cUART_data_flg==1)// if new data available, send it back through USART tx line (echo it)
{
UART_putc(cUART_char);
cUART_data_flg=0; // clear new data flag so one charactor will echoed once
}
}
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#pragma code InterruptVectorLow = 0x18
void InterruptVectorLow (void)
{
_asm
goto InterruptHandlerLow //jump to interrupt routine
_endasm
}
//----------------------------------------------------------------------------
// Low priority interrupt routine
#pragma code
#pragma interrupt InterruptHandlerLow
void InterruptHandlerLow ()
{
if (PIR1bits.RCIF==1)//is interrupt occured by EUSART receive?,
//then RCREG is full we have new data (cleared when RCREG is read)
{
if(RCSTA&0x06) //more efficient way than following commented method to check for reception error
//if(RCSTAbits.FERR==1 || RCSTAbits.OERR==1 )
{
RCSTAbits.CREN=0; //Overrun error (can be cleared by clearing bit CREN)
cUART_char=RCREG; //clear Framing error
RCSTAbits.CREN=1;
}
else
{
cUART_char = RCREG; // read new data into variable
cUART_data_flg = 1; // new data received. so enable flg
}
}
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
void init_uart(void) // init UART module for 9600bps boud, start bit 1, stopbit 1, parity NONE
{
cUART_data_flg=0; // init data receive flag to zero (no data)
TRISCbits.TRISC7=1; //Make UART RX pin input
TRISCbits.TRISC6=0; //Make UART TX pin output
SPBRGH = 0x02; //9600bps 20MHz Osc
SPBRG = 0x08;
RCSTAbits.CREN=1; //1 = Enables receiver
RCSTAbits.SPEN=1; //1 = Serial port enabled (configures RX/DT and TX/CK pins as serial port pins)
BAUDCONbits.BRG16=1;//1 = 16-bit Baud Rate Generator – SPBRGH and SPBRG
TXSTAbits.SYNC=0; //0 = Asynchronous mode
TXSTAbits.BRGH=1; //1 = High speed
TXSTAbits.TXEN=1; //1 = Transmit enabled
RCONbits.IPEN = 1; //enable Interrupt priority levels
IPR1bits.RCIP=0; // EUSART Receive Interrupt Priority 0 = Low priority
PIE1bits.RCIE=1; // 1 = Enables the EUSART receive interrupt
INTCONbits.GIEL = 1;//enable interrupts
INTCONbits.GIEH = 1;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
void UART_putc(unsigned char c)
{
TXSTAbits.TXEN=0;// disable transmission
TXREG=c; // load txreg with data
TXSTAbits.TXEN=1; // enable transmission
while(TXSTAbits.TRMT==0) // wait here till transmit complete
{
Nop();
}
}

Resources