EMG control program for use with Olimex ECG/EMG boards. Interacts with my OlimexChart Matlab programs to produce ECG or EMG strip chart displays. Also controls a relay for my Human-Human interface activity.
Fork of TimeTests by
main.cpp@1:d835bb04d8f0, 2017-10-31 (annotated)
- Committer:
- CSTritt
- Date:
- Tue Oct 31 21:20:05 2017 +0000
- Revision:
- 1:d835bb04d8f0
- Parent:
- 0:cbee9f6e3fe9
- Child:
- 2:60d9595f9981
Initial Nucleo version.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
CSTritt | 0:cbee9f6e3fe9 | 1 | /* |
CSTritt | 1:d835bb04d8f0 | 2 | Project: EMG_Control |
CSTritt | 0:cbee9f6e3fe9 | 3 | File: main.cpp |
CSTritt | 1:d835bb04d8f0 | 4 | Created by: Dr. C. S. Tritt |
CSTritt | 1:d835bb04d8f0 | 5 | Last revision on: 9/30/17 (v. 1.0) |
CSTritt | 0:cbee9f6e3fe9 | 6 | |
CSTritt | 1:d835bb04d8f0 | 7 | EMG control program for use with Olimex ECG/EMG shields and active low relays. |
CSTritt | 1:d835bb04d8f0 | 8 | For use with my Matlab OlimexChart4.m program. Use for my Human-Human |
CSTritt | 1:d835bb04d8f0 | 9 | interface activity. See external documentation for more information. |
CSTritt | 0:cbee9f6e3fe9 | 10 | |
CSTritt | 0:cbee9f6e3fe9 | 11 | */ |
CSTritt | 0:cbee9f6e3fe9 | 12 | #include "mbed.h" |
CSTritt | 1:d835bb04d8f0 | 13 | // Needed for isdigit function. |
CSTritt | 1:d835bb04d8f0 | 14 | #include <ctype.h> |
CSTritt | 0:cbee9f6e3fe9 | 15 | |
CSTritt | 1:d835bb04d8f0 | 16 | // Global Constants... |
CSTritt | 1:d835bb04d8f0 | 17 | // EMG input pin (set by Olimex jumper). |
CSTritt | 1:d835bb04d8f0 | 18 | #define EMG_IN_PIN A0 |
CSTritt | 1:d835bb04d8f0 | 19 | // Relay digital output pin. |
CSTritt | 1:d835bb04d8f0 | 20 | #define RELAY_OUT_PIN D12 |
CSTritt | 0:cbee9f6e3fe9 | 21 | |
CSTritt | 1:d835bb04d8f0 | 22 | // ID String |
CSTritt | 1:d835bb04d8f0 | 23 | const char idString[] = {"EMG Control Nucleo v. 1.0"}; |
CSTritt | 1:d835bb04d8f0 | 24 | // Buad rate, must be matched in Serial Monitor/Matlab. 115200 works. |
CSTritt | 1:d835bb04d8f0 | 25 | const int PSPD = 115200; |
CSTritt | 1:d835bb04d8f0 | 26 | // Default wait time between samples (mS). 50 Hz. |
CSTritt | 1:d835bb04d8f0 | 27 | const int WAIT = 20; |
CSTritt | 1:d835bb04d8f0 | 28 | // Default hold time for simulator output (mS). |
CSTritt | 1:d835bb04d8f0 | 29 | const int HOLD = 500; |
CSTritt | 1:d835bb04d8f0 | 30 | // Default decay factor (larger is faster). |
CSTritt | 1:d835bb04d8f0 | 31 | const int DECAY = 2; |
CSTritt | 1:d835bb04d8f0 | 32 | // Default mean of EMG signal (usually around 512). |
CSTritt | 1:d835bb04d8f0 | 33 | const int MEAN = 512; |
CSTritt | 1:d835bb04d8f0 | 34 | // Default scale factor (larger lowers sum). |
CSTritt | 1:d835bb04d8f0 | 35 | const int SCALE = 4; |
CSTritt | 1:d835bb04d8f0 | 36 | // Default threshold for relay activation. |
CSTritt | 1:d835bb04d8f0 | 37 | const float THRESHOLD = 512; |
CSTritt | 1:d835bb04d8f0 | 38 | // Default output code: 1 = EMG, 2 = RSum |
CSTritt | 1:d835bb04d8f0 | 39 | const int CODE = 1; |
CSTritt | 0:cbee9f6e3fe9 | 40 | |
CSTritt | 1:d835bb04d8f0 | 41 | // Global mbed objects... |
CSTritt | 1:d835bb04d8f0 | 42 | // Relay output object & pin. |
CSTritt | 1:d835bb04d8f0 | 43 | DigitalOut relay(RELAY_OUT_PIN); |
CSTritt | 1:d835bb04d8f0 | 44 | // EMG analogy input object & pin. |
CSTritt | 1:d835bb04d8f0 | 45 | AnalogIn oliVal(EMG_IN_PIN); |
CSTritt | 1:d835bb04d8f0 | 46 | // PC serial object pins & baud rate. |
CSTritt | 1:d835bb04d8f0 | 47 | Serial pc(USBTX, USBRX, PSPD); |
CSTritt | 1:d835bb04d8f0 | 48 | // Ticker for millisecond clock. |
CSTritt | 1:d835bb04d8f0 | 49 | Ticker milliTick; |
CSTritt | 1:d835bb04d8f0 | 50 | |
CSTritt | 1:d835bb04d8f0 | 51 | // Global variable... |
CSTritt | 1:d835bb04d8f0 | 52 | volatile unsigned int millis = 0; // Milliseconds since reset for timestamp. |
CSTritt | 1:d835bb04d8f0 | 53 | |
CSTritt | 1:d835bb04d8f0 | 54 | // Function declarations... |
CSTritt | 1:d835bb04d8f0 | 55 | // Millisecond clock callback/ISR. |
CSTritt | 1:d835bb04d8f0 | 56 | void milliIncr(void); |
CSTritt | 1:d835bb04d8f0 | 57 | // Converts ASCII digit code to corresponding int value. |
CSTritt | 1:d835bb04d8f0 | 58 | int dig2Int(char myChar); |
CSTritt | 0:cbee9f6e3fe9 | 59 | |
CSTritt | 0:cbee9f6e3fe9 | 60 | int main() |
CSTritt | 0:cbee9f6e3fe9 | 61 | { |
CSTritt | 1:d835bb04d8f0 | 62 | relay.write(1); // Assure active low relay is off at start. |
CSTritt | 1:d835bb04d8f0 | 63 | // Announce program identity. |
CSTritt | 1:d835bb04d8f0 | 64 | pc.printf("%s\n", idString); |
CSTritt | 1:d835bb04d8f0 | 65 | |
CSTritt | 1:d835bb04d8f0 | 66 | // Define and initialize important variables... |
CSTritt | 1:d835bb04d8f0 | 67 | unsigned int actTime = 0; // Most recent relay activation time (mS). |
CSTritt | 1:d835bb04d8f0 | 68 | float waitTime = (float) WAIT / 1000.f; // Wait time between samples (S). |
CSTritt | 1:d835bb04d8f0 | 69 | |
CSTritt | 1:d835bb04d8f0 | 70 | int hold = HOLD; // Hold time for stimulator output (mS). |
CSTritt | 1:d835bb04d8f0 | 71 | int decay = DECAY; // Decay factor (larger is faster). |
CSTritt | 1:d835bb04d8f0 | 72 | int mean = MEAN; // Mean of EMG signal (usually around 512). |
CSTritt | 1:d835bb04d8f0 | 73 | int scale = SCALE; // Scale factor (larger lowers sum). |
CSTritt | 1:d835bb04d8f0 | 74 | int threshold = THRESHOLD; // Threshold for relay activation. |
CSTritt | 1:d835bb04d8f0 | 75 | int rSum = 0; // Initial decaying running sum of squared activity. |
CSTritt | 1:d835bb04d8f0 | 76 | |
CSTritt | 1:d835bb04d8f0 | 77 | int parmVal = 0; // Initial command parameter value. |
CSTritt | 1:d835bb04d8f0 | 78 | int code = CODE; // Output code: 1 = EMG, 2 = Running Sum. |
CSTritt | 1:d835bb04d8f0 | 79 | bool go = false; // Flag for sending data. Start not sending. |
CSTritt | 1:d835bb04d8f0 | 80 | |
CSTritt | 1:d835bb04d8f0 | 81 | milliTick.attach_us(milliIncr, 1000); // Attach ISR to mS clock ticker. |
CSTritt | 0:cbee9f6e3fe9 | 82 | while(true) { |
CSTritt | 1:d835bb04d8f0 | 83 | if (pc.readable()) { // Process command text... |
CSTritt | 1:d835bb04d8f0 | 84 | char myChar = pc.getc(); // Read a character. |
CSTritt | 1:d835bb04d8f0 | 85 | pc.putc(myChar); // Echo the character. |
CSTritt | 1:d835bb04d8f0 | 86 | if (isdigit(myChar)) { // Process the digit... |
CSTritt | 1:d835bb04d8f0 | 87 | parmVal = 10 * parmVal + dig2Int(myChar); // Shift & add value. |
CSTritt | 1:d835bb04d8f0 | 88 | } else { // Deal with command code letters... |
CSTritt | 1:d835bb04d8f0 | 89 | switch (myChar) { // Add cases below for more commands. |
CSTritt | 1:d835bb04d8f0 | 90 | case 'd': // Change decay value. |
CSTritt | 1:d835bb04d8f0 | 91 | if (parmVal == 0) parmVal = DECAY; // Use default. |
CSTritt | 1:d835bb04d8f0 | 92 | decay = parmVal; // Change decay. |
CSTritt | 1:d835bb04d8f0 | 93 | break; // All but last case needs a break. |
CSTritt | 1:d835bb04d8f0 | 94 | case 'g': // Switch into go (read & output data) mode. |
CSTritt | 1:d835bb04d8f0 | 95 | go = true; |
CSTritt | 1:d835bb04d8f0 | 96 | break; // All but last case needs a break. |
CSTritt | 1:d835bb04d8f0 | 97 | case 'h': // Change hold value. |
CSTritt | 1:d835bb04d8f0 | 98 | if (parmVal == 0) parmVal = HOLD; // Use default. |
CSTritt | 1:d835bb04d8f0 | 99 | hold = parmVal; // Change hold. |
CSTritt | 1:d835bb04d8f0 | 100 | case 'i': // Send program ID. |
CSTritt | 1:d835bb04d8f0 | 101 | pc.printf("%s\n", idString); |
CSTritt | 1:d835bb04d8f0 | 102 | break; // All but last case needs a break. |
CSTritt | 1:d835bb04d8f0 | 103 | case 'm': // Change expected mean value. |
CSTritt | 1:d835bb04d8f0 | 104 | if (parmVal == 0) parmVal = MEAN; // Use default. |
CSTritt | 1:d835bb04d8f0 | 105 | mean = parmVal; // Change mean. |
CSTritt | 1:d835bb04d8f0 | 106 | break; // All but last case needs a break. |
CSTritt | 1:d835bb04d8f0 | 107 | case 'o': // Change output code value. |
CSTritt | 1:d835bb04d8f0 | 108 | if (parmVal == 0) parmVal = CODE; // Use default. |
CSTritt | 1:d835bb04d8f0 | 109 | code = parmVal; // Change code. |
CSTritt | 1:d835bb04d8f0 | 110 | break; // All but last case needs a break. |
CSTritt | 1:d835bb04d8f0 | 111 | case 's': // Change scale factor value. |
CSTritt | 1:d835bb04d8f0 | 112 | if (parmVal == 0) parmVal = SCALE; // Use default. |
CSTritt | 1:d835bb04d8f0 | 113 | scale = parmVal; // Change scale. |
CSTritt | 1:d835bb04d8f0 | 114 | break; // All but last case needs a break. |
CSTritt | 1:d835bb04d8f0 | 115 | case 't': // Change activation threshold value. |
CSTritt | 1:d835bb04d8f0 | 116 | if (parmVal == 0) parmVal = THRESHOLD; // Use default. |
CSTritt | 1:d835bb04d8f0 | 117 | threshold = parmVal; // Change threshold. |
CSTritt | 1:d835bb04d8f0 | 118 | break; // All but last case needs a break. |
CSTritt | 1:d835bb04d8f0 | 119 | case 'w': // Change between sample wait value (S). |
CSTritt | 1:d835bb04d8f0 | 120 | if (parmVal == 0) parmVal = WAIT; // Use default. |
CSTritt | 1:d835bb04d8f0 | 121 | waitTime = (float) parmVal / 1000.f; // Change waitTime. |
CSTritt | 1:d835bb04d8f0 | 122 | break; // All but last case needs a break. |
CSTritt | 1:d835bb04d8f0 | 123 | case 'x': // Send data marker (time & minus parmVal). |
CSTritt | 1:d835bb04d8f0 | 124 | // Also use for debugging command processing. |
CSTritt | 1:d835bb04d8f0 | 125 | pc.printf("%u, %d\n", millis, -parmVal); |
CSTritt | 1:d835bb04d8f0 | 126 | break; // All but last case needs a break. |
CSTritt | 1:d835bb04d8f0 | 127 | case 'z': // Switch out of go (read & output data) mode. |
CSTritt | 1:d835bb04d8f0 | 128 | go = false; |
CSTritt | 1:d835bb04d8f0 | 129 | break; // All but last case needs a break. |
CSTritt | 1:d835bb04d8f0 | 130 | } |
CSTritt | 1:d835bb04d8f0 | 131 | parmVal = 0; // Reset parmVal to zero for next command. |
CSTritt | 1:d835bb04d8f0 | 132 | } |
CSTritt | 1:d835bb04d8f0 | 133 | } // End of command text processing. |
CSTritt | 1:d835bb04d8f0 | 134 | if (go) { // Complete go mode tasks... |
CSTritt | 1:d835bb04d8f0 | 135 | // Read and process EMG data... |
CSTritt | 1:d835bb04d8f0 | 136 | float EMG_float = oliVal.read(); // Read & save analog Olimex value. |
CSTritt | 1:d835bb04d8f0 | 137 | unsigned int time = millis; // Save read time. |
CSTritt | 1:d835bb04d8f0 | 138 | int EMG_int = (int)(1023.f * EMG_float); // Scale EMG reading. |
CSTritt | 1:d835bb04d8f0 | 139 | int diff =EMG_int - mean; // Center on specified mean. |
CSTritt | 1:d835bb04d8f0 | 140 | // Accumulate decaying running sum of squares (filtered value). |
CSTritt | 1:d835bb04d8f0 | 141 | rSum = rSum/decay + diff*diff/scale; |
CSTritt | 1:d835bb04d8f0 | 142 | |
CSTritt | 1:d835bb04d8f0 | 143 | // Activate relay if appropriate... |
CSTritt | 1:d835bb04d8f0 | 144 | if (time - actTime > hold) { |
CSTritt | 1:d835bb04d8f0 | 145 | relay.write(0); // Activate active low relay. |
CSTritt | 1:d835bb04d8f0 | 146 | actTime = time; // Save activation time. |
CSTritt | 1:d835bb04d8f0 | 147 | } else { |
CSTritt | 1:d835bb04d8f0 | 148 | relay.write(1); // Deactivate active low relay. |
CSTritt | 1:d835bb04d8f0 | 149 | } |
CSTritt | 1:d835bb04d8f0 | 150 | |
CSTritt | 1:d835bb04d8f0 | 151 | // Send data to PC... |
CSTritt | 1:d835bb04d8f0 | 152 | pc.printf("%u, ", time); // Send the time and a comma. |
CSTritt | 1:d835bb04d8f0 | 153 | if (code == 1) { |
CSTritt | 1:d835bb04d8f0 | 154 | pc.printf("%d\n", EMG_int); |
CSTritt | 1:d835bb04d8f0 | 155 | } else if (code == 2) { |
CSTritt | 1:d835bb04d8f0 | 156 | pc.printf("%d\n", rSum); |
CSTritt | 1:d835bb04d8f0 | 157 | } else { // Invalid code value. |
CSTritt | 1:d835bb04d8f0 | 158 | pc.printf("?\n"); |
CSTritt | 1:d835bb04d8f0 | 159 | } |
CSTritt | 1:d835bb04d8f0 | 160 | } else if (!relay.read()){ |
CSTritt | 1:d835bb04d8f0 | 161 | relay.write(1); // Deactivate relay in |
CSTritt | 0:cbee9f6e3fe9 | 162 | } |
CSTritt | 1:d835bb04d8f0 | 163 | wait(waitTime); |
CSTritt | 0:cbee9f6e3fe9 | 164 | } |
CSTritt | 0:cbee9f6e3fe9 | 165 | } |
CSTritt | 0:cbee9f6e3fe9 | 166 | |
CSTritt | 0:cbee9f6e3fe9 | 167 | void milliIncr(void) // Call back that adds millisconds to millis. |
CSTritt | 0:cbee9f6e3fe9 | 168 | { |
CSTritt | 0:cbee9f6e3fe9 | 169 | millis++; // Increment by 10 milliseconds each time. |
CSTritt | 1:d835bb04d8f0 | 170 | } |
CSTritt | 1:d835bb04d8f0 | 171 | |
CSTritt | 1:d835bb04d8f0 | 172 | int dig2Int(char myChar) |
CSTritt | 1:d835bb04d8f0 | 173 | { |
CSTritt | 1:d835bb04d8f0 | 174 | /* |
CSTritt | 1:d835bb04d8f0 | 175 | Utility function for Converting a digit to the equivalent int. |
CSTritt | 1:d835bb04d8f0 | 176 | */ |
CSTritt | 1:d835bb04d8f0 | 177 | int charVal = (int) myChar; // ASCII digit binary values are shifted by 48. |
CSTritt | 1:d835bb04d8f0 | 178 | return charVal - 48; |
CSTritt | 0:cbee9f6e3fe9 | 179 | } |