1+ #if defined(ARDUINO_ARCH_MBED)
2+
3+ #include < Arduino.h>
4+ #include < Servo.h>
5+
6+ class ServoImpl {
7+ mbed::DigitalOut *pin;
8+ mbed::Timeout timeout; // calls a callback once when a timeout expires
9+ mbed::Ticker ticker; // calls a callback repeatedly with a timeout
10+ uint32_t duration;
11+
12+ public:
13+ ServoImpl (PinName _pin) {
14+ pin = new mbed::DigitalOut (_pin);
15+ }
16+
17+ ~ServoImpl () {
18+ ticker.detach ();
19+ timeout.detach ();
20+ delete pin;
21+ }
22+
23+ void start (uint32_t duration_us) {
24+ duration = duration_us;
25+ ticker.attach (mbed::callback (this , &ServoImpl::call), 0 .02f );
26+ }
27+
28+ void call () {
29+ timeout.attach (mbed::callback (this , &ServoImpl::toggle), duration / 1e6 );
30+ toggle ();
31+ }
32+
33+ void toggle () {
34+ *pin = !*pin;
35+ }
36+
37+ uint32_t read () {
38+ return duration;
39+ }
40+ };
41+
42+ static ServoImpl* servos[MAX_SERVOS]; // static array of servo structures
43+ uint8_t ServoCount = 0 ; // the total number of attached servos
44+
45+ #define SERVO_MIN () (MIN_PULSE_WIDTH - this ->min) // minimum value in uS for this servo
46+ #define SERVO_MAX () (MAX_PULSE_WIDTH - this ->max) // maximum value in uS for this servo
47+
48+ #define TRIM_DURATION 15 // callback overhead (35 uS) -> 15uS if toggle() is called after starting the timeout
49+
50+ Servo::Servo ()
51+ {
52+ if (ServoCount < MAX_SERVOS) {
53+ this ->servoIndex = ServoCount++;
54+ } else {
55+ this ->servoIndex = INVALID_SERVO; // too many servos
56+ }
57+ }
58+
59+ uint8_t Servo::attach (int pin)
60+ {
61+ return this ->attach (pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
62+ }
63+
64+ uint8_t Servo::attach (int pin, int min, int max)
65+ {
66+ pinMode (pin, OUTPUT); // set servo pin to output
67+ servos[this ->servoIndex ] = new ServoImpl (digitalPinToPinName (pin));
68+
69+ this ->min = (MIN_PULSE_WIDTH - min);
70+ this ->max = (MAX_PULSE_WIDTH - max);
71+ return this ->servoIndex ;
72+ }
73+
74+ void Servo::detach ()
75+ {
76+ delete servos[this ->servoIndex ];
77+ servos[this ->servoIndex ] = NULL ;
78+ }
79+
80+ void Servo::write (int value)
81+ {
82+ // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
83+ if (value < MIN_PULSE_WIDTH)
84+ {
85+ if (value < 0 )
86+ value = 0 ;
87+ else if (value > 180 )
88+ value = 180 ;
89+
90+ value = map (value, 0 , 180 , SERVO_MIN (), SERVO_MAX ());
91+ }
92+ writeMicroseconds (value);
93+ }
94+
95+ void Servo::writeMicroseconds (int value)
96+ {
97+ if (!servos[this ->servoIndex ]) {
98+ return ;
99+ }
100+ // calculate and store the values for the given channel
101+ byte channel = this ->servoIndex ;
102+ if ( (channel < MAX_SERVOS) ) // ensure channel is valid
103+ {
104+ if (value < SERVO_MIN ()) // ensure pulse width is valid
105+ value = SERVO_MIN ();
106+ else if (value > SERVO_MAX ())
107+ value = SERVO_MAX ();
108+
109+ value = value - TRIM_DURATION;
110+ servos[this ->servoIndex ]->start (value);
111+ }
112+ }
113+
114+ int Servo::read () // return the value as degrees
115+ {
116+ return map (readMicroseconds (), SERVO_MIN (), SERVO_MAX (), 0 , 180 );
117+ }
118+
119+ int Servo::readMicroseconds ()
120+ {
121+ if (!servos[this ->servoIndex ]) {
122+ return 0 ;
123+ }
124+ return servos[this ->servoIndex ]->read ();
125+ }
126+
127+ bool Servo::attached ()
128+ {
129+ return servos[this ->servoIndex ] != NULL ;
130+ }
131+
132+ #endif
0 commit comments