I have two arduinos, each coupled with an arduino wireless shield and an xbee on top of it.
The communication is not working as expected. I can receive and send bytes, but the connection between the modules is often interrupted, so the serial buffer is growing quite a lot.
Furthermore, if I move the modules more than 1 meter away from each other, the connection is refused completely.
I was wondering, if my xbee modules might be a kind of broken or I maybe misconfigured them.
Any ideas?
The source code of the sender:
void setup()
{
Serial.begin(9600);
}
void loop()
{
int sensorValue = analogRead(0);
int val = map(sensorValue, 0, 1023, 35, 160);
Serial.write(char(val));
delay(250);
}
The source code of the receiver:
#include <Servo.h>
Servo motor1;
Servo motor2;
Servo motor3;
Servo motor4;
void setup()
{
motor1.attach(9);
motor2.attach(10);
motor3.attach(3);
motor4.attach(11);
Serial.begin(9600);
}
void loop()
{
if(Serial.available() > 0)
{
byte incoming = Serial.read();
int inValue = constrain(incoming, 35, 160);
motor1.write(inValue);
motor2.write(inValue);
motor3.write(inValue);
motor4.write(inValue);
}
delay(250);
}
A few things to consider:
Make sure the radios haven't formed a network on channel 26 (0x1A). The XBee module has to run with lower power on that channel, so I usually set ATSC to 0x7FFF to exclude channel 26.
That model of XBee uses a PCB antenna, located in the tapered part of the module. Make sure that doesn't have anything metallic above or below it (ground plane, components, wires) and that you aren't putting it in a big metal enclosure that would limit the signal.
Check the value of ATRO, the Packetization Timeout. You'll want it set to a low value (3-5) or even 0 or 1 if you want the XBee to transmit characters as they come in, instead of waiting for more data to possibly group together in a single packet.
If you're having range issues, check the ATPL (Power Level) and ATPM (Power Mode) settings. Enabling Boost Mode (ATPM=1) and highest power level (ATPL=4) could help with the range issue.
You might want to change your receive code to poll more often for bytes, or to even ignore multiple bytes and only use the last value received. This will prevent a backlog of bytes on the receiving end.
Process any outstanding bytes:
while (Serial.available() > 0)
{
byte incoming = Serial.read();
int inValue = constrain(incoming, 35, 160);
motor1.write(inValue);
motor2.write(inValue);
motor3.write(inValue);
motor4.write(inValue);
}
Ignore buffered bytes and only write the last value:
if (Serial.available() > 0)
{
byte incoming;
// read all bytes but only use the last value read
while (Serial.available() > 0) incoming = Serial.read();
int inValue = constrain(incoming, 35, 160);
motor1.write(inValue);
motor2.write(inValue);
motor3.write(inValue);
motor4.write(inValue);
}
Related
I am a novice to Arduino. I came across an article on rs 485 and currently trying to implement the same between 2 arduino unos. I copied code from internet which is pretty simple but I am unable to make communication work properly. Here is the code for master arduino with explanation of what I am trying to do.
**Master Arduino Code**
/* master will send a message I1LF where I shows start of master message by master.
* 1 shows the slave device No. from whom data is to be fetched and L
* shows that master wants to read slave's sensor data
* and F indicates finish of message by master.
* slave will respond by sending Serial.println(i1) where i is slave no and 1 is to let master know that
* correct slave is sending data. then slave would send sensor_value and then f indicates end of slave message.
* master will display data read from rs 485 bus.
*/
#include<LiquidCrystal.h> //Library for LCD display
//function
LiquidCrystal lcd(4, 5, 6, 7, 8, 9);
const int Enable = 2;
int value1=0;
void setup()
{
Serial.begin(9600);
pinMode(Enable, OUTPUT);
digitalWrite(Enable, HIGH); // put master arduino into transmission mode.
lcd.begin(16,2);
lcd.clear();
}
void loop()
{
Serial.print('I'); // I indicates master has started communication.
Serial.print('1'); // this is the address of slave from whom data is to be fetched.
Serial.print('L'); // this means master wants to read sensor data.
Serial.print('F'); // this means end of message.
Serial.flush(); // wiat untill all data has been pushed to the serial.
digitalWrite(Enable, LOW); // put master into receiving mode.
if(Serial.find('i')) // i will be sent (to indicate start of slave
//message , by the slave that was prompted by
//master.
{
int slave = Serial.parseInt(); // check which slave is sending
//data.
value1 = Serial.parseInt();
if(Serial.read() == 'f' && slave == 1) // f indicates end of message
//sent by slave and 1 is the
//address of the slave sent by
// the slave so that master can
//recognize which slave is this.
{
lcd.setCursor(0,0);
lcd.print("Slave : ");
lcd.setCursor(11,0);
lcd.print(value1);
}
}
digitalWrite(Enable, HIGH);
delay(300);
}
This is the slave arduino code
#include<LiquidCrystal.h>
LiquidCrystal lcd(4, 5, 6, 7, 8, 9);
const int Enable = 2;
const int SlaveNumber = 1;
void setup()
{
Serial.begin(9600);
pinMode(Enable, OUTPUT);
digitalWrite(Enable, LOW); // initially put slave in receiving mode
pinMode(A0, INPUT);
lcd.begin(16,2);
lcd.clear();
}
void loop()
{
if(Serial.available())
{
if(Serial.read()=='I') // all slaves will detect I on rs 485 bus which //means master has started commmunication.
{
int Slave = Serial.parseInt(); // read next character on rs 485 bus
//which would definitely be a digit
//indicating slave no to whom master
//wishes to communicate.
if(Slave == SlaveNumber) // check if master wants to commnucate
//with you.
{
char command = Serial.read(); // read next character in
//serial buffer which would be
//command L
delay(100);
if(command == 'L')
{
if(Serial.read()=='F') // if master's message has
//finished.
{
int AnalogValue = analogRead(0); // read sensor
digitalWrite(Enable, HIGH); // put slave in
//transmission mode.
Serial.print("i"); // i indicates start of
//slave message
Serial.println(SlaveNumber); // send slave no so that
//master can identify which
//slave he is receiving
//data from.
Serial.print(AnalogValue);
Serial.print("f"); // indicates end of message by the
//slave.
Serial.flush();
digitalWrite(Enable, LOW); // put slave in
//listening ( receivig ) mode
}
}
}
}
}
}
This is screen shot of proteous simulation showing Master unable to read slave1's sensor data
enter image description here
I assessed that problem arose because of master and slave both being in transmission mode so I attached a not gate between master's enable pin and slave's enable pin and then master is working fine. but practically attaching a not gate wont be possible. that's why I want to know how to ensure that enable of both master and slave is not high simultaneously. I have tried a couple of strategies and introduced delays at different locations in the code but nothing seems to work. by hit and trial it starts to work sometimes but I want to know the correct way of doing so.
This is screen shot of proteous simulation which shows master reading correctly slave1 data only after I attach a not gate between master Enable pin and Slave's Enable pin.
Code for both master and slave and circuit is exactly the same as before. only a not gate has been used between master's enable pin and slave's enable pin.
enter image description here
I tried another library madleech/Auto485 but that i also showing the same problem. have tried a couple of times adding delays at different locations in master code but to no use. i know problem is because of enable pins of both MAX 485 modules connected to 2 arduinos going high simultaneously but i am unable to figure out how to address this issue.
You need to wait for each byte to be available before reading the serial port.
In your code:
if(Serial.available()) // you wait
{
if(Serial.read()=='I') // all slaves will detect I on rs 485 bus which //means master has started commmunication.
{
// parseInt() does wait for a byte to be availeble, so that works...
int Slave = Serial.parseInt();bus
if(Slave == SlaveNumber)
{
// Here serial.read() will most likely return -1, since it is very
// unlikely that a byte is already available at this point.
char command = Serial.read();
// ...
You should wait for the serial port to have received bytes before reading them.
You can try inserting a loop before calling read(), as in:
while (!Serial.available()) {} // wait for something to read
char byteRead = Serial.read();
This blocking code should help fix the code as you have it now. You should probably explore non-blocking ways of reading serial commands, such as using some sort of finite state machine algorithm. As a rule of thumb, embedded software should avoid blocking.
I am trying to retrieve data from an RLS absolute rotary encoder via SPI through Arduino Uno. I have managed to learn the basics of SPI, but I can't seem to get this working. I keep printing the transfer data and keep getting 255.
I also use the recommended pins for Arduino Uno here: https://www.arduino.cc/en/reference/SPI
Here is the link to the Absolute Encoder DataSheet: https://resources.renishaw.com/en/details/data-sheet-orbis-true-absolute-rotary-encoder--97180
Any help is appreciated.
Here is my code I have been trying:
#include <SPI.h>
unsigned int data;
int CS = 10; //Slave Select Pin
// The SS pin starts communication when pulled low and stops when high
void setup() {
Serial.begin(9600);
RTC_init();
}
int RTC_init() {
pinMode(CS, OUTPUT);
SPI.begin();
SPI.setBitOrder(LSBFIRST); // Sets Bit order according to data sheet (LSBFIRST)
SPI.setDataMode(SPI_MODE2); // 2 or 3, Not sure (I have tried both)
digitalWrite(CS, LOW); // Start communications
/*
Commands List:
Command "1" (0x31) – position request (total: 3 bytes) + 4 for multi-turn
Command "3" (0x33) – short position request (total: 2 bytes) + 4 for multi-turn
Command "d" (0x64) – position request + detailed status (total: 4 bytes) + 4 for multi-turn
Command "t" (0x74) – position request + temperature (total: 5 bytes) + 4 for multi-turn
Command "v" (0x76) – serial number (total: 7 bytes)
*/
unsigned int data = SPI.transfer(0x33); // Data
digitalWrite(CS, HIGH); // End communications
return(data);
}
void loop() {
Serial.println(RTC_init());
}
First, you forgot to set your CS pin to output. That won't help.
void setup()
{
Serial.begin(9600);
digitalWrite(CS, HIGH); // set CS pin HIGH
pinMode(CS, OUTPUT); // then enable output.
}
SPI is a two way master/slave synchronous link, with the clock being driven by bytes being sent out by the master. This means that when transacting on SPI, you are expected to send out as many bytes as you want to receive.
As shown on the timing diagram on page 14 of the datasheet, you are expected to send one byte with the command, then as many null bytes as the response requires minus 1.
The diagram shows the clock being low at idle, and input bits being stable when the clock goes low, that's SPI mode 1.
To read the position, for a non-multiturn encoder.
unsigned int readEncoderPos()
{
// this initialization could be moved to setup(), if you do not use
// the SPI to communicate with another peripheral.
// Setting speed to 1MHz, but the encoder can probably do better
// than that. When having communication issues, start slow, then set
// final speed when everything works.
SPI.beginTransaction(SPISettings(1'000'000, MSBFIRST, SPI_MODE1));
digitalWrite(CS, LOW);
// wait at least 2.5us, as per datasheet.
delayMicroseconds(3);
unsigned int reading = SPI.transfer16(0x3300); // 0x3300, since we're sending MSB first.
digitalWrite(CS, HIGH);
// not needed if you moved SPI.beginTransaction() to setup.
SPI.endTransaction();
// shift out the 2 status bits
return reading >> 2;
}
I plan to have several Arduino boards connected to XBee series 2 radios in the same network performing the same operation. They are to transmit data to another board that will upload all of the data at once using a cellular connection. I would like to uniquely identify each board in some way. I realize I can hardcode a serial number into the EEPROM memory of the Arduino board. However that will not scale very well for what I am trying to do. Is there a way to read the XBee's serial number using Arduino code, so that I can transmit it along with my data?
string serialnumber
volatile int IRQcount1;
volatile int IRQcount2;
int pin2 = 2;
int pin3 = 3;
int pin_irq1 = 0; //IRQ that matches to pin 2
int pin_irq2 = 1; //IRQ that matches to pin 3
void setup() {
Serial.begin (9600);
}
void IRQcounter1() {
IRQcount1++;
}
void IRQcounter2() {
IRQcount2++;
}
// I would like some function to get the serial number here
void get_xbee_serial() {
}
void loop() {
attachInterrupt(pin_irq1, IRQcounter1, RISING);
attachInterrupt(pin_irq2, IRQcounter2, RISING);
delay(25);
detachInterrupt(pin2);
detachInterrupt(pin3);
Serial.print(F("Xbee Serial Number = "));
Serial.print(serialnumber);
Serial.print(F(" Counter 1 = "));
Serial.print(IRQcount1);
Serial.print(F(" Counter 2 = "));
Serial.println(IRQcount2);
}
You can retrieve the serial number using the AT commands ATSH and ATSL (serial number high/low). You can do that by going into command mode, sending those sequences followed by a return, and parsing the responses.
To get into command mode, you need to wait 1 second without sending anything, send the escape sequence +++, and then wait another second. The XBee module should respond with OK\r indicating that it's ready to receive commands.
Send ATSH\r and you should get a hex string representing the top four bytes of the serial number. Repeat with ATSL\r for the bottom four bytes.
And know that if you use a destination address of 0, the XBee module will automatically send data to the coordinator on your network. If the coordinator is running in API mode, it can retrieve the sender's 64-bit MAC address from the frame header of the received data.
I have this RFID reader "Rosslare AY-X12", and it's working with Wiegand 26bit. I have an arduino mini Pro and connected together it's working fine but it only reads the card one time and then I have nothing.
When I put on the card arduino reads that card but only one time during the card is near by the reader and it again reads that card when I put off the card and then I put on. But I want to read that card continuously, I mean when the card is near by the Reader still reading the card, every 1ms reads that card.
Do you have any idea how to do that ? Is there any RFID arduino library which can do that? I had got the Mifare and its can do that. But this 125Khz reader which can communicate over Wiegand can't do that or I don't know how to do that.
I'm using this library : https://github.com/monkeyboard/Wiegand-Protocol-Library-for-Arduino
My previous answer was deleted. I am going to make another attempt to answer the questions.
Do you have any idea how to do that ?
This cannot be done by Arduino because Arduino in your case is just reading the D0 and D1 pulses from your RFID reader. Since your RFID reader Rosslare AY-X12 does not send out continuous output of wiegand protocol, there is no way Arduino can read more than what was not sent to it.
The common RFID readers will not send continuous data of the same card because in the common use case (entry/exit/attendance), normally one tap is to check-in and another tap is to check-out. If the RFID reader sends continuous data of the same card, the main system receiving the multiple wiegand data will be confused and will not be able to determine if the user actually wish to check-in or check-out.
Is there any RFID arduino library which can do that?
No. There is no such RFID Arduino library. If the RFID reader is not sending out continuous data, there is no way the receiver (Arduino) can receive them.
Is there a way to achieve this?
Yes, there are some readers that has the option to turn on the continuous output of data, for example 714-52 Mifare® ID Reader with selectable outputs. In its specification :
Continuous output with tag in field or single transmission
With this reader configured to continuous output, you can then use Arduino and the monkeyboard wiegand library to read the data.
I wrote my own wiegand code. Its not that difficult. I attached interrupts to the data pins and when they change I log the zero or one. You then build up the binary string and once timed out because no bits coming in. Then you convert the binary to decimal.
#include <LiquidCrystal.h>
int data0 = 2; //set wiegand data 0 pin
int data1 = 3; //set wiegand data 1 pin
unsigned long bit_holder; //unsigned long (positive 32 bit number)
unsigned long oldbit = 0;
volatile int bit_count = 0;
LiquidCrystal lcd(8, 9, 10, 11, 12, 13);
unsigned long badge;
unsigned int timeout;
unsigned int t = 800;
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
lcd.print("Present Badge");
delay(2);
Serial.println("Present Badge");
pinMode(data0, INPUT);
digitalWrite(data0, HIGH);
pinMode(data1, INPUT);
digitalWrite(data1, HIGH);
attachInterrupt(0, zero, FALLING); //attach interrupts and assign functions
attachInterrupt(1, one, FALLING);
}
void zero(){
bit_count ++;
bit_holder = (bit_holder << 1) + 0; //shift left one and add a 0
timeout = t;
}
void one(){
bit_count ++;
bit_holder = (bit_holder << 1) + 1; //shift left one and add a 1
timeout = t;
}
void loop() {
timeout --;
if (timeout == 0 && bit_count > 0){
lcd.clear();
lcd.print("Dec:");
lcd.print(bit_holder);
lcd.setCursor(0,1);
lcd.print("Hex:");
lcd.print(String(bit_holder,HEX));
Serial.print("bit count= ");
Serial.println(bit_count);
Serial.print("bits= ");
Serial.println(bit_holder,BIN);
oldbit = bit_holder; //store previous this value as previous
bit_count = 0; //reset bit count
bit_holder = 0; //reset badge number
}
}
You may need to find a reader that offer a continuously reading, as I know almost of Wiegand Reader in the market can't perform a continuously reading because they have a "onboard" control that controls this...
Maybe you can try with Arduino Serial RFID Reader...
try a this timer libary Timer1 and mayby try this code it worked for me, my tags and cards now reads continuously.
Greetings from Denmark
Gregor
#include <Timer1.h>
//******************************************************************
// ATmega168, ATmega328:
// - Using Timer 1 disables PWM (analogWrite) on pins 9 and 10
// ATmega2560:
// - Using Timer 1 disables PWM (analogWrite) on pins 11 and 12
// - Using Timer 3 disables PWM (analogWrite) on pins 2, 3 and 5
// - Using Timer 4 disables PWM (analogWrite) on pins 6, 7 and 8
// - Using Timer 5 disables PWM (analogWrite) on pins 44, 45 and 46
//******************************************************************
unsigned int lastTime;
#include <SoftwareSerial.h>
SoftwareSerial RFID = SoftwareSerial(2,4);
char character;
String our_id;
void setup()
{
// Disable Arduino's default millisecond counter (from now on, millis(), micros(),
// delay() and delayMicroseconds() will not work)
disableMillis();
// Prepare Timer1 to count
// On 16 MHz Arduino boards, this function has a resolution of 4us
// On 8 MHz Arduino boards, this function has a resolution of 8us
startCountingTimer1();
lastTime = readTimer1();
Serial.begin(9600);
RFID.begin(9600);
}
void loop()
{
unsigned int now = readTimer1();
while (RFID.available()>0)
{
character = RFID.read();
our_id += character;
lastTime = now;
}
if (our_id.length() > 10) {
our_id = our_id.substring(1,13);
Serial.println(our_id);
our_id = "";
}
delay(1000);
}
I intend to read the data received by the xbee in an interrupt handler.
But as the handler can not use delays, I can not use readPacket (100).
I have the following code:
#include <XBee.h>
#include <avr/power.h>
#include <avr/sleep.h>
XBee xbee = XBee();
XBeeResponse response = XBeeResponse();
ZBRxResponse rx = ZBRxResponse();
int size;
uint8_t buffer[256];
void setup() {
Serial.begin(9600);
Serial1.begin(9600);
xbee.begin(Serial1);
attachInterrupt(0, wake_up_now, LOW );
}
void wake_up_now() {
xbee.readPacket();
if(xbee.getResponse().isAvailable()){
if (xbee.getResponse().getApiId() == ZB_RX_RESPONSE) {
xbee.getResponse().getZBRxResponse(rx);
size = rx.getDataLength();
for (int i = 0; i < size; i++)
buffer[i] = rx.getData(i);
}
}
}
void sleepNow() {
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_enable();
power_adc_disable();
power_spi_disable();
power_timer0_disable();
power_timer1_disable();
power_timer2_disable();
power_twi_disable();
sleep_mode();
sleep_disable();
power_all_enable();
}
void loop() {
Serial.print("Awake");
Serial.println(size);
for (int i = 0; i < size; i++)
Serial.println(buffer[i]);
Serial.println("Entering Sleep mode");
delay(100);
sleepNow();
}
If you receive data the first time I can not read this data.
But later, when more data is received the data that was sent in the first message is read.
I really need to read the data in the handler, how can I solve this?
When I designed this ANSI C XBee Host library, I thought I could include frame processing as part of the serial interrupt handler on the Freescale HCS08 platform. I found that it just didn't work well, especially at a baud rate of 115,200.
The final design I went with was to keep a buffer of bytes from the serial port, and parse/dispatch frames in a "tick" function called in my main event loop. In one application, I was calling the "tick" function at least once every 50ms (IIRC).
As for forcing the XBee module to buffer serial data while you're sleeping, I think you'll have a hard time with that. You'd need to deassert RTS, but then wait to see if the XBee was still sending you a byte. My recollection is that I would still get multiple bytes (3 or 4?) after deasserting RTS. You'll also have to handle the condition of getting a partial packet while you're awake, and needing to decide whether you'll receive the whole frame then, or the next time you wake up.
You'd probably be better off using the XBee module's SPI interface, since the host controls when bytes are sent, and it might even be possible to have the XBee trigger a hardware interrupt on the host when it has bytes to send. You can also use high speeds (460kbps and up, I believe) to get the bytes quickly.