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@1:0a2f89da0616, 2018-11-04 (annotated)
- Committer:
- mzcs
- Date:
- Sun Nov 04 17:00:46 2018 +0000
- Revision:
- 1:0a2f89da0616
- Parent:
- 0:437bb8e2f8a7
.
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| mzcs | 1:0a2f89da0616 | 1 | /* |
| mzcs | 1:0a2f89da0616 | 2 | Copyright (c) 2018 - Moran ZALTSMAN |
| mzcs | 1:0a2f89da0616 | 3 | |
| mzcs | 1:0a2f89da0616 | 4 | This program is free software: you can redistribute it and/or modify |
| mzcs | 1:0a2f89da0616 | 5 | it under the terms of the GNU General Public License as published by |
| mzcs | 1:0a2f89da0616 | 6 | the Free Software Foundation, either version 3 of the License, or |
| mzcs | 1:0a2f89da0616 | 7 | (at your option) any later version. |
| mzcs | 1:0a2f89da0616 | 8 | |
| mzcs | 1:0a2f89da0616 | 9 | This program is distributed in the hope that it will be useful, |
| mzcs | 1:0a2f89da0616 | 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| mzcs | 1:0a2f89da0616 | 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| mzcs | 1:0a2f89da0616 | 12 | GNU General Public License for more details. |
| mzcs | 1:0a2f89da0616 | 13 | |
| mzcs | 1:0a2f89da0616 | 14 | You should have received a copy of the GNU General Public License |
| mzcs | 1:0a2f89da0616 | 15 | along with this program. If not, see <https://www.gnu.org/licenses/>. |
| mzcs | 1:0a2f89da0616 | 16 | */ |
| mzcs | 1:0a2f89da0616 | 17 | |
| mzcs | 0:437bb8e2f8a7 | 18 | #include "mbed.h" |
| mzcs | 0:437bb8e2f8a7 | 19 | #include "mbed_mem_trace.h" |
| mzcs | 0:437bb8e2f8a7 | 20 | /*#include "hal/pinmap.h"*/ |
| mzcs | 0:437bb8e2f8a7 | 21 | #include "DebounceIn.h" |
| mzcs | 0:437bb8e2f8a7 | 22 | |
| mzcs | 0:437bb8e2f8a7 | 23 | // a Polling-based (IRQ-less) Edge-Detection Mechanism - Using DebounceIn Class & mBed-OS Thread(s) : |
| mzcs | 0:437bb8e2f8a7 | 24 | |
| mzcs | 0:437bb8e2f8a7 | 25 | // [ 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 | 26 | |
| mzcs | 0:437bb8e2f8a7 | 27 | DebounceIn btn_1(PA_11, PullUp), btn_2(PA_12, PullUp); // Inverted Logic : On -> "0", Off -> "1" |
| mzcs | 0:437bb8e2f8a7 | 28 | |
| mzcs | 0:437bb8e2f8a7 | 29 | PwmOut pwm_out_1(PA_8); |
| mzcs | 0:437bb8e2f8a7 | 30 | |
| mzcs | 0:437bb8e2f8a7 | 31 | 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 | 32 | |
| mzcs | 0:437bb8e2f8a7 | 33 | |
| mzcs | 0:437bb8e2f8a7 | 34 | class PwmOut_Elevator |
| mzcs | 0:437bb8e2f8a7 | 35 | { |
| mzcs | 0:437bb8e2f8a7 | 36 | public: |
| mzcs | 0:437bb8e2f8a7 | 37 | |
| mzcs | 0:437bb8e2f8a7 | 38 | PwmOut_Elevator(DebounceIn *debounce_in, PwmOut *pwm_out, float step) { _debounce_in = debounce_in; _pwm_out = pwm_out; _step = step; }; |
| mzcs | 0:437bb8e2f8a7 | 39 | |
| mzcs | 0:437bb8e2f8a7 | 40 | void PwmOut_Elevator_Operator() /* To Be Run Inside a Thread */ |
| mzcs | 0:437bb8e2f8a7 | 41 | { |
| mzcs | 0:437bb8e2f8a7 | 42 | while (1) |
| mzcs | 0:437bb8e2f8a7 | 43 | { |
| mzcs | 0:437bb8e2f8a7 | 44 | ThisThread::sleep_for((_debounce_in->get_debounce_us() / 1000) - 1); // Sleep for a Single (1) DebounceIn Sampling-Period |
| mzcs | 0:437bb8e2f8a7 | 45 | |
| mzcs | 0:437bb8e2f8a7 | 46 | if ((_debounce_in->get_edge_direction() == 0) && (_debounce_in->get_edge_direction_acted_upon() == 0)) |
| mzcs | 0:437bb8e2f8a7 | 47 | { |
| mzcs | 0:437bb8e2f8a7 | 48 | if ((_pwm_out->read() + _step) >= 0.65f) { _pwm_out->write(_pwm_out->read() + _step); } |
| mzcs | 0:437bb8e2f8a7 | 49 | else { _pwm_out->write(0.65f); } // <- a Fail-Safe Default |
| mzcs | 0:437bb8e2f8a7 | 50 | |
| mzcs | 0:437bb8e2f8a7 | 51 | _debounce_in->set_edge_direction_acted_upon(); |
| mzcs | 0:437bb8e2f8a7 | 52 | } |
| mzcs | 0:437bb8e2f8a7 | 53 | } |
| mzcs | 0:437bb8e2f8a7 | 54 | } |
| mzcs | 0:437bb8e2f8a7 | 55 | |
| mzcs | 0:437bb8e2f8a7 | 56 | protected: |
| mzcs | 0:437bb8e2f8a7 | 57 | |
| mzcs | 0:437bb8e2f8a7 | 58 | DebounceIn *_debounce_in; |
| mzcs | 0:437bb8e2f8a7 | 59 | PwmOut *_pwm_out; |
| mzcs | 0:437bb8e2f8a7 | 60 | float _step; |
| mzcs | 0:437bb8e2f8a7 | 61 | |
| mzcs | 0:437bb8e2f8a7 | 62 | }; // class PwmOut_Elevator - Ends |
| mzcs | 0:437bb8e2f8a7 | 63 | |
| mzcs | 0:437bb8e2f8a7 | 64 | |
| mzcs | 0:437bb8e2f8a7 | 65 | class Display |
| mzcs | 0:437bb8e2f8a7 | 66 | { |
| mzcs | 0:437bb8e2f8a7 | 67 | public: |
| mzcs | 0:437bb8e2f8a7 | 68 | |
| mzcs | 0:437bb8e2f8a7 | 69 | Display(BusOut *bus_out, PwmOut *pwm_out) { _bus_out = bus_out; _pwm_out = pwm_out; }; |
| mzcs | 0:437bb8e2f8a7 | 70 | |
| mzcs | 0:437bb8e2f8a7 | 71 | void Display_Operator(void) /* To Be Run Inside a Thread */ |
| mzcs | 0:437bb8e2f8a7 | 72 | { |
| mzcs | 0:437bb8e2f8a7 | 73 | while (1) |
| mzcs | 0:437bb8e2f8a7 | 74 | { |
| mzcs | 0:437bb8e2f8a7 | 75 | ThisThread::sleep_for(10); // 10ms -> a Projected 100-Hz Update Rate |
| mzcs | 0:437bb8e2f8a7 | 76 | |
| mzcs | 0:437bb8e2f8a7 | 77 | _bus_out->write( (uint8_t ((_pwm_out->read() - 0.65f)/0.05f)) + 1 ); // (65% -> 1) .. (100% -> 8), 5% Step |
| mzcs | 0:437bb8e2f8a7 | 78 | } |
| mzcs | 0:437bb8e2f8a7 | 79 | } |
| mzcs | 0:437bb8e2f8a7 | 80 | |
| mzcs | 0:437bb8e2f8a7 | 81 | protected: |
| mzcs | 0:437bb8e2f8a7 | 82 | |
| mzcs | 0:437bb8e2f8a7 | 83 | PwmOut *_pwm_out; |
| mzcs | 0:437bb8e2f8a7 | 84 | BusOut *_bus_out; |
| mzcs | 0:437bb8e2f8a7 | 85 | |
| mzcs | 0:437bb8e2f8a7 | 86 | }; // class Display - Ends |
| mzcs | 0:437bb8e2f8a7 | 87 | |
| mzcs | 0:437bb8e2f8a7 | 88 | |
| mzcs | 0:437bb8e2f8a7 | 89 | 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 | 90 | |
| mzcs | 0:437bb8e2f8a7 | 91 | Display display_1(&bus_out_1, &pwm_out_1); |
| mzcs | 0:437bb8e2f8a7 | 92 | |
| mzcs | 0:437bb8e2f8a7 | 93 | |
| mzcs | 0:437bb8e2f8a7 | 94 | // for Debugging |
| mzcs | 0:437bb8e2f8a7 | 95 | Semaphore smph_debug_output(1, 1); // (a Binary Semaphore - e.g. : Effectively a Mutex) |
| mzcs | 0:437bb8e2f8a7 | 96 | |
| mzcs | 0:437bb8e2f8a7 | 97 | Serial port_serial_1(PA_9, PA_10); |
| mzcs | 0:437bb8e2f8a7 | 98 | |
| mzcs | 0:437bb8e2f8a7 | 99 | class Debug |
| mzcs | 0:437bb8e2f8a7 | 100 | { |
| mzcs | 0:437bb8e2f8a7 | 101 | public: |
| mzcs | 0:437bb8e2f8a7 | 102 | |
| mzcs | 0:437bb8e2f8a7 | 103 | Debug(Serial *port_serial) { _serial = port_serial; } |
| mzcs | 0:437bb8e2f8a7 | 104 | |
| mzcs | 0:437bb8e2f8a7 | 105 | void Debug_Output_Mem_Stats(void) /* To Be Run Inside a Thread */ |
| mzcs | 0:437bb8e2f8a7 | 106 | { |
| mzcs | 0:437bb8e2f8a7 | 107 | // allocate enough room for every thread's stack statistics |
| mzcs | 0:437bb8e2f8a7 | 108 | // int8_t cnt = osThreadGetCount(); |
| mzcs | 0:437bb8e2f8a7 | 109 | // mbed_stats_stack_t *stats = (mbed_stats_stack_t*) malloc(cnt * sizeof(mbed_stats_stack_t)); |
| mzcs | 0:437bb8e2f8a7 | 110 | int8_t cnt; |
| mzcs | 0:437bb8e2f8a7 | 111 | |
| mzcs | 0:437bb8e2f8a7 | 112 | _serial->printf("Debug::Debug_Output_Mem_Stats() : Hello ! :)\r\n\r\n"); |
| mzcs | 0:437bb8e2f8a7 | 113 | |
| mzcs | 0:437bb8e2f8a7 | 114 | while (1) |
| mzcs | 0:437bb8e2f8a7 | 115 | { |
| mzcs | 0:437bb8e2f8a7 | 116 | smph_debug_output.wait(); |
| mzcs | 0:437bb8e2f8a7 | 117 | |
| mzcs | 0:437bb8e2f8a7 | 118 | cnt = osThreadGetCount(); |
| mzcs | 0:437bb8e2f8a7 | 119 | |
| mzcs | 0:437bb8e2f8a7 | 120 | // mbed_stats_stack_t *stats = (mbed_stats_stack_t*) malloc(cnt * sizeof(mbed_stats_stack_t)); |
| mzcs | 0:437bb8e2f8a7 | 121 | mbed_stats_stack_t *stats = new mbed_stats_stack_t[cnt]; |
| mzcs | 0:437bb8e2f8a7 | 122 | |
| mzcs | 0:437bb8e2f8a7 | 123 | cnt = mbed_stats_stack_get_each(stats, cnt); |
| mzcs | 0:437bb8e2f8a7 | 124 | |
| mzcs | 0:437bb8e2f8a7 | 125 | for (int8_t i = 0; i < cnt; i++) { |
| mzcs | 0:437bb8e2f8a7 | 126 | _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 | 127 | } |
| mzcs | 0:437bb8e2f8a7 | 128 | |
| mzcs | 0:437bb8e2f8a7 | 129 | // free(stats); |
| mzcs | 0:437bb8e2f8a7 | 130 | delete stats; |
| mzcs | 0:437bb8e2f8a7 | 131 | |
| mzcs | 0:437bb8e2f8a7 | 132 | // Grab the heap statistics |
| mzcs | 0:437bb8e2f8a7 | 133 | mbed_stats_heap_t heap_stats; |
| mzcs | 0:437bb8e2f8a7 | 134 | mbed_stats_heap_get(&heap_stats); |
| mzcs | 0:437bb8e2f8a7 | 135 | _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 | 136 | |
| mzcs | 0:437bb8e2f8a7 | 137 | smph_debug_output.release(); |
| mzcs | 0:437bb8e2f8a7 | 138 | |
| mzcs | 0:437bb8e2f8a7 | 139 | ThisThread::sleep_for(250); |
| mzcs | 0:437bb8e2f8a7 | 140 | } |
| mzcs | 0:437bb8e2f8a7 | 141 | |
| mzcs | 0:437bb8e2f8a7 | 142 | } |
| mzcs | 0:437bb8e2f8a7 | 143 | |
| mzcs | 0:437bb8e2f8a7 | 144 | void Debug_Output_General(void) /* To Be Run Inside a Thread */ |
| mzcs | 0:437bb8e2f8a7 | 145 | { |
| mzcs | 0:437bb8e2f8a7 | 146 | _serial->printf("Debug::Debug_Output_General() : Hello ! :)\r\n\r\n"); |
| mzcs | 0:437bb8e2f8a7 | 147 | |
| mzcs | 0:437bb8e2f8a7 | 148 | while (1) |
| mzcs | 0:437bb8e2f8a7 | 149 | { |
| mzcs | 0:437bb8e2f8a7 | 150 | smph_debug_output.wait(); |
| mzcs | 0:437bb8e2f8a7 | 151 | |
| mzcs | 0:437bb8e2f8a7 | 152 | _serial->printf("Debug::Debug_Output_General() : 'btn_1' Current Value = %d\r\n", btn_1.read()); |
| mzcs | 0:437bb8e2f8a7 | 153 | _serial->printf("Debug::Debug_Output_General() : 'btn_1/edge_direction' Current Value = %d\r\n", btn_1.get_edge_direction()); |
| mzcs | 0:437bb8e2f8a7 | 154 | _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 | 155 | _serial->printf("Debug::Debug_Output_General() : 'btn_2' Current Value = %d\r\n", btn_2.read()); |
| mzcs | 0:437bb8e2f8a7 | 156 | _serial->printf("Debug::Debug_Output_General() : 'btn_2/edge_direction' Current Value = %d\r\n", btn_2.get_edge_direction()); |
| mzcs | 0:437bb8e2f8a7 | 157 | _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 | 158 | _serial->printf("Debug::Debug_Output_General() : 'pwm_out_1' Current Value = %f\r\n", pwm_out_1.read()); |
| mzcs | 0:437bb8e2f8a7 | 159 | _serial->printf("Debug::Debug_Output_General() : 'bus_out_1' Current Value = %d\r\n\r\n", bus_out_1.read()); |
| mzcs | 0:437bb8e2f8a7 | 160 | |
| mzcs | 0:437bb8e2f8a7 | 161 | smph_debug_output.release(); |
| mzcs | 0:437bb8e2f8a7 | 162 | |
| mzcs | 0:437bb8e2f8a7 | 163 | ThisThread::sleep_for(250); |
| mzcs | 0:437bb8e2f8a7 | 164 | } |
| mzcs | 0:437bb8e2f8a7 | 165 | } |
| mzcs | 0:437bb8e2f8a7 | 166 | |
| mzcs | 0:437bb8e2f8a7 | 167 | protected: |
| mzcs | 0:437bb8e2f8a7 | 168 | |
| mzcs | 0:437bb8e2f8a7 | 169 | Serial *_serial; |
| mzcs | 0:437bb8e2f8a7 | 170 | |
| mzcs | 0:437bb8e2f8a7 | 171 | }; // class Debug - Ends |
| mzcs | 0:437bb8e2f8a7 | 172 | |
| mzcs | 0:437bb8e2f8a7 | 173 | Debug debug_1(&port_serial_1); |
| mzcs | 0:437bb8e2f8a7 | 174 | /// |
| mzcs | 0:437bb8e2f8a7 | 175 | |
| mzcs | 0:437bb8e2f8a7 | 176 | 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 | 177 | |
| mzcs | 0:437bb8e2f8a7 | 178 | |
| mzcs | 0:437bb8e2f8a7 | 179 | int main() |
| mzcs | 0:437bb8e2f8a7 | 180 | { |
| mzcs | 0:437bb8e2f8a7 | 181 | mbed_mem_trace_set_callback(mbed_mem_trace_default_callback); |
| mzcs | 0:437bb8e2f8a7 | 182 | |
| mzcs | 0:437bb8e2f8a7 | 183 | // Set PWM |
| mzcs | 0:437bb8e2f8a7 | 184 | pwm_out_1.period_us(40); // 25 kHz Period |
| mzcs | 0:437bb8e2f8a7 | 185 | pwm_out_1.write(0.65f); // 65% Duty-Cycle (65% Fan Speed : a Safe Default) |
| mzcs | 0:437bb8e2f8a7 | 186 | /// |
| mzcs | 0:437bb8e2f8a7 | 187 | |
| mzcs | 0:437bb8e2f8a7 | 188 | debug_general_thr.start(callback(&debug_1, &Debug::Debug_Output_General)); |
| mzcs | 0:437bb8e2f8a7 | 189 | |
| mzcs | 0:437bb8e2f8a7 | 190 | port_serial_1.printf("main(): 'debug_general_thr' Started.\r\n"); |
| mzcs | 0:437bb8e2f8a7 | 191 | |
| mzcs | 0:437bb8e2f8a7 | 192 | debug_mem_stats_thr.start(callback(&debug_1, &Debug::Debug_Output_Mem_Stats)); |
| mzcs | 0:437bb8e2f8a7 | 193 | |
| mzcs | 0:437bb8e2f8a7 | 194 | port_serial_1.printf("main(): 'debug_mem_stats_thr' Started.\r\n"); |
| mzcs | 0:437bb8e2f8a7 | 195 | |
| mzcs | 0:437bb8e2f8a7 | 196 | 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 | 197 | |
| mzcs | 0:437bb8e2f8a7 | 198 | 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 | 199 | |
| mzcs | 0:437bb8e2f8a7 | 200 | btn_1_thr.start(callback(&btn_1_pwmout_elevator, &PwmOut_Elevator::PwmOut_Elevator_Operator)); |
| mzcs | 0:437bb8e2f8a7 | 201 | |
| mzcs | 0:437bb8e2f8a7 | 202 | port_serial_1.printf("main(): 'btn_1_thr' Started.\r\n"); |
| mzcs | 0:437bb8e2f8a7 | 203 | |
| mzcs | 0:437bb8e2f8a7 | 204 | ThisThread::sleep_for(100); |
| mzcs | 0:437bb8e2f8a7 | 205 | |
| mzcs | 0:437bb8e2f8a7 | 206 | btn_2_thr.start(callback(&btn_2_pwmout_elevator, &PwmOut_Elevator::PwmOut_Elevator_Operator)); |
| mzcs | 0:437bb8e2f8a7 | 207 | |
| mzcs | 0:437bb8e2f8a7 | 208 | port_serial_1.printf("main(): 'btn_2_thr' Started.\r\n"); |
| mzcs | 0:437bb8e2f8a7 | 209 | |
| mzcs | 0:437bb8e2f8a7 | 210 | ThisThread::sleep_for(100); |
| mzcs | 0:437bb8e2f8a7 | 211 | |
| mzcs | 0:437bb8e2f8a7 | 212 | display_thr.start(callback(&display_1, &Display::Display_Operator)); |
| mzcs | 0:437bb8e2f8a7 | 213 | |
| mzcs | 0:437bb8e2f8a7 | 214 | port_serial_1.printf("main(): 'display_thr' Started.\r\n"); |
| mzcs | 0:437bb8e2f8a7 | 215 | |
| mzcs | 0:437bb8e2f8a7 | 216 | ThisThread::sleep_for(osWaitForever); |
| mzcs | 0:437bb8e2f8a7 | 217 | } |