1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-21 10:26:06 +03:00

Merge pull request #1231 from Makuna/ServoDetachFixes

Fix detach and attach
This commit is contained in:
Ivan Grokhotkov 2015-12-18 08:45:37 +03:00
commit fa485cd88f

View File

@ -1,20 +1,20 @@
/* /*
Copyright (c) 2015 Michael C. Miller. All right reserved. Copyright (c) 2015 Michael C. Miller. All right reserved.
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details. Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#if defined(ESP8266) #if defined(ESP8266)
@ -26,9 +26,12 @@
const uint32_t c_CycleCompensation = 4; // compensation us to trim adjust for digitalWrite delays const uint32_t c_CycleCompensation = 4; // compensation us to trim adjust for digitalWrite delays
#define INVALID_PIN 63 // flag indicating never attached servo
struct ServoInfo { struct ServoInfo {
uint8_t pin : 6; // a pin number from 0 to 63 uint8_t pin : 6; // a pin number from 0 to 62, 63 reserved
uint8_t isActive : 1; // true if this channel is enabled, pin not pulsed if false uint8_t isActive : 1; // true if this channel is enabled, pin not pulsed if false
uint8_t isDetaching : 1; // true if this channel is being detached, maintains pulse integrity
}; };
struct ServoState { struct ServoState {
@ -76,18 +79,37 @@ static void Servo_Handler(T* timer)
if (servoIndex < s_servoCount && s_servos[servoIndex].info.isActive) { if (servoIndex < s_servoCount && s_servos[servoIndex].info.isActive) {
// pulse this channel low if activated // pulse this channel low if activated
digitalWrite(s_servos[servoIndex].info.pin, LOW); digitalWrite(s_servos[servoIndex].info.pin, LOW);
if (s_servos[servoIndex].info.isDetaching) {
s_servos[servoIndex].info.isActive = false;
s_servos[servoIndex].info.isDetaching = false;
}
} }
timer->nextChannel(); timer->nextChannel();
} }
servoIndex = SERVO_INDEX(timer->timerId(), timer->getCurrentChannel()); servoIndex = SERVO_INDEX(timer->timerId(), timer->getCurrentChannel());
if (servoIndex < s_servoCount && timer->getCurrentChannel() < SERVOS_PER_TIMER) { if (servoIndex < s_servoCount &&
timer->getCurrentChannel() < SERVOS_PER_TIMER) {
timer->SetPulseCompare(timer->usToTicks(s_servos[servoIndex].usPulse) - c_CycleCompensation); timer->SetPulseCompare(timer->usToTicks(s_servos[servoIndex].usPulse) - c_CycleCompensation);
if (s_servos[servoIndex].info.isActive) { // check if activated if (s_servos[servoIndex].info.isActive) {
digitalWrite(s_servos[servoIndex].info.pin, HIGH); // its an active channel so pulse it high if (s_servos[servoIndex].info.isDetaching) {
// it was active, reset state and leave low
s_servos[servoIndex].info.isActive = false;
s_servos[servoIndex].info.isDetaching = false;
} }
else {
// its an active channel so pulse it high
digitalWrite(s_servos[servoIndex].info.pin, HIGH);
}
}
}
else {
if (!isTimerActive(timer->timerId())) {
// no active running channels on this timer, stop the ISR
finISR(timer->timerId());
} }
else { else {
// finished all channels so wait for the refresh period to expire before starting over // finished all channels so wait for the refresh period to expire before starting over
@ -100,6 +122,7 @@ static void Servo_Handler(T* timer)
// at least REFRESH_INTERVAL has elapsed // at least REFRESH_INTERVAL has elapsed
timer->SetCycleCompare(timer->GetCycleCount() + c_CycleCompensation * 2); timer->SetCycleCompare(timer->GetCycleCount() + c_CycleCompensation * 2);
} }
}
timer->setEndOfCycle(); timer->setEndOfCycle();
} }
@ -166,6 +189,10 @@ Servo::Servo()
// set default _minUs and _maxUs incase write() is called before attach() // set default _minUs and _maxUs incase write() is called before attach()
_minUs = MIN_PULSE_WIDTH; _minUs = MIN_PULSE_WIDTH;
_maxUs = MAX_PULSE_WIDTH; _maxUs = MAX_PULSE_WIDTH;
s_servos[_servoIndex].info.isActive = false;
s_servos[_servoIndex].info.isDetaching = false;
s_servos[_servoIndex].info.pin = INVALID_PIN;
} }
else { else {
_servoIndex = INVALID_SERVO; // too many servos _servoIndex = INVALID_SERVO; // too many servos
@ -182,9 +209,11 @@ uint8_t Servo::attach(int pin, int minUs, int maxUs)
ServoTimerSequence timerId; ServoTimerSequence timerId;
if (_servoIndex < MAX_SERVOS) { if (_servoIndex < MAX_SERVOS) {
if (s_servos[_servoIndex].info.pin == INVALID_PIN) {
pinMode(pin, OUTPUT); // set servo pin to output pinMode(pin, OUTPUT); // set servo pin to output
digitalWrite(pin, LOW); digitalWrite(pin, LOW);
s_servos[_servoIndex].info.pin = pin; s_servos[_servoIndex].info.pin = pin;
}
// keep the min and max within 200-3000 us, these are extreme // keep the min and max within 200-3000 us, these are extreme
// ranges and should support extreme servos while maintaining // ranges and should support extreme servos while maintaining
@ -197,6 +226,7 @@ uint8_t Servo::attach(int pin, int minUs, int maxUs)
if (!isTimerActive(timerId)) { if (!isTimerActive(timerId)) {
initISR(timerId); initISR(timerId);
} }
s_servos[_servoIndex].info.isDetaching = false;
s_servos[_servoIndex].info.isActive = true; // this must be set after the check for isTimerActive s_servos[_servoIndex].info.isActive = true; // this must be set after the check for isTimerActive
} }
return _servoIndex; return _servoIndex;
@ -206,10 +236,8 @@ void Servo::detach()
{ {
ServoTimerSequence timerId; ServoTimerSequence timerId;
s_servos[_servoIndex].info.isActive = false; if (s_servos[_servoIndex].info.isActive) {
timerId = SERVO_INDEX_TO_TIMER(_servoIndex); s_servos[_servoIndex].info.isDetaching = true;
if (!isTimerActive(timerId)) {
finISR(timerId);
} }
} }