首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用伺服和SoftwareSerial存在计时器冲突问题

使用伺服和SoftwareSerial存在计时器冲突问题
EN

Stack Overflow用户
提问于 2017-05-09 10:24:54
回答 1查看 2.9K关注 0票数 0

我在Arduino Nano板上使用Servo.h和SoftwareSerial.h有计时器碰撞问题。现在,我需要使用NFC模块和Arduino的串行监视器在我的笔记本上的2对串行引脚。

如果我得到的信息是正确的,有三个定时器(timer0,timer1,timer2)可以在纳米板上使用。我听说timer1是16位定时器,Servo.h和SoftwareSerial.h同时在Nano板上使用timer1,这就是他们不能避免计时器碰撞问题的原因。

然而,我需要使用这两个头文件没有计时器冲突。在这种情况下,我该怎么办?我是否必须修改Servo.h文件以避免使用timer1?

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

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

因此,在这一点上,我想使用timer0或timer2 (两者都是8位定时器),而不是使用timer1。如果不是,来自伺服和软件的头文件的timer1将被碰撞。下面是我使用的源代码。

代码语言:javascript
复制
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。为了避免这个碰撞问题,并使这两个工作良好,我应该做什么?我应该对源代码做些什么,比如添加几行代码或修改这些头文件吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-05-09 13:13:54

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

我想我的NeoSWSerial可以做到这一点。它重新使用micros()时钟(TIMER0)和换针中断来实现软件串行端口。这将其限制为9600、19200和38400,但它比SoftwareSerial效率高得多。它可以用于任何两个引脚。

更新

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

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

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

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

还有其他董事会有额外的UARTS。例如,Arduino Leo (ATMega32U4 MCU)有一个额外的串口,Serial1,您可以用于NFC。Serial仍可用于调试打印。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43867283

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档