【问题标题】:Having timer collision issue with using Servo and SoftwareSerial使用 Servo 和 SoftwareSerial 时遇到计时器冲突问题
【发布时间】:2017-05-09 10:24:54
【问题描述】:

我在 Arduino Nano 板上使用 Servo.h 和 SoftwareSerial.h 时遇到计时器冲突问题。现在我需要 2 对串行引脚,通过在我的笔记本电脑上使用 NFC 模块和 Arduino 的串行监视器。

如果我得到的信息没有错的话,Nano board 中提供了三个定时器(timer0、timer1、timer2)。我听说 timer1 是 16 位定时器,Servo.h 和 SoftwareSerial.h 在 Nano 板上同时使用该 timer1,这就是他们无法避免定时器冲突问题的原因。

但我需要同时使用这两个头文件而不会发生计时器冲突。在这种情况下,我该怎么办?不使用 timer1 需要修改 Servo.h 文件吗?

因为我对伺服电机所做的只是控制角度位置。

因此,在这个项目中使用 16 位定时器是没有用的,除非我使用 PWM 控制。

所以,此时,我想使用 timer0 或 timer2(两者都是 8 位定时器)而不是使用 timer1。否则,Servo 和 Software 头文件中的 timer1 将发生冲突。 以下是我使用的源代码。

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 时遇到计时器冲突问题。

它们同时共享 timer1。为了避免这种碰撞问题并使这两个工作正常,我应该怎么做?我应该对源代码做些什么,比如添加几行代码或修改那些头文件?

【问题讨论】:

  • 所以..你的意思是如果我真的想快速回答我的问题,我不应该使用“尽快”这个短语?
  • 这就是它所说的,是的。这里的答案大多是志愿者写的,不会急于求成。
  • 我完全理解这一点,并对我的态度感到非常抱歉。下次我会小心的。谢谢你的建议!
  • 别担心,大卫,祝你的项目好运。

标签: timer arduino collision servo software-serial


【解决方案1】:

通常,我会建议 AltSoftSerial 作为 SoftwareSerial 的替代品(阅读更多 here),但它也与伺服库的 TIMER1 使用冲突。它只能用于两个特定的引脚。

我认为我的NeoSWSerial 可以解决问题。它重新使用micros() 时钟 (TIMER0) 和引脚更改中断来实现软件串行端口。这将其限制为波特率 9600、19200 和 38400,但它比SoftwareSerial 高效得多。它可以用在任意两个引脚上。


更新

我不建议在 115200 使用软件串口,因为它在 38400 以上可能不可靠。您可以向 NFC 模块发送波特率配置命令以将其设置为较低的速率。

顺便说一句,如果您正在发送信息(不仅仅是接收),所有软件串行端口库都会在传输过程中禁用中断,除了 AltSoftSerial...您不能使用。请注意这一点,因为当您在NeoSWSerial 上传输时,它可能会影响您的伺服。

另外,请确保您使用的是伺服的 PWM 引脚之一。如果 Servo 库使用软件(就像软件串行端口一样)创建 PWM 信号,CPU 就没有时间做其他事情了。

将NFC模块放在硬件串口Serial上可能会更好。对于调试打印,使用连接到 TTL 串行到 USB 转换器的NeoSWSerial。然后在该转换器的 COM 端口上打开串行监视器。稍后删除调试,因为传输禁用中断。

还有其他具有额外 UART 的板。例如,Arduino Leo (ATMega32U4 MCU) 有一个额外的串行端口Serial1,您可以将其用于 NFC。 Serial 仍可用于调试打印。

【讨论】:

  • 您的 NeoSWSerial 的“micros()”是否仅适用于波特率 9600、19200 和 38400?我没有抱怨,但我正在考虑使用它在我的 arduino 板和需要 115200 波特率的 NFC 模块之间进行通信。
  • @DavidKim - 是的,只有那些波特率。更多信息在上面的更新中。
  • 谢谢。我将使用您的 NeoSWSerial 库尝试我的项目。
  • 我已经尝试了几个小时,但它不起作用..我不知道问题出在哪里,但是您的 NeoSWSerial 在 nano 上是否有任何特定的引脚?我将 NFC 模块的波特率从 115200 更改为 9600。我尝试了 pin3,4 & pin10,11 & pin 5,6 和其他数字引脚,我只能通过我的 Arduino 串行监视器看到的是 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 这意味着您可能知道,NFC 模块 RX、TX 引脚未正确连接。
  • 也许您可以编辑您的问题以包含您的代码?没有看到它,我只能猜测您正在调用read()而不检查available()read() 如果没有可用字符,则返回 -1,并将打印为十六进制 FF。请务必在调用ncf.read() 之前使用if (nfc.available())
猜你喜欢
  • 2021-10-24
  • 1970-01-01
  • 1970-01-01
  • 2020-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-11
  • 2016-08-08
相关资源
最近更新 更多