An I/O controller for virtual pinball machines: accelerometer nudge sensing, analog plunger input, button input encoding, LedWiz compatible output controls, and more.
Dependencies: mbed FastIO FastPWM USBDevice
Fork of Pinscape_Controller by
74HC595.h
00001 /* Copyright 2014 M J Roberts, MIT License 00002 * 00003 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 00004 * and associated documentation files (the "Software"), to deal in the Software without 00005 * restriction, including without limitation the rights to use, copy, modify, merge, publish, 00006 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 00007 * Software is furnished to do so, subject to the following conditions: 00008 * 00009 * The above copyright notice and this permission notice shall be included in all copies or 00010 * substantial portions of the Software. 00011 * 00012 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 00013 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00014 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 00015 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00016 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00017 */ 00018 00019 #ifndef HC595_INCLUDED 00020 #define HC595_INCLUDED 00021 00022 #include "mbed.h" 00023 00024 // 74HC595 Interface 00025 // 00026 // We require four GPIO pins: 00027 // 00028 // sin - serial data 00029 // sclk - serial clock 00030 // latch - the LATCH signal, which transfers the internal shift register 00031 // bits to the physical output pin states 00032 // ena - the Enable signal 00033 // 00034 // Note that the physical !OE (output enable) pin on the 74HC595 is active-low. 00035 // To allow for orderly startup that guarantees that outputs won't be pulsed 00036 // (even briefly) during power-on, we require the !OE pin to be wired with a 00037 // pull-up resistor to Vcc, and connected to our ENA GPIO pin via an inverter. 00038 // 00039 // Recommended wiring: connect the GPIO pin to the base of an NPN transistor 00040 // through a 2.2K resistor, connect the collector the !OE pin on the 74HC595, 00041 // and connect the emitter to ground. This will pull !OE to ground when we 00042 // write a digital 1 to the ENA GPIO, enabling the outputs. 00043 // 00044 // We use simple bit-banging through plain DigitalOut pins to send serial 00045 // data to the chips. This is fast enough for our purposes, since we send 00046 // only 8 bits per chip on each update (about 4us per chip per update), and 00047 // we only update when we get a command from the PC host that changes an 00048 // output state. These updates are at USB speed, so the update interval is 00049 // extremely long compared to the bit-banging time. If we wanted to use 00050 // these chips to implement PWM controlled by the microcontroller, or we 00051 // simply wanted to use a very long daisy-chain, we'd probably have to use 00052 // a faster transfer mechanism, such as the SPIO controller. 00053 00054 class HC595 00055 { 00056 public: 00057 HC595(int nchips, PinName sin, PinName sclk, PinName latch, PinName ena) : 00058 nchips(nchips), sin(sin), sclk(sclk), latch(latch), ena(ena) 00059 { 00060 // turn off all pins initially 00061 this->sin = 0; 00062 this->sclk = 0; 00063 this->latch = 0; 00064 this->ena = 0; 00065 00066 // allocate the state array 00067 state = new char[nchips*8]; 00068 memset(state, 0, nchips*8); 00069 dirty = false; 00070 } 00071 00072 // Initialize. This must be called once at startup to clear the chips' 00073 // shift registers. We clock a 0 bit (OFF state) to each shift register 00074 // position and latch the OFF states on the outputs. Note that this 00075 // doesn't enable the chips - that must be done with a separate call 00076 // to enable(true). 00077 void init() 00078 { 00079 // set the internal state of all inputs 00080 memset(state, 0, nchips*8); 00081 dirty = false; 00082 00083 // clock a 0 to each shift register bit (8 per chip) 00084 sin = 0; 00085 for (int i = 0 ; i < nchips*8 ; ++i) 00086 { 00087 sclk = 1; 00088 sclk = 0; 00089 } 00090 00091 // latch the output data (this transfers the serial data register 00092 // bit for each pin to the actual output pin) 00093 latch = 1; 00094 latch = 0; 00095 } 00096 00097 // Set an output state. This only sets the state internally; call 00098 // update() to apply changes to the physical outputs. 00099 void set(int idx, int val) 00100 { 00101 if (state[idx] != val) 00102 { 00103 state[idx] = val; 00104 dirty = true; 00105 } 00106 } 00107 00108 // Global enable/disable the outputs. We use this for cleaner startup, 00109 // by disabling all outputs after power-on and when coming out of sleep 00110 // mode until we've had a chance to initialize the chip registers. The 00111 // chips have random values in their shift registers when first powered 00112 // on, so we have to send an initial update after power-on. The snag 00113 // is that the chips might have a separate power supply from the KL25Z, 00114 // so we can't assume that the chips are powered just because the program 00115 // is running. Instead, we can use the USB connection status as a proxy 00116 // for chip power, on the assumption that (a) the chips are running off 00117 // of the PC power supply, and (b) the USB connection can only be running 00118 // when the PC is running (hence the PC power supply is on). 00119 void enable(bool f) 00120 { 00121 // set the new enable state 00122 ena = (f ? 1 : 0); 00123 } 00124 00125 // Apply updates. This sends the current state of each pin to the 00126 // chips and latches the new settings. If 'force' is true, we flush 00127 // our internal state to the chips even if we haven't made any changes 00128 // since the last update. 00129 void update(bool force = false) 00130 { 00131 // if we have changes to apply, or the caller wants the update to 00132 // happen regardless of pending changes, refresh the chips 00133 if (dirty || force) 00134 { 00135 // Clock out the new states. Since the outputs are arranged 00136 // as shift registers, we have to clock out the bits in reverse 00137 // order of port numbers - the first bit we output will end up 00138 // in the last register after we clock out all of the other bits. 00139 // So clock out the last bit first and the first bit last. 00140 for (int i = nchips*8-1 ; i >= 0 ; --i) 00141 { 00142 sclk = 0; 00143 sin = state[i]; 00144 sclk = 1; 00145 } 00146 00147 // latch the new states 00148 latch = 1; 00149 sclk = 0; 00150 latch = 0; 00151 00152 // outputs now reflect internal state 00153 dirty = false; 00154 } 00155 } 00156 00157 00158 private: 00159 int nchips; // number of chips in daisy chain 00160 bool dirty; // do we have changes to send to the chips? 00161 DigitalOut sin; // serial data pin 00162 DigitalOut sclk; // serial clock pin 00163 DigitalOut latch; // latch pin 00164 DigitalOut ena; // enable pin 00165 char *state; // array of current output states (0=off, 1=on) 00166 }; 00167 00168 #endif // HC595_INCLUDED
Generated on Wed Jul 13 2022 03:30:10 by 1.7.2