Возникла проблема столкновения таймера с использованием Servo и SoftwareSerial

У меня проблемы с таймером при использовании Servo.h и SoftwareSerial.h на плате Arduino Nano. И теперь мне нужно 2 пары последовательных контактов, используя модуль NFC и последовательный монитор Arduino на моем ноутбуке.

Если информация, которую я получил, не ошибается, на плате Nano есть три таймера (timer0, timer1, timer2). Как я слышал, timer1 - это 16-битный таймер, и Servo.h и SoftwareSerial.h одновременно используют этот таймер1 на плате Nano, поэтому они не могут избежать проблемы столкновения таймера.

Тем не менее мне нужно использовать оба заголовочных файла без столкновения таймера. Что мне делать в этом случае? Должен ли я изменить файл Servo.h, чтобы не использовать timer1?

Потому что все, что я делаю с моим серводвигателем, это контроль углового положения.

Поэтому использование 16-битного таймера в этом проекте бесполезно, я продолжаю, если не использую управление ШИМ.

Итак, на данный момент, я хочу использовать timer0 или timer2 (оба с 8-битным таймером) вместо использования timer1. Если нет, то timer1 из обоих заголовочных файлов Servo и Software будет конфликтовать. Ниже приведен исходный код, который я использую.

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

Резюме

У меня возникла проблема столкновения таймера с использованием Servo.h и SoftwareSerial.h.

они оба используют таймер1 одновременно. Что мне делать, чтобы избежать проблемы столкновения и заставить эти два работать нормально? Должен ли я что-то сделать с исходным кодом, например, добавив несколько строк кода или изменить эти заголовочные файлы?

1 ответ

Решение

Обычно я бы предложил AltSoftSerial как альтернатива SoftwareSerial (читайте больше здесь), но это также конфликтует с использованием библиотеки TIMER1 серво-библиотеки. Он может использоваться только на двух конкретных выводах.

Я думаю мой NeoSWSerialсделал бы трюк. Это повторно используетmicros()Синхронизация часов (TIMER0) и Pin Change для реализации программного последовательного порта. Это ограничивает скорость передачи данных 9600, 19200 и 38400, но это гораздо эффективнее, чемSoftwareSerial, Может использоваться на любых двух штырьках.


Обновить

Я бы не советовал использовать программный последовательный порт на 115200, так как он может быть ненадежным выше 38400. Возможно, вы сможете отправить команду конфигурации скорости передачи данных в модуль NFC, чтобы установить для него более низкую скорость.

Кстати, если вы отправляете информацию (а не только получаете), все программные библиотеки последовательных портов отключают прерывания во время передачи, кроме AltSoftSerial... который вы не можете использовать. Просто знайте об этом, потому что это может повлиять на ваш сервопривод при передаче на NeoSWSerial,

Также убедитесь, что вы используете один из выводов ШИМ для сервопривода. Если библиотека сервосистемы создает сигнал ШИМ с программным обеспечением (точно так же, как программный последовательный порт), у ЦПУ не будет времени для чего-то еще.

Может быть, лучше поставить модуль NFC на аппаратный последовательный порт, Serial, Для отладочных отпечатков используйте NeoSWSerial подключен к преобразователю последовательного порта в USB TTL. Затем откройте последовательный монитор на COM-порту этого конвертера. Удалите отладку позже, потому что передача отключает прерывания.

Есть и другие доски с дополнительными UARTS. Например, Arduino Leo (ATMega32U4 MCU) имеет дополнительный последовательный порт, Serial1, что вы могли бы использовать для NFC. Serial все еще будет доступен для отладочных отпечатков.

Другие вопросы по тегам