1

I'm having timer collision problems with using Servo.h and SoftwareSerial.h on Arduino Nano board. And now I need 2 pairs of Serial pins by using NFC Module and Arduino's Serial Monitor on my laptop.

If the information I got is not wrong, there are three timers (timer0, timer1, timer2) available in Nano board. As I heard timer1 is 16bit timer, and both Servo.h and SoftwareSerial.h use that timer1 at the same time on Nano board that's why they can't avoid timer collision issue.

Yet I need to use both header files without timer collision. In this case, what should I do? Do I have to modify Servo.h file for not using timer1?

Because all I do with my Servo Motor is controlling angular position.

Therefore, using 16bit-timer is of no use in this project I'm proceeding unless I use PWM control.

So, at this point, I want to use timer0 or timer2 (both are 8 bit-timer) instead of using timer1. If not, the timer1 from both header files of Servo and Software will be collide. Following is the source code I use.

const unsigned char wake[24]={
  0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xfd, 0xd4, 0x14, 0x01, 0x17, 0x00};//wake up NFC module
const unsigned char firmware[9]={
  0x00, 0x00, 0xFF, 0x02, 0xFE, 0xD4, 0x02, 0x2A, 0x00};//
const unsigned char tag[11]={
  0x00, 0x00, 0xFF, 0x04, 0xFC, 0xD4, 0x4A, 0x01, 0x00, 0xE1, 0x00};//detecting tag command
const unsigned char std_ACK[25] = {
  0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x0C, 
0xF4, 0xD5, 0x4B, 0x01, 0x01, 0x00, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x00};
unsigned char old_id[5];

unsigned char receive_ACK[25];//Command receiving buffer
//int inByte = 0;               //incoming serial byte buffer

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#define print1Byte(args) mySerial.write(args)
#define print1lnByte(args)  mySerial.write(args),mySerial.println()
#else
#include "WProgram.h"
#define print1Byte(args) mySerial.print(args,BYTE)
#define print1lnByte(args)  mySerial.println(args,BYTE)
#endif

#include <Servo.h>
#include <NeoSWSerial.h>

NeoSWSerial mySerial(5,6);

volatile uint32_t newlines = 0UL;

Servo sv;

int pos1=0; //initial value = 93 degree
int pos2=180;
int sw1 = 4;

static void handleRxChar( uint8_t c )
    {
      if (c == '\n')
        newlines++;
    }

void setup(){
  mySerial.attachInterrupt( handleRxChar );
  pinMode(sw1, INPUT_PULLUP);
  sv.attach(9);
  Serial.begin(9600);  // open serial with PC
  mySerial.begin(9600);  //open serial1 with device
  //Serial2.begin(115200);
  wake_card();
  delay(100);
  read_ACK(15);
  delay(100);
  display(15);
}

void loop(){
  send_tag(); 
  read_ACK(25);
  delay(100);
  if (!cmp_id ()) {   //nfc tag
    if (test_ACK ()) {
      display (25);
      sv.write(pos1);
      delay(2500);
      sv.write(pos2);
    }
  }
  else if (cmp_id()){   // switch
    if(digitalRead(sw1) == LOW){
      sv.write(pos1);   // waits 15ms for the servo to reach the position
      }
    else if(digitalRead(sw1) == HIGH){
      sv.write(pos2);
    }
  }
  copy_id ();
}

void copy_id (void) {//save old id
  int ai, oi;
  for (oi=0, ai=19; oi<5; oi++,ai++) {
    old_id[oi] = receive_ACK[ai];
  }
}

char cmp_id (void){//return true if find id is old
  int ai, oi;
  for (oi=0,ai=19; oi<5; oi++,ai++) {
    if (old_id[oi] != receive_ACK[ai])
      return 0;
  }
  return 1;
}

int test_ACK (void) {// return true if receive_ACK accord with std_ACK
  int i;
  for (i=0; i<19; i++) {
    if (receive_ACK[i] != std_ACK[i])
      return 0;
  }
  return 1;
}

void send_id (void) {//send id to PC
  int i;
  Serial.print ("ID: ");
  for (i=19; i<= 23; i++) {
    Serial.print (receive_ACK[i], HEX);
    Serial.print (" ");
  }
  Serial.println ();
}

void UART1_Send_Byte(unsigned char command_data){//send byte to device
  print1Byte(command_data);
#if defined(ARDUINO) && ARDUINO >= 100
  mySerial.flush();// complete the transmission of outgoing serial data 
#endif
} 

void UART_Send_Byte(unsigned char command_data){//send byte to PC
  Serial.print(command_data,HEX);
  Serial.print(" ");
} 

void read_ACK(unsigned char temp){//read ACK into reveive_ACK[]
  unsigned char i;
  for(i=0;i<temp;i++) {
    receive_ACK[i]= mySerial.read();
  }
}

void wake_card(void){//send wake[] to device
  unsigned char i;
  for(i=0;i<24;i++) //send command
    UART1_Send_Byte(wake[i]);
}

void firmware_version(void){//send fireware[] to device
  unsigned char i;
  for(i=0;i<9;i++) //send command
    UART1_Send_Byte(firmware[i]);
}

void send_tag(void){//send tag[] to device
  unsigned char i;
  for(i=0;i<11;i++) //send command
    UART1_Send_Byte(tag[i]);
}

void display(unsigned char tem){//send receive_ACK[] to PC
  unsigned char i;
  for(i=0;i<tem;i++) //send command
    UART_Send_Byte(receive_ACK[i]);
  Serial.println();
}

Summary

I am having timer collision issue with using Servo.h and SoftwareSerial.h.

they both share timer1 at the same time. To avoid this collision issue and make these two work fine, what should I do? Should I do something with the source code like by adding up few lines of code or modify those header files?

David Kim
  • 23
  • 1
  • 6

1 Answers1

2

Normally, I would have suggested AltSoftSerial as the alternative to SoftwareSerial (read more here), but it also conflicts with the Servo library's TIMER1 use. It can only be used on two specific pins.

I think my NeoSWSerial would do the trick. It re-uses the micros() clock (TIMER0) and Pin Change interrupts to implement a software serial port. This limits it to bauds rates 9600, 19200 and 38400, but it is much more efficient than SoftwareSerial. It can be used on any two pins.


Update

I would not suggest using a software serial port at 115200, as it can be unreliable above 38400. You might be able to send a baud rate configuration command to the NFC module to set it to a lower rate.

BTW, if you are sending information (not just receiving), all software serial port libraries disable interrupts during transmission, except AltSoftSerial... which you can't use. Just be aware of that, because it may affect your Servo when you transmit on NeoSWSerial.

Also, be sure you are using one of the PWM pins for the servo. If the Servo library is creating the PWM signal with software (just like a software serial port), the CPU won't have time for much else.

It might be better to put the NFC module on the hardware serial port, Serial. For debug prints, use NeoSWSerial connected to a TTL Serial-to-USB converter. Then open the Serial Monitor on that converter's COM port. Remove the debug later, because transmitting disables interrupts.

There are other boards that have additional UARTS. For example, an Arduino Leo (ATMega32U4 MCU) has an extra serial port, Serial1, that you could use for the NFC. Serial would still be available for debug prints.

slash-dev
  • 1,569
  • 2
  • 9
  • 9
  • Is your NeoSWSerial's 'micros()' only available at baudsrate 9600,19200 and 38400? I'm not complaining but i was thinking of using it on communicating between my arduino board and NFC Module which needs baudsrate of 115200. – David Kim May 10 '17 at 01:40
  • @DavidKim - Yes, only those baud rates. More info in update above. – slash-dev May 10 '17 at 14:47
  • thank you. I'll try my project with your NeoSWSerial library. – David Kim May 11 '17 at 06:08
  • I've tried this for hours but it doesn't work..i don't know what the problem is but are there any specific pins on nano for your NeoSWSerial? I changed baudsrate for NFC Module from 115200 to 9600. I tried pin3,4 & pin10,11 & pin 5,6 and other digital pins, only thing i can see through my Arduino Serial Monitor is FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF which means as you might know, the NFC Module RX,TX pins not connected properly. – David Kim May 11 '17 at 10:27
  • Maybe you could edit your question to include your code? Without seeing it, I can only guess that you are calling `read()` without checking `available()`. `read()` returns -1 if there are no characters available, and that will print as hex FF. Be sure to use `if (nfc.available())` before calling `ncf.read()`. – slash-dev May 11 '17 at 12:55