Fan Controller - PWM HF (25kHz) Type, w/ a Two Button Escalator & a 4-LED Binary State-Display for UI.
The Circuit, as Built on an Universal PCB, Ready For Installation (in a '3.5 Drive-Slot) - Using a Thermoplastic Carrier :
main.cpp@0:437bb8e2f8a7, 2018-11-04 (annotated)
- Committer:
- mzcs
- Date:
- Sun Nov 04 16:49:49 2018 +0000
- Revision:
- 0:437bb8e2f8a7
- Child:
- 1:0a2f89da0616
1st Publication.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mzcs | 0:437bb8e2f8a7 | 1 | #include "mbed.h" |
mzcs | 0:437bb8e2f8a7 | 2 | #include "mbed_mem_trace.h" |
mzcs | 0:437bb8e2f8a7 | 3 | /*#include "hal/pinmap.h"*/ |
mzcs | 0:437bb8e2f8a7 | 4 | #include "DebounceIn.h" |
mzcs | 0:437bb8e2f8a7 | 5 | |
mzcs | 0:437bb8e2f8a7 | 6 | // a Polling-based (IRQ-less) Edge-Detection Mechanism - Using DebounceIn Class & mBed-OS Thread(s) : |
mzcs | 0:437bb8e2f8a7 | 7 | |
mzcs | 0:437bb8e2f8a7 | 8 | // [ Note : Shared-Resource (e.g. : PWMOut, BusOut) Are At Least Thread-Safe ( See : https://docs.mbed.com/docs/mbed-os-handbook/en/latest/concepts/thread_safety/ ) ] |
mzcs | 0:437bb8e2f8a7 | 9 | |
mzcs | 0:437bb8e2f8a7 | 10 | DebounceIn btn_1(PA_11, PullUp), btn_2(PA_12, PullUp); // Inverted Logic : On -> "0", Off -> "1" |
mzcs | 0:437bb8e2f8a7 | 11 | |
mzcs | 0:437bb8e2f8a7 | 12 | PwmOut pwm_out_1(PA_8); |
mzcs | 0:437bb8e2f8a7 | 13 | |
mzcs | 0:437bb8e2f8a7 | 14 | BusOut bus_out_1(PA_15, PB_3, PB_4, PB_5); // a 4-bit Bus - For a 4 LED Status-Display Setup |
mzcs | 0:437bb8e2f8a7 | 15 | |
mzcs | 0:437bb8e2f8a7 | 16 | |
mzcs | 0:437bb8e2f8a7 | 17 | class PwmOut_Elevator |
mzcs | 0:437bb8e2f8a7 | 18 | { |
mzcs | 0:437bb8e2f8a7 | 19 | public: |
mzcs | 0:437bb8e2f8a7 | 20 | |
mzcs | 0:437bb8e2f8a7 | 21 | PwmOut_Elevator(DebounceIn *debounce_in, PwmOut *pwm_out, float step) { _debounce_in = debounce_in; _pwm_out = pwm_out; _step = step; }; |
mzcs | 0:437bb8e2f8a7 | 22 | |
mzcs | 0:437bb8e2f8a7 | 23 | void PwmOut_Elevator_Operator() /* To Be Run Inside a Thread */ |
mzcs | 0:437bb8e2f8a7 | 24 | { |
mzcs | 0:437bb8e2f8a7 | 25 | while (1) |
mzcs | 0:437bb8e2f8a7 | 26 | { |
mzcs | 0:437bb8e2f8a7 | 27 | ThisThread::sleep_for((_debounce_in->get_debounce_us() / 1000) - 1); // Sleep for a Single (1) DebounceIn Sampling-Period |
mzcs | 0:437bb8e2f8a7 | 28 | |
mzcs | 0:437bb8e2f8a7 | 29 | if ((_debounce_in->get_edge_direction() == 0) && (_debounce_in->get_edge_direction_acted_upon() == 0)) |
mzcs | 0:437bb8e2f8a7 | 30 | { |
mzcs | 0:437bb8e2f8a7 | 31 | if ((_pwm_out->read() + _step) >= 0.65f) { _pwm_out->write(_pwm_out->read() + _step); } |
mzcs | 0:437bb8e2f8a7 | 32 | else { _pwm_out->write(0.65f); } // <- a Fail-Safe Default |
mzcs | 0:437bb8e2f8a7 | 33 | |
mzcs | 0:437bb8e2f8a7 | 34 | _debounce_in->set_edge_direction_acted_upon(); |
mzcs | 0:437bb8e2f8a7 | 35 | } |
mzcs | 0:437bb8e2f8a7 | 36 | } |
mzcs | 0:437bb8e2f8a7 | 37 | } |
mzcs | 0:437bb8e2f8a7 | 38 | |
mzcs | 0:437bb8e2f8a7 | 39 | protected: |
mzcs | 0:437bb8e2f8a7 | 40 | |
mzcs | 0:437bb8e2f8a7 | 41 | DebounceIn *_debounce_in; |
mzcs | 0:437bb8e2f8a7 | 42 | PwmOut *_pwm_out; |
mzcs | 0:437bb8e2f8a7 | 43 | float _step; |
mzcs | 0:437bb8e2f8a7 | 44 | |
mzcs | 0:437bb8e2f8a7 | 45 | }; // class PwmOut_Elevator - Ends |
mzcs | 0:437bb8e2f8a7 | 46 | |
mzcs | 0:437bb8e2f8a7 | 47 | |
mzcs | 0:437bb8e2f8a7 | 48 | class Display |
mzcs | 0:437bb8e2f8a7 | 49 | { |
mzcs | 0:437bb8e2f8a7 | 50 | public: |
mzcs | 0:437bb8e2f8a7 | 51 | |
mzcs | 0:437bb8e2f8a7 | 52 | Display(BusOut *bus_out, PwmOut *pwm_out) { _bus_out = bus_out; _pwm_out = pwm_out; }; |
mzcs | 0:437bb8e2f8a7 | 53 | |
mzcs | 0:437bb8e2f8a7 | 54 | void Display_Operator(void) /* To Be Run Inside a Thread */ |
mzcs | 0:437bb8e2f8a7 | 55 | { |
mzcs | 0:437bb8e2f8a7 | 56 | while (1) |
mzcs | 0:437bb8e2f8a7 | 57 | { |
mzcs | 0:437bb8e2f8a7 | 58 | ThisThread::sleep_for(10); // 10ms -> a Projected 100-Hz Update Rate |
mzcs | 0:437bb8e2f8a7 | 59 | |
mzcs | 0:437bb8e2f8a7 | 60 | _bus_out->write( (uint8_t ((_pwm_out->read() - 0.65f)/0.05f)) + 1 ); // (65% -> 1) .. (100% -> 8), 5% Step |
mzcs | 0:437bb8e2f8a7 | 61 | } |
mzcs | 0:437bb8e2f8a7 | 62 | } |
mzcs | 0:437bb8e2f8a7 | 63 | |
mzcs | 0:437bb8e2f8a7 | 64 | protected: |
mzcs | 0:437bb8e2f8a7 | 65 | |
mzcs | 0:437bb8e2f8a7 | 66 | PwmOut *_pwm_out; |
mzcs | 0:437bb8e2f8a7 | 67 | BusOut *_bus_out; |
mzcs | 0:437bb8e2f8a7 | 68 | |
mzcs | 0:437bb8e2f8a7 | 69 | }; // class Display - Ends |
mzcs | 0:437bb8e2f8a7 | 70 | |
mzcs | 0:437bb8e2f8a7 | 71 | |
mzcs | 0:437bb8e2f8a7 | 72 | PwmOut_Elevator btn_1_pwmout_elevator(&btn_1, &pwm_out_1, 0.05f), btn_2_pwmout_elevator(&btn_2, &pwm_out_1, -0.05f); |
mzcs | 0:437bb8e2f8a7 | 73 | |
mzcs | 0:437bb8e2f8a7 | 74 | Display display_1(&bus_out_1, &pwm_out_1); |
mzcs | 0:437bb8e2f8a7 | 75 | |
mzcs | 0:437bb8e2f8a7 | 76 | |
mzcs | 0:437bb8e2f8a7 | 77 | // for Debugging |
mzcs | 0:437bb8e2f8a7 | 78 | Semaphore smph_debug_output(1, 1); // (a Binary Semaphore - e.g. : Effectively a Mutex) |
mzcs | 0:437bb8e2f8a7 | 79 | |
mzcs | 0:437bb8e2f8a7 | 80 | Serial port_serial_1(PA_9, PA_10); |
mzcs | 0:437bb8e2f8a7 | 81 | |
mzcs | 0:437bb8e2f8a7 | 82 | class Debug |
mzcs | 0:437bb8e2f8a7 | 83 | { |
mzcs | 0:437bb8e2f8a7 | 84 | public: |
mzcs | 0:437bb8e2f8a7 | 85 | |
mzcs | 0:437bb8e2f8a7 | 86 | Debug(Serial *port_serial) { _serial = port_serial; } |
mzcs | 0:437bb8e2f8a7 | 87 | |
mzcs | 0:437bb8e2f8a7 | 88 | void Debug_Output_Mem_Stats(void) /* To Be Run Inside a Thread */ |
mzcs | 0:437bb8e2f8a7 | 89 | { |
mzcs | 0:437bb8e2f8a7 | 90 | // allocate enough room for every thread's stack statistics |
mzcs | 0:437bb8e2f8a7 | 91 | // int8_t cnt = osThreadGetCount(); |
mzcs | 0:437bb8e2f8a7 | 92 | // mbed_stats_stack_t *stats = (mbed_stats_stack_t*) malloc(cnt * sizeof(mbed_stats_stack_t)); |
mzcs | 0:437bb8e2f8a7 | 93 | int8_t cnt; |
mzcs | 0:437bb8e2f8a7 | 94 | |
mzcs | 0:437bb8e2f8a7 | 95 | _serial->printf("Debug::Debug_Output_Mem_Stats() : Hello ! :)\r\n\r\n"); |
mzcs | 0:437bb8e2f8a7 | 96 | |
mzcs | 0:437bb8e2f8a7 | 97 | while (1) |
mzcs | 0:437bb8e2f8a7 | 98 | { |
mzcs | 0:437bb8e2f8a7 | 99 | smph_debug_output.wait(); |
mzcs | 0:437bb8e2f8a7 | 100 | |
mzcs | 0:437bb8e2f8a7 | 101 | cnt = osThreadGetCount(); |
mzcs | 0:437bb8e2f8a7 | 102 | |
mzcs | 0:437bb8e2f8a7 | 103 | // mbed_stats_stack_t *stats = (mbed_stats_stack_t*) malloc(cnt * sizeof(mbed_stats_stack_t)); |
mzcs | 0:437bb8e2f8a7 | 104 | mbed_stats_stack_t *stats = new mbed_stats_stack_t[cnt]; |
mzcs | 0:437bb8e2f8a7 | 105 | |
mzcs | 0:437bb8e2f8a7 | 106 | cnt = mbed_stats_stack_get_each(stats, cnt); |
mzcs | 0:437bb8e2f8a7 | 107 | |
mzcs | 0:437bb8e2f8a7 | 108 | for (int8_t i = 0; i < cnt; i++) { |
mzcs | 0:437bb8e2f8a7 | 109 | _serial->printf("Debug::Debug_Output_Mem_Stats(): Thread: 0x%lX, Stack size: %lu / %lu\r\n", stats[i].thread_id, stats[i].max_size, stats[i].reserved_size); |
mzcs | 0:437bb8e2f8a7 | 110 | } |
mzcs | 0:437bb8e2f8a7 | 111 | |
mzcs | 0:437bb8e2f8a7 | 112 | // free(stats); |
mzcs | 0:437bb8e2f8a7 | 113 | delete stats; |
mzcs | 0:437bb8e2f8a7 | 114 | |
mzcs | 0:437bb8e2f8a7 | 115 | // Grab the heap statistics |
mzcs | 0:437bb8e2f8a7 | 116 | mbed_stats_heap_t heap_stats; |
mzcs | 0:437bb8e2f8a7 | 117 | mbed_stats_heap_get(&heap_stats); |
mzcs | 0:437bb8e2f8a7 | 118 | _serial->printf("Debug::Debug_Output_Mem_Stats(): Heap size: %lu / %lu bytes\r\n\r\n", heap_stats.current_size, heap_stats.reserved_size); |
mzcs | 0:437bb8e2f8a7 | 119 | |
mzcs | 0:437bb8e2f8a7 | 120 | smph_debug_output.release(); |
mzcs | 0:437bb8e2f8a7 | 121 | |
mzcs | 0:437bb8e2f8a7 | 122 | ThisThread::sleep_for(250); |
mzcs | 0:437bb8e2f8a7 | 123 | } |
mzcs | 0:437bb8e2f8a7 | 124 | |
mzcs | 0:437bb8e2f8a7 | 125 | } |
mzcs | 0:437bb8e2f8a7 | 126 | |
mzcs | 0:437bb8e2f8a7 | 127 | void Debug_Output_General(void) /* To Be Run Inside a Thread */ |
mzcs | 0:437bb8e2f8a7 | 128 | { |
mzcs | 0:437bb8e2f8a7 | 129 | _serial->printf("Debug::Debug_Output_General() : Hello ! :)\r\n\r\n"); |
mzcs | 0:437bb8e2f8a7 | 130 | |
mzcs | 0:437bb8e2f8a7 | 131 | while (1) |
mzcs | 0:437bb8e2f8a7 | 132 | { |
mzcs | 0:437bb8e2f8a7 | 133 | smph_debug_output.wait(); |
mzcs | 0:437bb8e2f8a7 | 134 | |
mzcs | 0:437bb8e2f8a7 | 135 | _serial->printf("Debug::Debug_Output_General() : 'btn_1' Current Value = %d\r\n", btn_1.read()); |
mzcs | 0:437bb8e2f8a7 | 136 | _serial->printf("Debug::Debug_Output_General() : 'btn_1/edge_direction' Current Value = %d\r\n", btn_1.get_edge_direction()); |
mzcs | 0:437bb8e2f8a7 | 137 | _serial->printf("Debug::Debug_Output_General() : 'btn_1/edge_direction_acted_upon' Current Value = %d\r\n", btn_1.get_edge_direction_acted_upon()); |
mzcs | 0:437bb8e2f8a7 | 138 | _serial->printf("Debug::Debug_Output_General() : 'btn_2' Current Value = %d\r\n", btn_2.read()); |
mzcs | 0:437bb8e2f8a7 | 139 | _serial->printf("Debug::Debug_Output_General() : 'btn_2/edge_direction' Current Value = %d\r\n", btn_2.get_edge_direction()); |
mzcs | 0:437bb8e2f8a7 | 140 | _serial->printf("Debug::Debug_Output_General() : 'btn_2/edge_direction_acted_upon' Current Value = %d\r\n", btn_2.get_edge_direction_acted_upon()); |
mzcs | 0:437bb8e2f8a7 | 141 | _serial->printf("Debug::Debug_Output_General() : 'pwm_out_1' Current Value = %f\r\n", pwm_out_1.read()); |
mzcs | 0:437bb8e2f8a7 | 142 | _serial->printf("Debug::Debug_Output_General() : 'bus_out_1' Current Value = %d\r\n\r\n", bus_out_1.read()); |
mzcs | 0:437bb8e2f8a7 | 143 | |
mzcs | 0:437bb8e2f8a7 | 144 | smph_debug_output.release(); |
mzcs | 0:437bb8e2f8a7 | 145 | |
mzcs | 0:437bb8e2f8a7 | 146 | ThisThread::sleep_for(250); |
mzcs | 0:437bb8e2f8a7 | 147 | } |
mzcs | 0:437bb8e2f8a7 | 148 | } |
mzcs | 0:437bb8e2f8a7 | 149 | |
mzcs | 0:437bb8e2f8a7 | 150 | protected: |
mzcs | 0:437bb8e2f8a7 | 151 | |
mzcs | 0:437bb8e2f8a7 | 152 | Serial *_serial; |
mzcs | 0:437bb8e2f8a7 | 153 | |
mzcs | 0:437bb8e2f8a7 | 154 | }; // class Debug - Ends |
mzcs | 0:437bb8e2f8a7 | 155 | |
mzcs | 0:437bb8e2f8a7 | 156 | Debug debug_1(&port_serial_1); |
mzcs | 0:437bb8e2f8a7 | 157 | /// |
mzcs | 0:437bb8e2f8a7 | 158 | |
mzcs | 0:437bb8e2f8a7 | 159 | Thread btn_1_thr(osPriorityNormal, 240), btn_2_thr(osPriorityNormal, 240), display_thr(osPriorityNormal, 240), debug_general_thr(osPriorityNormal, 640), debug_mem_stats_thr(osPriorityNormal, 640); |
mzcs | 0:437bb8e2f8a7 | 160 | |
mzcs | 0:437bb8e2f8a7 | 161 | |
mzcs | 0:437bb8e2f8a7 | 162 | int main() |
mzcs | 0:437bb8e2f8a7 | 163 | { |
mzcs | 0:437bb8e2f8a7 | 164 | mbed_mem_trace_set_callback(mbed_mem_trace_default_callback); |
mzcs | 0:437bb8e2f8a7 | 165 | |
mzcs | 0:437bb8e2f8a7 | 166 | // Set PWM |
mzcs | 0:437bb8e2f8a7 | 167 | pwm_out_1.period_us(40); // 25 kHz Period |
mzcs | 0:437bb8e2f8a7 | 168 | pwm_out_1.write(0.65f); // 65% Duty-Cycle (65% Fan Speed : a Safe Default) |
mzcs | 0:437bb8e2f8a7 | 169 | /// |
mzcs | 0:437bb8e2f8a7 | 170 | |
mzcs | 0:437bb8e2f8a7 | 171 | debug_general_thr.start(callback(&debug_1, &Debug::Debug_Output_General)); |
mzcs | 0:437bb8e2f8a7 | 172 | |
mzcs | 0:437bb8e2f8a7 | 173 | port_serial_1.printf("main(): 'debug_general_thr' Started.\r\n"); |
mzcs | 0:437bb8e2f8a7 | 174 | |
mzcs | 0:437bb8e2f8a7 | 175 | debug_mem_stats_thr.start(callback(&debug_1, &Debug::Debug_Output_Mem_Stats)); |
mzcs | 0:437bb8e2f8a7 | 176 | |
mzcs | 0:437bb8e2f8a7 | 177 | port_serial_1.printf("main(): 'debug_mem_stats_thr' Started.\r\n"); |
mzcs | 0:437bb8e2f8a7 | 178 | |
mzcs | 0:437bb8e2f8a7 | 179 | port_serial_1.printf("main(): Going To Sleep For a %dms\r\n", ((btn_1.get_debounce_us()*btn_1.get_samples()/1000)+1)); |
mzcs | 0:437bb8e2f8a7 | 180 | |
mzcs | 0:437bb8e2f8a7 | 181 | ThisThread::sleep_for((btn_1.get_debounce_us()*btn_1.get_samples()/1000)+1); // Sleep for 251ms - To Get Initial Stable Input-Values of Buttons via Their DebounceIn Instances |
mzcs | 0:437bb8e2f8a7 | 182 | |
mzcs | 0:437bb8e2f8a7 | 183 | btn_1_thr.start(callback(&btn_1_pwmout_elevator, &PwmOut_Elevator::PwmOut_Elevator_Operator)); |
mzcs | 0:437bb8e2f8a7 | 184 | |
mzcs | 0:437bb8e2f8a7 | 185 | port_serial_1.printf("main(): 'btn_1_thr' Started.\r\n"); |
mzcs | 0:437bb8e2f8a7 | 186 | |
mzcs | 0:437bb8e2f8a7 | 187 | ThisThread::sleep_for(100); |
mzcs | 0:437bb8e2f8a7 | 188 | |
mzcs | 0:437bb8e2f8a7 | 189 | btn_2_thr.start(callback(&btn_2_pwmout_elevator, &PwmOut_Elevator::PwmOut_Elevator_Operator)); |
mzcs | 0:437bb8e2f8a7 | 190 | |
mzcs | 0:437bb8e2f8a7 | 191 | port_serial_1.printf("main(): 'btn_2_thr' Started.\r\n"); |
mzcs | 0:437bb8e2f8a7 | 192 | |
mzcs | 0:437bb8e2f8a7 | 193 | ThisThread::sleep_for(100); |
mzcs | 0:437bb8e2f8a7 | 194 | |
mzcs | 0:437bb8e2f8a7 | 195 | display_thr.start(callback(&display_1, &Display::Display_Operator)); |
mzcs | 0:437bb8e2f8a7 | 196 | |
mzcs | 0:437bb8e2f8a7 | 197 | port_serial_1.printf("main(): 'display_thr' Started.\r\n"); |
mzcs | 0:437bb8e2f8a7 | 198 | |
mzcs | 0:437bb8e2f8a7 | 199 | ThisThread::sleep_for(osWaitForever); |
mzcs | 0:437bb8e2f8a7 | 200 | } |