如何根据需要为esp32 arduino步进电机控制器应用程序删除并重新启动硬件计时器用于中断

如何解决如何根据需要为esp32 arduino步进电机控制器应用程序删除并重新启动硬件计时器用于中断

我在弄清楚如何禁用然后重新启用(在触发事件时)esp-arduino库here中的硬件(esp32-hal-timer)计时器(对于步进电机控制器应用程序)时遇到麻烦与我的esp32开发板。它会递减计数并根据需要触发ISR,但会禁用它(这样就不会不必要地调用ISR)了,但是当我尝试重新启动它时,它不会启动。奇怪的是,它的启动方式与第一次相同,所以我不确定这是否与我的代码有关,或者与特定库处理垃圾收集的方式有关。这也是我第一次尝试使用中断。我的代码在下面。

为避免麻烦,一般过程是在设置方法中初始化计时器(称为motorTimer),然后连接到wifi,在mqtt的回调方法中,任何带有整数有效载荷的消息都会触发然后在motor.h类中使用“ moveTo”方法,然后在触发ISR计时器时触发同一类中的update方法。然后,计时器将在每次迭代中更改其时间,以进行加速度补偿。这很有效,直到需要杀死计时器然后稍后重新启动-才完全不调用ISR,就像计时器没有正确停止一样。这就是我的问题所在。

#include <SPI.h>
#include <Adafruit_MAX31855.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include "VCDevices.h"

// Replace the next variables with your SSID/Password combination
// //WiFi info:
const char* ssid = "SSID";
const char* password = "PASSWORD_HERE";

// Add your MQTT Broker IP address,example:
const char* mqtt_server = "home.IOT.lan";

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char topArr[50];
char msgArr[100];
// get size of array first,to feed to for loop
int numDevices = sizeof(devices)/sizeof(device);
int value = 0;
unsigned long heartbeat_previousMillis = 0;
unsigned long motorCheck_previousMillis = 0;
const long timeOut = 60000;
const long motorCheckTime = 600;

hw_timer_t * motorTimer = NULL;
bool state = 0;
int count = 0;

int d = 0;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
bool finished = false;

enum LogLevel
{
    Debug,//Sends message only to the serial port
    Error,//Sends message over MQTT to 'Errors' topic,and to serial port with "Error: " pre-appended
    Message //Sends message over serial and MQTT to 'StatusMessage' topic
};

///****** TIMER LOGIC HERE ******
//TODO: timer needs to just figure out what time the next pulse needs to be fired at - needs to be calculated on the fly

//This is calculated inside the Motor class.
 
void IRAM_ATTR motorInterrupt(void) 
{
  Serial.println("B");
  portENTER_CRITICAL(&timerMux);
  noInterrupts();
  //check if the motor is in motion still
  if (!linMotor.getMotorStatus())
  {
    d = linMotor.Update();
    timerAlarmWrite(motorTimer,d,true);
    timerAlarmEnable(motorTimer);
  }
  else 
  {
    // timerAlarmWrite(motorTimer,1,true);
    timerAlarmDisable(motorTimer);
    finished = true;
  }
  //kill the timer and interrupt if not
  interrupts();
  portEXIT_CRITICAL(&timerMux);
}

//****** END TIMER HERE *****

void log(LogLevel level,String message)
{
    switch(level)
    {
        case LogLevel::Debug:
            Serial.println(message);
            break;
        case LogLevel::Error:
            print(ErrorTopic,message);
            break;
        case LogLevel::Message:
            Serial.print("Message: ");
            Serial.println(message);
            print(StatusTopic,message);
            break;
    }
}


void print(char topic[],String message)
{
    Serial.print(topic);
    Serial.print(" : ");
    Serial.println(message);
    //topic.toCharArray(topArr,sizeof(topic)+2);
    message.toCharArray(msgArr,sizeof(msgArr));
    client.publish(topic,msgArr,message.length());
}
// WiFi methods are located below:

void setup_wifi() 
{
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid,password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic,byte* message,unsigned int length)
{
  Serial.print("Message arrived on topic: ");
  Serial.print(topic);
  Serial.print(". Message: ");
  String messageTemp;
  String response;

  //check if heartbeat signal was sent
  if (String(topic) == HeartbeatTopic)
  {
    heartbeat_previousMillis = millis();
  }
  
  for (int i = 0; i < length; i++) {
    Serial.print((char)message[i]);
    messageTemp += (char)message[i];
  }

  Serial.println();
  // Iterate through each device and update states accordingly
  for (int i = 0; i < numDevices; i = i + 1) 
  {
    // the char arrays need to be cast as strings to compare to each other
    if (String(topic) == String(devices[i].controlTopic))
    {
      if (messageTemp == "on")
      {
        digitalWrite(devices[i].pinNumber,devices[i].shouldInvert?LOW:HIGH);
        response = "on";
      }
      else
      {
        digitalWrite(devices[i].pinNumber,devices[i].shouldInvert?HIGH:LOW);
        response = "off";
      }
      log(LogLevel::Message,response);
      print(devices[i].stateTopic,response);
      break;
    }
    if (String(topic) == String(motorControlTopic) || String(topic) == String(motorSetTopic))
    {
      if (String(topic) == String(motorSetTopic))
      {
        //sets speed for now,other params later
        linMotor.SetSpeed(messageTemp.toInt());
        response = "Parameters set";
      }
      if (String(topic) == String(motorControlTopic)) 
      {
        if (messageTemp.toInt() > 0)
        {
          //check if motor is available to run
          if (linMotor.getMotorStatus())
          {
            linMotor.MoveTo(messageTemp.toInt());
            //TODO: Setup timer stuff here
            // motorTimer = NULL;
            // motorTimer = timerBegin(1,80,true);
            
            // timerAttachInterrupt(motorTimer,&motorInterrupt,true);
            timerSetAutoReload(motorTimer,true);
            timerAlarmWrite(motorTimer,true);
            timerAlarmEnable(motorTimer);
            
            response = "moving to " + String(messageTemp.toInt()) + " mm position";
          }
          else
          {
            response = "motor is busy - wait for movement to end!";
          }
        }
        else if (messageTemp == "home")
        {
          linMotor.SetZero();
          response = "setting motor to zero";
        }
        else if (messageTemp == "stop")
        {
          linMotor.EStop();    
          if (motorTimer != NULL)
          {
            timerDetachInterrupt(motorTimer); 
          }
          response = "motor stopped";
          //TODO: detach timer here!
        }
      }
      
      //TODO: put in GUI call for position updates
      //print(motorStateTopic,"position is: " + String(linMotor.getPosition()));
      log(LogLevel::Message,response);
      print(motorStateTopic,response);
      break;
    }
  }
}  

void setup()
{ 
  //Testing code here: 
  motorTimer = timerBegin(1,true);
  timerAttachInterrupt(motorTimer,true);
  //end testing code
  //Start serial connection
    Serial.begin(115200);
    for (int i = 0; i < numDevices; i = i + 1)
  { 
    pinMode(devices[i].pinNumber,OUTPUT);
    digitalWrite(devices[i].pinNumber,devices[i].shouldInvert?HIGH:LOW);
  }
  pinMode(pulsePin,OUTPUT);
  pinMode(directionPin,OUTPUT);
    delay(500);
  linMotor.SetSpeed(250);
  linMotor.SetAcceleration(20);

    log(LogLevel::Debug,"Connecting to mqtt");
    Serial.println(mqtt_server);
    setup_wifi();
    client.setServer(mqtt_server,1883);
  client.setCallback(callback);
    
    reconnect();
    log(LogLevel::Message,"Connected");

    log(LogLevel::Message,"System Started!");

  // Initialize heartbeat timer
  heartbeat_previousMillis = millis();
  motorCheck_previousMillis = millis();
}

void reconnect() 
{
  // Loop until we're reconnected
  while (!client.connected()) {
  Serial.print("Attempting MQTT connection...");
    Serial.println(mqtt_server);
    // Attempt to connect
    if (client.connect("ESP8266Client")) {
      Serial.println("connected");

      // Subscribe to all relevant messages
      for (int i = 0; i < numDevices; i = i + 1)
      {
        client.subscribe(devices[i].controlTopic);
      } 
      // subscribe to the heartbeat topic as well
      client.subscribe(HeartbeatTopic);
      client.subscribe(motorControlTopic);
      client.subscribe(motorSetTopic);
      } 
      else 
      {
      Serial.print("failed,rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void loop()
{
    if (!client.connected()) reconnect();
  client.loop();  
  unsigned long currentMillis = millis();
  if (currentMillis - motorCheck_previousMillis >= motorCheckTime)
  {
      // print(motorStateTopic,"position is: " + String(linMotor.GetPosition()));
      portENTER_CRITICAL(&timerMux);
      Serial.println(String(linMotor.GetPosition()));
      portEXIT_CRITICAL(&timerMux);
      motorCheck_previousMillis = currentMillis;      
      if (finished) 
      {
        // timerAlarmWrite(motorTimer,false);
        // Serial.println("wrote 0 alarm");
        // timerAlarmDisable(motorTimer);       // stop alarm
        // Serial.println("disabled alarm");
        // timerEnd(motorTimer);
        // Serial.println("timerEnd");
        // motorTimer = NULL;
        // Serial.println("NULLED timer");
        // motorTimer = timerBegin(1,true);
        // Serial.println("timer stated again!");

      //   timerRestart(motorTimer);
      //   timerDetachInterrupt(motorTimer);    // detach interrupt
      //   timerEnd(motorTimer);    
        finished = false;
      }
  }
}

我不认为需要显示motor.h方法,但是如果需要可以发布。预先感谢您的帮助!

Edit1:只是意识到互斥体在循环功能内的计时器删除发生之前已被关闭,但是它仍然没有解决。同样,该部分评论中的内容是我迄今为止尝试的所有未成功的内容。

Edit2:为清楚起见,重新措辞。

解决方法

“重新启动”一词让我想到它将立即立即重新启动计时器,但事实并非如此。如果之前将重载设置为false,则必须在实际执行之前重新设置计时器-这对于我的用例来说非常合适。下面是我的新代码(图上我将包括wifi和mqtt内容,以帮助其他人):

library(dplyr)

join_then_average <- function(df1,df2,var) {
  full_join(df1,by = "id")  %>%
    mutate(x = rowMeans(select(.,contains(var))))
}

join_then_average(a,b,'x')

# A tibble: 3 x 4
#     id   x.x   x.y     x
#  <int> <int> <int> <dbl>
#1     1     4    16    10
#2     2     5    17    11
#3     3     6    18    12
,

我发现这个问题与我遇到的问题非常相似,同样在步进应用程序中,我需要为步进器设置一个引脚高电平才能运行,然后在 2 毫秒后,需要将引脚设置回低电平。为此,我在第一个计时器的 ISR 内触发了第二个计时器表单,但无论我尝试/设置什么,第二个计时器总是在 23us 后触发。为了说明我制作了下面的准系统示例,以便可以看到两个 ISR 之间的间隔无论如何总是 22/23us。此例程/策略是非常流行的 TeensyStep library (ESP32 Fork) 的一部分,而且非常短的脉冲长度并没有真正受到大型驱动程序的青睐。我做错了什么?

hw_timer_t *timerA = NULL;
hw_timer_t *timerB = NULL;

void IRAM_ATTR onTimerA()
{
  digitalWrite(13,1);  
  Serial.print("HI ");
  Serial.println(micros());
  timerAlarmEnable(timerB);
}

void IRAM_ATTR onTimerB()
{
  digitalWrite(13,0);  
  Serial.print("LO ");
  Serial.println(micros());    
}

void setup()
{
  Serial.begin(115200);
  while (!Serial);

  timerA = timerBegin(0,80,true);
  timerAttachInterrupt(timerA,&onTimerA,true);
  timerAlarmWrite(timerA,1000000,true);  
  
  timerB = timerBegin(1,true);
  timerAttachInterrupt(timerB,&onTimerB,true);
  timerAlarmWrite(timerB,200000,false);

  timerAlarmEnable(timerA);
}

void loop(){}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-