Interface the RenBed with a simple optical linear encoder, using X1 encoding.
Dependencies: SevenSegmentDisplay mbed
This is an example of a copper strip-board design for an optical linear encoder (IRED), and how it is wired up to the Renbed on a breadboard:
The trimmer potentiometer is used to vary the current through the IRED LEDs, in order to balance out the two output signals.
main.cpp@1:83e238178956, 2016-09-08 (annotated)
- Committer:
- elijahorr
- Date:
- Thu Sep 08 07:15:57 2016 +0000
- Revision:
- 1:83e238178956
- Parent:
- 0:c71cc517659b
first issue
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
elijahorr | 1:83e238178956 | 1 | /******************************************************************************* |
elijahorr | 1:83e238178956 | 2 | * Program to interface RenBed to a simple optical linear encoder * |
elijahorr | 1:83e238178956 | 3 | * Copyright (c) 2016 Elijah Orr * |
elijahorr | 1:83e238178956 | 4 | * * |
elijahorr | 1:83e238178956 | 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy * |
elijahorr | 1:83e238178956 | 6 | * of this software and associated documentation files (the "Software"), to deal* |
elijahorr | 1:83e238178956 | 7 | * in the Software without restriction, including without limitation the rights * |
elijahorr | 1:83e238178956 | 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * |
elijahorr | 1:83e238178956 | 9 | * copies of the Software, and to permit persons to whom the Software is * |
elijahorr | 1:83e238178956 | 10 | * furnished to do so, subject to the following conditions: * |
elijahorr | 1:83e238178956 | 11 | * * |
elijahorr | 1:83e238178956 | 12 | * The above copyright notice and this permission notice shall be included in * |
elijahorr | 1:83e238178956 | 13 | * all copies or substantial portions of the Software. * |
elijahorr | 1:83e238178956 | 14 | * * |
elijahorr | 1:83e238178956 | 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * |
elijahorr | 1:83e238178956 | 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * |
elijahorr | 1:83e238178956 | 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * |
elijahorr | 1:83e238178956 | 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * |
elijahorr | 1:83e238178956 | 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,* |
elijahorr | 1:83e238178956 | 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * |
elijahorr | 1:83e238178956 | 21 | * THE SOFTWARE. * |
elijahorr | 1:83e238178956 | 22 | * * |
elijahorr | 1:83e238178956 | 23 | * Encoder * |
elijahorr | 1:83e238178956 | 24 | * * |
elijahorr | 1:83e238178956 | 25 | * V1.0 08/09/2016 First issue of code Elijah Orr * |
elijahorr | 1:83e238178956 | 26 | *******************************************************************************/ |
elijahorr | 1:83e238178956 | 27 | |
elijahorr | 0:c71cc517659b | 28 | #include "mbed.h" |
elijahorr | 0:c71cc517659b | 29 | #include "SevenSegmentDisplay.h" |
elijahorr | 0:c71cc517659b | 30 | |
elijahorr | 1:83e238178956 | 31 | /* define values for high and low analog signals, used to compare to ADC values. 0.56 indicates that the low level is set to 56% of 3.3V. |
elijahorr | 1:83e238178956 | 32 | * you will likely need to change these values for your particular encoder */ |
elijahorr | 0:c71cc517659b | 33 | #define SIGNAL_LOW 0.56 |
elijahorr | 0:c71cc517659b | 34 | #define SIGNAL_HIGH 0.60 |
elijahorr | 0:c71cc517659b | 35 | |
elijahorr | 0:c71cc517659b | 36 | class Encoder{ |
elijahorr | 1:83e238178956 | 37 | |
elijahorr | 1:83e238178956 | 38 | //public functions and variables can be accessed from anywhere |
elijahorr | 0:c71cc517659b | 39 | public: |
elijahorr | 0:c71cc517659b | 40 | |
elijahorr | 0:c71cc517659b | 41 | /**************************************************************************************************************** |
elijahorr | 0:c71cc517659b | 42 | * Encoder - class constructor, used to declare an instant of the Encoder class. * |
elijahorr | 0:c71cc517659b | 43 | * * |
elijahorr | 0:c71cc517659b | 44 | * Parameters: PinA - analog channel A, PinB - analog channel B, OutputA - digital output for channel A, * |
elijahorr | 0:c71cc517659b | 45 | * OutputB - digital output for channel B, InputA - input for the feedback of digital channel A, * |
elijahorr | 0:c71cc517659b | 46 | * InputB - input for the feedback of digital channel B * |
elijahorr | 0:c71cc517659b | 47 | * * |
elijahorr | 0:c71cc517659b | 48 | * Returns: none * |
elijahorr | 0:c71cc517659b | 49 | ****************************************************************************************************************/ |
elijahorr | 0:c71cc517659b | 50 | Encoder(PinName pinA, PinName pinB, PinName OutputA, PinName OutputB, PinName InputA, PinName InputB) : |
elijahorr | 0:c71cc517659b | 51 | SignalA(pinA), SignalB(pinB), SquaredA(OutputA), SquaredB(OutputB), SquaredA_in(InputA), SquaredB_in(InputB){ |
elijahorr | 0:c71cc517659b | 52 | |
elijahorr | 0:c71cc517659b | 53 | //attach ADC function to ticker, will be called every 75 microseconds (pretty much as often as possible) |
elijahorr | 0:c71cc517659b | 54 | ProcessCycle.attach_us(this, &Encoder::ConvertSignals, 75); |
elijahorr | 0:c71cc517659b | 55 | //attach rising_A function to rising edge interrupt on the feedback signal for digital channel A |
elijahorr | 0:c71cc517659b | 56 | SquaredA_in.rise(this, &Encoder::rising_A); |
elijahorr | 0:c71cc517659b | 57 | //attach falling_A function to falling edge interrupt on the feedback signal for digital channel B |
elijahorr | 0:c71cc517659b | 58 | SquaredA_in.fall(this, &Encoder::falling_A); |
elijahorr | 0:c71cc517659b | 59 | } |
elijahorr | 0:c71cc517659b | 60 | |
elijahorr | 0:c71cc517659b | 61 | /******************************************************************************* |
elijahorr | 0:c71cc517659b | 62 | * get_count - returns the current encoder counter value |
elijahorr | 0:c71cc517659b | 63 | * |
elijahorr | 0:c71cc517659b | 64 | * Parameters: none |
elijahorr | 0:c71cc517659b | 65 | * |
elijahorr | 0:c71cc517659b | 66 | * Returns: int - current counter value |
elijahorr | 0:c71cc517659b | 67 | *******************************************************************************/ |
elijahorr | 0:c71cc517659b | 68 | int get_count(void){ |
elijahorr | 0:c71cc517659b | 69 | return count; |
elijahorr | 0:c71cc517659b | 70 | } |
elijahorr | 1:83e238178956 | 71 | |
elijahorr | 1:83e238178956 | 72 | //private functions and variables are only accessable from within the encoder class |
elijahorr | 0:c71cc517659b | 73 | private: |
elijahorr | 0:c71cc517659b | 74 | AnalogIn SignalA; //analog input for signal A |
elijahorr | 0:c71cc517659b | 75 | AnalogIn SignalB; //analog input for signal B |
elijahorr | 0:c71cc517659b | 76 | DigitalOut SquaredA; //digital output for the digital translation of channel A |
elijahorr | 0:c71cc517659b | 77 | DigitalOut SquaredB; //digital output for the digital translation of channel B |
elijahorr | 0:c71cc517659b | 78 | InterruptIn SquaredA_in; //interrupt for the feedback of digital channel A signal |
elijahorr | 0:c71cc517659b | 79 | InterruptIn SquaredB_in; //interrupt for the feedback of digital channel B signal |
elijahorr | 0:c71cc517659b | 80 | Ticker ProcessCycle; //ticker to attach signal converter function to |
elijahorr | 0:c71cc517659b | 81 | |
elijahorr | 0:c71cc517659b | 82 | int count; //variable to store counter value |
elijahorr | 0:c71cc517659b | 83 | |
elijahorr | 0:c71cc517659b | 84 | /******************************************************************************* |
elijahorr | 0:c71cc517659b | 85 | * ConvertSignals - converts the analog signals from the encoder into digital |
elijahorr | 0:c71cc517659b | 86 | * quadrature signals. |
elijahorr | 0:c71cc517659b | 87 | * |
elijahorr | 0:c71cc517659b | 88 | * Parameters: none |
elijahorr | 0:c71cc517659b | 89 | * |
elijahorr | 0:c71cc517659b | 90 | * Returns: none |
elijahorr | 0:c71cc517659b | 91 | *******************************************************************************/ |
elijahorr | 0:c71cc517659b | 92 | void ConvertSignals(void){ |
elijahorr | 0:c71cc517659b | 93 | |
elijahorr | 0:c71cc517659b | 94 | //take readings from the ADC |
elijahorr | 0:c71cc517659b | 95 | float A_reading = SignalA; |
elijahorr | 0:c71cc517659b | 96 | float B_reading = SignalB; |
elijahorr | 0:c71cc517659b | 97 | |
elijahorr | 0:c71cc517659b | 98 | //decision algorithm to decide when to set the digital signals high/low, |
elijahorr | 0:c71cc517659b | 99 | //SIGNAL_LOW and SIGNAL_HIGH are user defined high and low for the analog signals |
elijahorr | 0:c71cc517659b | 100 | if(A_reading < SIGNAL_LOW){ |
elijahorr | 0:c71cc517659b | 101 | SquaredA = 0; |
elijahorr | 0:c71cc517659b | 102 | } |
elijahorr | 0:c71cc517659b | 103 | else if(A_reading > SIGNAL_HIGH){ |
elijahorr | 0:c71cc517659b | 104 | SquaredA = 1; |
elijahorr | 0:c71cc517659b | 105 | } |
elijahorr | 0:c71cc517659b | 106 | |
elijahorr | 0:c71cc517659b | 107 | if(B_reading < SIGNAL_LOW){ |
elijahorr | 0:c71cc517659b | 108 | SquaredB = 0; |
elijahorr | 0:c71cc517659b | 109 | } |
elijahorr | 0:c71cc517659b | 110 | else if(B_reading > SIGNAL_HIGH){ |
elijahorr | 0:c71cc517659b | 111 | SquaredB = 1; |
elijahorr | 0:c71cc517659b | 112 | } |
elijahorr | 0:c71cc517659b | 113 | } |
elijahorr | 0:c71cc517659b | 114 | |
elijahorr | 0:c71cc517659b | 115 | /******************************************************************************* |
elijahorr | 0:c71cc517659b | 116 | * rising_A - interrupt function for rising edges on channel A, decides when |
elijahorr | 0:c71cc517659b | 117 | * the count should be decremented. |
elijahorr | 0:c71cc517659b | 118 | * |
elijahorr | 0:c71cc517659b | 119 | * Parameters: none |
elijahorr | 0:c71cc517659b | 120 | * |
elijahorr | 0:c71cc517659b | 121 | * Returns: none |
elijahorr | 0:c71cc517659b | 122 | *******************************************************************************/ |
elijahorr | 0:c71cc517659b | 123 | |
elijahorr | 0:c71cc517659b | 124 | void rising_A(void){ |
elijahorr | 0:c71cc517659b | 125 | if(SquaredB.read() == 0){ |
elijahorr | 0:c71cc517659b | 126 | count--; |
elijahorr | 0:c71cc517659b | 127 | } |
elijahorr | 0:c71cc517659b | 128 | } |
elijahorr | 0:c71cc517659b | 129 | |
elijahorr | 0:c71cc517659b | 130 | /******************************************************************************* |
elijahorr | 0:c71cc517659b | 131 | * falling_A - interrupt function for rising edges on channel A, decides when |
elijahorr | 0:c71cc517659b | 132 | * the count should be incremented. |
elijahorr | 0:c71cc517659b | 133 | * |
elijahorr | 0:c71cc517659b | 134 | * Parameters: none |
elijahorr | 0:c71cc517659b | 135 | * |
elijahorr | 0:c71cc517659b | 136 | * Returns: none |
elijahorr | 0:c71cc517659b | 137 | *******************************************************************************/ |
elijahorr | 0:c71cc517659b | 138 | |
elijahorr | 0:c71cc517659b | 139 | void falling_A(void){ |
elijahorr | 0:c71cc517659b | 140 | if(SquaredB.read() == 0){ |
elijahorr | 0:c71cc517659b | 141 | count++; |
elijahorr | 0:c71cc517659b | 142 | } |
elijahorr | 0:c71cc517659b | 143 | } |
elijahorr | 0:c71cc517659b | 144 | |
elijahorr | 0:c71cc517659b | 145 | }; |
elijahorr | 0:c71cc517659b | 146 | |
elijahorr | 0:c71cc517659b | 147 | /* Create an instance of the class Encoder, which will be called lollipop (because of the lolly stick height control). |
elijahorr | 0:c71cc517659b | 148 | * Pins must be given in the order specified in the constructor, and analog inputs must be ADC pins */ |
elijahorr | 0:c71cc517659b | 149 | Encoder lollipop(P0_15, P0_22, P0_17, P0_7, P1_14, P0_1); |
elijahorr | 0:c71cc517659b | 150 | SevenSegmentDisplay display(INSTANT); //create instance of SevenSegmentDisplay to drive the 7 segs |
elijahorr | 0:c71cc517659b | 151 | |
elijahorr | 0:c71cc517659b | 152 | /******************************************************************************* |
elijahorr | 0:c71cc517659b | 153 | * main - this is the main program routine. The encoder class is working in the |
elijahorr | 0:c71cc517659b | 154 | * background, as the constructor was called above. |
elijahorr | 0:c71cc517659b | 155 | * |
elijahorr | 0:c71cc517659b | 156 | * Parameters: none |
elijahorr | 0:c71cc517659b | 157 | * |
elijahorr | 0:c71cc517659b | 158 | * Returns: none |
elijahorr | 0:c71cc517659b | 159 | *******************************************************************************/ |
elijahorr | 0:c71cc517659b | 160 | int main(){ |
elijahorr | 0:c71cc517659b | 161 | //a while loop with the parameter 1 will always execute, and repeat forever |
elijahorr | 0:c71cc517659b | 162 | while(1){ |
elijahorr | 0:c71cc517659b | 163 | int counter = lollipop.get_count(); //get the current encoder count value |
elijahorr | 0:c71cc517659b | 164 | |
elijahorr | 0:c71cc517659b | 165 | // if the counter value is positive, seperate into individual digits and drive displays |
elijahorr | 0:c71cc517659b | 166 | if(counter >= 0){ |
elijahorr | 0:c71cc517659b | 167 | display.FadeMode(INSTANT); |
elijahorr | 0:c71cc517659b | 168 | int first_digit = counter/10; |
elijahorr | 0:c71cc517659b | 169 | int second_digit = counter%10; |
elijahorr | 0:c71cc517659b | 170 | display.DisplayDigits(first_digit, second_digit); |
elijahorr | 0:c71cc517659b | 171 | } |
elijahorr | 0:c71cc517659b | 172 | //if the counter value is negative, make the display flash while displaying value |
elijahorr | 0:c71cc517659b | 173 | else if(counter < 0){ |
elijahorr | 0:c71cc517659b | 174 | display.FadeMode(FLASH); |
elijahorr | 0:c71cc517659b | 175 | display.FlashRate(500); |
elijahorr | 0:c71cc517659b | 176 | counter = counter*-1; |
elijahorr | 0:c71cc517659b | 177 | int first_digit = counter/10; |
elijahorr | 0:c71cc517659b | 178 | int second_digit = counter%10; |
elijahorr | 0:c71cc517659b | 179 | display.DisplayDigits(first_digit, second_digit); |
elijahorr | 0:c71cc517659b | 180 | } |
elijahorr | 0:c71cc517659b | 181 | wait(0.2); |
elijahorr | 0:c71cc517659b | 182 | } |
elijahorr | 0:c71cc517659b | 183 | } |
elijahorr | 0:c71cc517659b | 184 |