Library for using the TLC5940 as a servo controller.
TLC5940Servo.cpp@5:56daa8c0697d, 2014-10-21 (annotated)
- Committer:
- dudanian
- Date:
- Tue Oct 21 06:26:25 2014 +0000
- Revision:
- 5:56daa8c0697d
- Parent:
- 2:1d2251574d35
- Child:
- 6:b001282e967b
Added mbed official docs for the Server inner class as well as support for the position(float degrees) function from the official mbed class.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
dudanian | 0:9fc434ff7a03 | 1 | #include "TLC5940Servo.h" |
dudanian | 0:9fc434ff7a03 | 2 | |
dudanian | 2:1d2251574d35 | 3 | TLC5940Servo::TLC5940Servo(PinName MOSI, PinName SCLK, PinName XLAT, PinName BLANK, |
dudanian | 2:1d2251574d35 | 4 | PinName GSCLK, const int number) : number(number), spi(MOSI, NC, SCLK), gsclk(GSCLK), |
dudanian | 2:1d2251574d35 | 5 | blank(BLANK), xlat(XLAT), newData(false), need_xlat(false) { |
dudanian | 0:9fc434ff7a03 | 6 | spi.format(12, 0); |
dudanian | 0:9fc434ff7a03 | 7 | spi.frequency(SPI_SPEED); |
dudanian | 2:1d2251574d35 | 8 | |
dudanian | 0:9fc434ff7a03 | 9 | xlat = 0; |
dudanian | 0:9fc434ff7a03 | 10 | blank = 1; |
dudanian | 2:1d2251574d35 | 11 | |
dudanian | 0:9fc434ff7a03 | 12 | reset_ticker.attach_us(this, &TLC5940Servo::reset, (1000000.0/GSCLK_SPEED) * 4096.0); |
dudanian | 2:1d2251574d35 | 13 | |
dudanian | 0:9fc434ff7a03 | 14 | gsclk.period_us(1000000.0/GSCLK_SPEED); |
dudanian | 0:9fc434ff7a03 | 15 | gsclk.write(.5); |
dudanian | 0:9fc434ff7a03 | 16 | |
dudanian | 2:1d2251574d35 | 17 | servos = new Servo[16 * number]; |
dudanian | 0:9fc434ff7a03 | 18 | } |
dudanian | 0:9fc434ff7a03 | 19 | |
dudanian | 2:1d2251574d35 | 20 | TLC5940Servo::~TLC5940Servo() { |
dudanian | 2:1d2251574d35 | 21 | delete[] servos; |
dudanian | 2:1d2251574d35 | 22 | } |
dudanian | 2:1d2251574d35 | 23 | |
dudanian | 2:1d2251574d35 | 24 | void TLC5940Servo::calibrate(int index, float range, float degrees) { |
dudanian | 2:1d2251574d35 | 25 | servos[index].calibrate(range, degrees); |
dudanian | 0:9fc434ff7a03 | 26 | } |
dudanian | 0:9fc434ff7a03 | 27 | |
dudanian | 2:1d2251574d35 | 28 | void TLC5940Servo::calibrate(float range, float degrees) { |
dudanian | 2:1d2251574d35 | 29 | for (int i = 0; i < 16 * number; i++) |
dudanian | 2:1d2251574d35 | 30 | servos[i].calibrate(range, degrees); |
dudanian | 0:9fc434ff7a03 | 31 | } |
dudanian | 0:9fc434ff7a03 | 32 | |
dudanian | 2:1d2251574d35 | 33 | TLC5940Servo::Servo& TLC5940Servo::operator[](int index) { |
dudanian | 2:1d2251574d35 | 34 | newData = true; |
dudanian | 2:1d2251574d35 | 35 | return servos[index]; |
dudanian | 2:1d2251574d35 | 36 | } |
dudanian | 2:1d2251574d35 | 37 | |
dudanian | 2:1d2251574d35 | 38 | // most complicated method, heavily commented |
dudanian | 2:1d2251574d35 | 39 | void TLC5940Servo::reset() { |
dudanian | 0:9fc434ff7a03 | 40 | gsclk.write(0); // turn off gsclk |
dudanian | 0:9fc434ff7a03 | 41 | blank = 1; // start reset |
dudanian | 2:1d2251574d35 | 42 | |
dudanian | 0:9fc434ff7a03 | 43 | // latch data if new data was written |
dudanian | 0:9fc434ff7a03 | 44 | if (need_xlat) { |
dudanian | 0:9fc434ff7a03 | 45 | xlat = 1; |
dudanian | 0:9fc434ff7a03 | 46 | xlat = 0; |
dudanian | 2:1d2251574d35 | 47 | |
dudanian | 0:9fc434ff7a03 | 48 | need_xlat = false; |
dudanian | 0:9fc434ff7a03 | 49 | } |
dudanian | 2:1d2251574d35 | 50 | |
dudanian | 0:9fc434ff7a03 | 51 | blank = 0; // turn off reset |
dudanian | 0:9fc434ff7a03 | 52 | gsclk.write(.5); // restart gsclk |
dudanian | 0:9fc434ff7a03 | 53 | |
dudanian | 0:9fc434ff7a03 | 54 | if (newData) { |
dudanian | 2:1d2251574d35 | 55 | |
dudanian | 2:1d2251574d35 | 56 | // Send data backwards - this makes servos[0] index correspond to OUT0 |
dudanian | 2:1d2251574d35 | 57 | for (int i = (16 * number) - 1; i >= 0; i--) { |
dudanian | 0:9fc434ff7a03 | 58 | // Get the lower 12 bits of the buffer and send |
dudanian | 2:1d2251574d35 | 59 | spi.write(servos[i].pulsewidth() & 0xFFF); |
dudanian | 0:9fc434ff7a03 | 60 | } |
dudanian | 2:1d2251574d35 | 61 | |
dudanian | 0:9fc434ff7a03 | 62 | // Latch after current GS data is done being displayed |
dudanian | 0:9fc434ff7a03 | 63 | need_xlat = true; |
dudanian | 2:1d2251574d35 | 64 | |
dudanian | 0:9fc434ff7a03 | 65 | // No new data to send (we just sent it!) |
dudanian | 0:9fc434ff7a03 | 66 | newData = false; |
dudanian | 0:9fc434ff7a03 | 67 | } |
dudanian | 2:1d2251574d35 | 68 | } |
dudanian | 2:1d2251574d35 | 69 | |
dudanian | 2:1d2251574d35 | 70 | /** |
dudanian | 2:1d2251574d35 | 71 | * TLC5940 Inner Servo class |
dudanian | 2:1d2251574d35 | 72 | * |
dudanian | 2:1d2251574d35 | 73 | * Helps to abstract some of the details away |
dudanian | 2:1d2251574d35 | 74 | */ |
dudanian | 2:1d2251574d35 | 75 | static float clamp(float value, float min, float max) { |
dudanian | 2:1d2251574d35 | 76 | if(value < min) { |
dudanian | 2:1d2251574d35 | 77 | return min; |
dudanian | 2:1d2251574d35 | 78 | } else if(value > max) { |
dudanian | 2:1d2251574d35 | 79 | return max; |
dudanian | 2:1d2251574d35 | 80 | } else { |
dudanian | 2:1d2251574d35 | 81 | return value; |
dudanian | 2:1d2251574d35 | 82 | } |
dudanian | 2:1d2251574d35 | 83 | } |
dudanian | 2:1d2251574d35 | 84 | |
dudanian | 2:1d2251574d35 | 85 | TLC5940Servo::Servo::Servo() { |
dudanian | 2:1d2251574d35 | 86 | calibrate(); |
dudanian | 2:1d2251574d35 | 87 | write(0.5); |
dudanian | 2:1d2251574d35 | 88 | } |
dudanian | 2:1d2251574d35 | 89 | |
dudanian | 2:1d2251574d35 | 90 | void TLC5940Servo::Servo::write(float percent) { |
dudanian | 2:1d2251574d35 | 91 | float offset = _range * 2.0 * (percent - 0.5); |
dudanian | 2:1d2251574d35 | 92 | _pw = (int)(4095 - ((0.0015 + clamp(offset, -_range, _range))/0.02 * 4096.0)); |
dudanian | 2:1d2251574d35 | 93 | _p = clamp(percent, 0.0, 1.0); |
dudanian | 2:1d2251574d35 | 94 | } |
dudanian | 2:1d2251574d35 | 95 | |
dudanian | 5:56daa8c0697d | 96 | void TLC5940Servo::Servo::position(float degrees) { |
dudanian | 5:56daa8c0697d | 97 | float offset = _range * (degrees / _degrees); |
dudanian | 5:56daa8c0697d | 98 | _pw = (int)(4095 - ((0.0015 + clamp(offset, -_range, _range))/0.02 * 4096.0)); |
dudanian | 5:56daa8c0697d | 99 | } |
dudanian | 5:56daa8c0697d | 100 | |
dudanian | 2:1d2251574d35 | 101 | void TLC5940Servo::Servo::calibrate(float range, float degrees) { |
dudanian | 2:1d2251574d35 | 102 | _range = range; |
dudanian | 2:1d2251574d35 | 103 | _degrees = degrees; |
dudanian | 2:1d2251574d35 | 104 | } |
dudanian | 2:1d2251574d35 | 105 | |
dudanian | 2:1d2251574d35 | 106 | float TLC5940Servo::Servo::read() { |
dudanian | 2:1d2251574d35 | 107 | return _p; |
dudanian | 2:1d2251574d35 | 108 | } |
dudanian | 2:1d2251574d35 | 109 | |
dudanian | 2:1d2251574d35 | 110 | int TLC5940Servo::Servo::pulsewidth() { |
dudanian | 2:1d2251574d35 | 111 | return _pw; |
dudanian | 2:1d2251574d35 | 112 | } |
dudanian | 2:1d2251574d35 | 113 | |
dudanian | 2:1d2251574d35 | 114 | TLC5940Servo::Servo& TLC5940Servo::Servo::operator= (float percent) { |
dudanian | 2:1d2251574d35 | 115 | write(percent); |
dudanian | 2:1d2251574d35 | 116 | return *this; |
dudanian | 2:1d2251574d35 | 117 | } |
dudanian | 2:1d2251574d35 | 118 | |
dudanian | 5:56daa8c0697d | 119 | TLC5940Servo::Servo& TLC5940Servo::Servo::operator= (TLC5940Servo::Servo& rhs) { |
dudanian | 5:56daa8c0697d | 120 | write(rhs.read()); |
dudanian | 5:56daa8c0697d | 121 | return *this; |
dudanian | 5:56daa8c0697d | 122 | } |
dudanian | 5:56daa8c0697d | 123 | |
dudanian | 2:1d2251574d35 | 124 | TLC5940Servo::Servo::operator float() { |
dudanian | 2:1d2251574d35 | 125 | return read(); |
dudanian | 2:1d2251574d35 | 126 | } |