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 :

/media/uploads/mzcs/img_20181108_073655_hdr-a.jpg

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?

UserRevisionLine numberNew 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 }