Timer 如何根据需要删除和重新启动esp32 arduino(步进电机控制器应用)的hw定时器(用于中断)
对于带有esp32开发板的步进电机控制器应用程序,我无法确定如何禁用然后重新启用(在触发事件时)esp arduino库中的hw(esp32 hal定时器)定时器。它将倒计时并根据需要多次触发ISR,但当我禁用它时(以便不会不必要地调用ISR),当我再次尝试启动它时,它将不会启动。奇怪的是,它的启动方式与第一次相同,因此我不确定这是我的代码问题还是特定库处理垃圾收集的方式问题。这也是我第一次尝试处理中断。我的代码如下 为了避免过多地费力,一般过程是在setup方法中初始化计时器(称为motorTimer),然后在mqtt的回调方法中连接到wifi。任何有效负载为整数的消息都将触发motor.h类中的“moveTo”方法,然后,在触发ISR计时器时,将触发该类中的更新方法。然后,计时器将在每次迭代中更改其时间,以进行加速度补偿。这工作得很好,直到时间结束计时器,然后重新启动它-然后根本不调用ISR,就像计时器没有正确停止一样。这就是我的问题所在Timer 如何根据需要删除和重新启动esp32 arduino(步进电机控制器应用)的hw定时器(用于中断),timer,arduino,interrupt,esp32,Timer,Arduino,Interrupt,Esp32,对于带有esp32开发板的步进电机控制器应用程序,我无法确定如何禁用然后重新启用(在触发事件时)esp arduino库中的hw(esp32 hal定时器)定时器。它将倒计时并根据需要多次触发ISR,但当我禁用它时(以便不会不必要地调用ISR),当我再次尝试启动它时,它将不会启动。奇怪的是,它的启动方式与第一次相同,因此我不确定这是我的代码问题还是特定库处理垃圾收集的方式问题。这也是我第一次尝试处理中断。我的代码如下 为了避免过多地费力,一般过程是在setup方法中初始化计时器(称为motorT
#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, 1, 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, 80, true);
timerAttachInterrupt(motorTimer, &motorInterrupt, 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, 0, 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, 80, true);
// Serial.println("timer stated again!");
// timerRestart(motorTimer);
// timerDetachInterrupt(motorTimer); // detach interrupt
// timerEnd(motorTimer);
finished = false;
}
}
}
#包括
#包括
#包括
#包括
#包括
#包括“VCDevices.h”
//用SSID/密码组合替换下一个变量
////WiFi信息:
const char*ssid=“ssid”;
const char*password=“password\u HERE”;
//添加您的MQTT代理IP地址,例如:
const char*mqtt_server=“home.IOT.lan”;
无线客户端;
PubSubClient客户(espClient);
long lastMsg=0;
char-topArr[50];
char-msgArr[100];
//首先获取数组的大小,以馈送到for循环
int numDevices=sizeof(设备)/sizeof(设备);
int值=0;
无符号长心跳\u previousMillis=0;
未签名的长motorCheck_previousMillis=0;
const long timeOut=60000;
const long motorCheckTime=600;
hw_timer_t*motorTimer=NULL;
布尔状态=0;
整数计数=0;
int d=0;
portMUX\u TYPE timerMux=portMUX\u初始值设定项\u未锁定;
bool finished=false;
枚举日志级别
{
调试,//只向串行端口发送消息
错误,//通过MQTT将消息发送到“Errors”主题,并发送到带有“Error:”前缀的串行端口
消息//通过串行和MQTT向“StatusMessage”主题发送消息
};
///******这里是定时器逻辑******
//TODO:计时器需要计算下一个脉冲需要发射的时间-需要动态计算
//这是在Motor类中计算的。
无效IRAM_ATTR电机中断(无效)
{
序列号。打印号(“B”);
portENTER_临界(&timerMux);
无中断();
//检查电机是否仍在运动
如果(!linMotor.getMotorStatus())
{
d=linMotor.Update();
timerAlarmWrite(motorTimer,d,true);
timerAlarmEnable(电机定时器);
}
其他的
{
//timerAlarmWrite(motorTimer,1,true);
timerAlarmDisable(马达定时器);
完成=正确;
}
//关闭计时器,否则中断
中断();
portEXIT_临界值(&timerMux);
}
//******这里是结束计时器*****
无效日志(日志级别、字符串消息)
{
开关(电平)
{
案例日志级别::调试:
Serial.println(消息);
打破
案例日志级别::错误:
打印(错误主题、消息);
打破
案例日志级别::消息:
串行打印(“消息:”);
Serial.println(消息);
打印(状态主题、消息);
打破
}
}
无效打印(字符主题[],字符串消息)
{
连续打印(主题);
连续打印(“:”);
Serial.println(消息);
//toCharArray(topArr,sizeof(topic)+2);
message.toCharArray(msgArr,sizeof(msgArr));
publish(topic,msgArr,message.length());
}
//WiFi方法如下所示:
无效设置\u wifi()
{
延迟(10);
//我们从连接WiFi网络开始
Serial.println();
串行打印(“连接到”);
序列号println(ssid);
WiFi.begin(ssid,密码);
while(WiFi.status()!=WL_已连接){
延迟(500);
连续打印(“.”);
}
Serial.println(“”);
Serial.println(“WiFi连接”);
Serial.println(“IP地址:”);
Serial.println(WiFi.localIP());
}
无效回调(字符*主题,字节*消息,无符号整数长度)
{
Serial.print(“邮件到达主题:”);
连续打印(主题);
串行打印(“.Message:”);
字符串messageTemp;
字符串响应;
//检查是否发送了心跳信号
if(字符串(主题)=HeartbeatTopic)
{
心跳_previousMillis=millis();
}
for(int i=0;i0)
{
//检查电机是否可用
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include "VCDevices.h"
hw_timer_t * motorTimer = NULL;
Motor linMotor2 = Motor(pulsePin, directionPin);
int d = 0;
bool nextRun = false;
const char* ssid = "SSID";
const char* password = "PASSWORD_HERE";
const char* mqtt_server = "MQTT_SERVER_HERE";
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char topArr[50];
char msgArr[100];
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
//Timer ISR
void IRAM_ATTR motorInterrupt(void)
{
portENTER_CRITICAL(&timerMux);
noInterrupts();
//check if the motor is in motion still
if (!linMotor2.getMotorStatus())
{
d = linMotor2.Update();
//give timer different delay, dependent on its current speed
timerAlarmWrite(motorTimer, d, true);
timerAlarmEnable(motorTimer);
}
//kill the timer and interrupt if not
else
{
nextRun = true;
//set the 'reload' boolean to false, to get it to only trigger one more time
timerAlarmWrite(motorTimer, 10, false);
// Serial.println("POSITION REACHED!");
}
interrupts();
portEXIT_CRITICAL(&timerMux);
}
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"))
{
client.subscribe(motorControlTopic);
Serial.println("connected");
}
else
{
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
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;
for (int i = 0; i < length; i++) {
Serial.print((char)message[i]);
messageTemp += (char)message[i];
}
Serial.println();
if (String(topic) == String(motorControlTopic))
{
if (messageTemp.toInt() > 0)
{
//check if motor is available to run
if (linMotor2.getMotorStatus())
{
linMotor2.MoveTo(messageTemp.toInt());
//set the motor timer and enable it
timerAlarmWrite(motorTimer, 1, true);
timerAlarmEnable(motorTimer);
response = "moving to " + String(messageTemp.toInt()) + " mm position";
}
else
{
response = "motor is busy - wait for movement to end!";
}
Serial.println(response);
}
}
}
void setup()
{
//Start serial connection
Serial.begin(115200);
//Setup wifi and mqtt stuff
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
//Fix up motor settings
pinMode(pulsePin, OUTPUT);
linMotor2.SetSpeed(200);
linMotor2.SetAcceleration(10);
//Initialize timer here for later use!
motorTimer = timerBegin(1, 80, true);
timerAttachInterrupt(motorTimer, &motorInterrupt, true);
Serial.println("TIMER SET!!");
digitalWrite(pulsePin, LOW);
}
void loop()
{
if (!client.connected()) reconnect();
client.loop();
portENTER_CRITICAL(&timerMux);
vTaskDelay(500);
count = linMotor2.GetPosition();
Serial.println("POSITION: " + String(count));
if (nextRun)
{
noInterrupts();
timerRestart(motorTimer);
Serial.println("*********TIMER RESTARTED!******");
nextRun = false;
interrupts();
}
portEXIT_CRITICAL(&timerMux);
}
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, 80, true);
timerAttachInterrupt(timerB, &onTimerB, true);
timerAlarmWrite(timerB, 200000, false);
timerAlarmEnable(timerA);
}
void loop(){}