Project

General

Profile

Statistics
| Branch: | Revision:

robobuggy / arduino / InterruptRCRecieverReference / RCArduinoFastLib.h @ c5d6b0e8

History | View | Annotate | Download (6.67 KB)

1
/*****************************************************************************************************************************/
2
// RCArduinoFastLib by DuaneB is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
3
//
4
// http://rcarduino.blogspot.com
5
//
6
/*****************************************************************************************************************************/
7

    
8
#include "Arduino.h"
9

    
10
// COMMENT OR UNCOMMENT THIS LINE TO ENABLE THE SECOND BANK OF SERVOS
11
//#define MORE_SERVOS_PLEASE 1
12

    
13
// the first bank of servos uses OC1A - this will disable PWM on digital pin 9 - a small price for 10 fast and smooth servos
14
// the second bank of servos uses OC1B - this will disable PWM on digital pin 10 - a small price for 10 more fast and smooth servos
15

    
16
// The library blindly pulses all ten servos one and after another
17
// If you change the RC_CHANNEL_OUT_COUNT to 4 servos, the library will pulse them more frequently than
18
// it can ten -
19
// 10 servos at 1500us = 15ms = 66Hz
20
// 4 Servos at 1500us = 6ms = 166Hz
21
// if you wanted to go even higher, run two servos on each timer
22
// 2 Servos at 1500us = 3ms = 333Hz
23
//
24
// You might not want a high refresh rate though, so the setFrameSpace function is provided for you to
25
// add a pause before the library begins its next run through the servos
26
// for 50 hz, the pause should be to (20,000 - (RC_CHANNEL_OUT_COUNT * 2000))
27

    
28
// Change to set the number of servos/ESCs
29
#define RC_CHANNEL_OUT_COUNT 4
30

    
31
#if defined (MORE_SERVOS_PLEASE)
32
#define RCARDUINO_MAX_SERVOS (RC_CHANNEL_OUT_COUNT*2)
33
#else
34
#define RCARDUINO_MAX_SERVOS (RC_CHANNEL_OUT_COUNT)
35
#endif
36

    
37
// Minimum and Maximum servo pulse widths, you could change these,
38
// Check the servo library and use that range if you prefer
39
#define RCARDUINO_SERIAL_SERVO_MIN 1000
40
#define RCARDUINO_SERIAL_SERVO_MAX 2000
41
#define RCARDUINO_SERIAL_SERVO_DEFAULT 1500
42

    
43
#define RC_CHANNELS_NOPORT 0
44
#define RC_CHANNELS_PORTB 1
45
#define RC_CHANNELS_PORTC 2
46
#define RC_CHANNELS_PORTD 3
47
#define RC_CHANNELS_NOPIN 255
48

    
49
//////////////////////////////////////////////////////////////////////////////////////////////////////////
50
//
51
// CRCArduinoFastServos
52
//
53
// A class for generating signals in combination with a 4017 Counter
54
//
55
// Output upto 10 Servo channels using just digital pins 9 and 12
56
// 9 generates the clock signal and must be connected to the clock pin of the 4017
57
// 12 generates the reset pulse and must be connected to the master reset pin of the 4017
58
//
59
// The class uses Timer1, as this prevents use with the servo library
60
// The class uses pins 9 and 12
61
// The class does not adjust the servo frame to account for variations in pulse width,
62
// on the basis that many RC transmitters and receivers designed specifically to operate with servos
63
// output signals between 50 and 100hz, this is the same range as the library
64
//
65
// Use of an additional pin would provide for error detection, however using pin 12 to pulse master reset
66
// at the end of every frame means that the system is essentially self correcting
67
//
68
// Note
69
// This is a simplified derivative of the Arduino Servo Library created by Michael Margolis
70
// The simplification has been possible by moving some of the flexibility provided by the Servo library
71
// from software to hardware.
72
//
73
////////////////////////////////////////////////////////////////////////////////////////////////////////////
74

    
75

    
76
class CRCArduinoFastServos
77
{
78
  public:
79
    static void setup();
80

    
81
    // configures timer1
82
    static void begin();
83

    
84
    // called by the timer interrupt service routine, see the cpp file for details.
85
    static void OCR1A_ISR();
86

    
87
#if defined(MORE_SERVOS_PLEASE)
88
    static void OCR1B_ISR();
89
#endif
90

    
91
    // called to set the pulse width for a specific channel, pulse widths are in microseconds - degrees are for wimps !
92
    static void attach(uint8_t nChannel,uint8_t nPin);
93
    static void writeMicroseconds(uint8_t nChannel,uint16_t nMicroseconds);
94
    static void setFrameSpaceA(uint8_t sChannel,uint16_t unMicroseconds);
95
    static void setFrameSpaceB(uint8_t sChannel,uint16_t unMicroseconds);
96

    
97
  protected:
98
    class CPortPin
99
    {
100
      public:
101
        //uint8_t m_sPort;
102
        volatile unsigned char *m_pPort;
103
        uint8_t m_sPinMask;
104
        uint16_t m_unPulseWidth;
105
    };
106

    
107
    // this sets the value of the timer1 output compare register to a point in the future
108
    // based on the required pulse with for the current servo
109
    static void setOutputTimerForPulseDurationA() __attribute__((always_inline));
110

    
111

    
112
    static void setChannelPinLowA(uint8_t sChannel) __attribute__((always_inline));
113
    static void setCurrentChannelPinHighA();
114

    
115
    // Easy to optimise this, but lets keep it readable instead, its short enough.
116
    static volatile uint8_t*  getPortFromPin(uint8_t sPin) __attribute__((always_inline));
117
    static uint8_t getPortPinMaskFromPin(uint8_t sPin) __attribute__((always_inline));
118

    
119
    // Records the current output channel values in timer ticks
120
    // Manually set by calling writeChannel, the function adjusts from
121
    // user supplied micro seconds to timer ticks
122
    volatile static CPortPin m_ChannelOutA[RC_CHANNEL_OUT_COUNT];
123
    // current output channel, used by the timer ISR to track which channel is being generated
124
    static uint8_t m_sCurrentOutputChannelA;
125

    
126
#if defined(MORE_SERVOS_PLEASE)
127
    // Optional channel B for servo number 10 to 19
128
    volatile static CPortPin m_ChannelOutB[RC_CHANNEL_OUT_COUNT];
129
    static uint8_t m_sCurrentOutputChannelB;
130
    static void setOutputTimerForPulseDurationB();
131

    
132
    static void setChannelPinLowB(uint8_t sChannel) __attribute__((always_inline));
133
    static void setCurrentChannelPinHighB() __attribute__((always_inline));
134
#endif
135

    
136
    // two helper functions to convert between timer values and microseconds
137
    static uint16_t ticksToMicroseconds(uint16_t unTicks) __attribute__((always_inline));
138
    static uint16_t microsecondsToTicks(uint16_t unMicroseconds) __attribute__((always_inline));
139
};
140

    
141
// Change to set the number of channels in PPM Input stream
142
#define RC_CHANNEL_IN_COUNT 3
143
// two ticks per us, 3000 us * 2 ticks = 6000 minimum frame space
144
#define MINIMUM_FRAME_SPACE 6000
145
#define MAXIMUM_PULSE_SPACE 5000
146

    
147
class CRCArduinoPPMChannels
148
{
149
  public:
150
    static void begin();
151
    static void INT0ISR();
152
    static uint16_t getChannel(uint8_t nChannel);
153
    static uint8_t getSynchErrorCounter();
154

    
155
    protected:
156
    static void forceResynch();
157

    
158
    static volatile uint16_t m_unChannelSignalIn[RC_CHANNEL_IN_COUNT];
159
    static uint8_t m_sCurrentInputChannel;
160

    
161
    static uint16_t m_unChannelRiseTime;
162
    static volatile uint8_t m_sOutOfSynchErrorCounter;
163
};