Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit c61602f1912c36604127a0b8e5893fb646dd4392 @dreamcat4 committed Mar 27, 2011
Showing with 450 additions and 0 deletions.
  1. +215 −0 Mcp4261.cpp
  2. +96 −0 Mcp4261.h
  3. +93 −0 Mcp4261Example/Mcp4261Example.pde
  4. +46 −0 README.markdown
@@ -0,0 +1,215 @@
+
+// MCP4261 2-channel Digital Potentiometer
+// ww1.microchip.com/downloads/en/DeviceDoc/22059b.pdf
+
+// The default SPI Control Register - SPCR = B01010000;
+// interrupt disabled,spi enabled,msb 1st,master,clk low when idle,
+// sample on leading edge of clk,system clock/4 rate (fastest).
+// Enable the digital pins 11-13 for SPI (the MOSI,MISO,SPICLK)
+#include <Spi.h>
+#include "Mcp4261.h"
+
+//---------- constructor ----------------------------------------------------
+
+MCP4261::MCP4261(uint8_t slave_select_pin, float rAB_ohms)
+{
+ setup_ss(slave_select_pin);
+ setup_resistance(rAB_ohms, rW_ohms_typical);
+}
+
+MCP4261::MCP4261(uint8_t slave_select_pin, float rAB_ohms, float rW_ohms)
+{
+ setup_ss(slave_select_pin);
+ setup_resistance(rAB_ohms, rW_ohms);
+}
+
+//------------------ protected -----------------------------------------------
+
+uint16_t MCP4261::byte2uint16(byte high_byte, byte low_byte)
+{
+ return (uint16_t)high_byte<<8 | (uint16_t)low_byte;
+}
+
+byte MCP4261::uint16_high_byte(uint16_t uint16)
+{
+ return (byte)(uint16>>8);
+}
+
+byte MCP4261::uint16_low_byte(uint16_t uint16)
+{
+ return (byte)(uint16 & 0x00FF);
+}
+
+void MCP4261::setup_ss(uint8_t slave_select_pin)
+{
+ // Set slave select (Chip Select) pin for SPI Bus, and start high (disabled)
+ ::pinMode(slave_select_pin,OUTPUT);
+ ::digitalWrite(slave_select_pin,HIGH);
+ this->slave_select_pin = slave_select_pin;
+}
+
+void MCP4261::setup_resistance(float rAB_ohms, float rW_ohms)
+{
+ this->rAB_ohms = rAB_ohms;
+ this->rW_ohms = rW_ohms;
+ this->rAW_ohms_max = rAB_ohms - rW_ohms;
+ this->scale = rAW_ohms_max;
+}
+
+float MCP4261::step_increment()
+{
+ return (rAW_ohms_max - rW_ohms) / resolution;
+}
+
+unsigned int MCP4261::ohms2wiper_pos(float ohms)
+{
+ if(ohms <= 0.0)
+ return 0;
+ else if(scale != rAW_ohms_max)
+ ohms = ohms * rAW_ohms_max / scale;
+
+ return (unsigned int)((ohms - rW_ohms) / step_increment() ) + 0.5;
+}
+
+float MCP4261::wiper_pos2ohms(unsigned int wiper_pos)
+{
+ float ohms = rW_ohms + ( (float)wiper_pos * step_increment() );
+
+ if(scale != rAW_ohms_max)
+ ohms = ohms * scale / rAW_ohms_max;
+
+ return ohms;
+}
+
+void MCP4261::write(byte cmd_byte, byte data_byte)
+{
+ cmd_byte |= kCMD_WRITE;
+ ::digitalWrite(slave_select_pin, LOW);
+ byte high_byte = Spi.transfer(cmd_byte);
+ byte low_byte = Spi.transfer(data_byte);
+ ::digitalWrite(slave_select_pin, HIGH);
+ bool result = ~low_byte;
+}
+
+uint16_t MCP4261::read(byte cmd_byte)
+{
+ cmd_byte |= kCMD_READ;
+ ::digitalWrite(slave_select_pin, LOW);
+ byte high_byte = Spi.transfer(cmd_byte);
+ byte low_byte = Spi.transfer(0xFF);
+ ::digitalWrite(slave_select_pin, HIGH);
+ return byte2uint16(high_byte, low_byte);
+}
+
+void MCP4261::wiper_pos(byte pot, unsigned int wiper_pos)
+{
+ byte cmd_byte = 0x00;
+ byte data_byte = 0x00;
+ cmd_byte |= pot;
+
+ // Calculate the 9-bit data value to send
+ if(wiper_pos > 255)
+ cmd_byte |= B00000001; // Table 5-1 (page 36)
+ else
+ data_byte = (byte)(wiper_pos & 0x00FF);
+
+ write(cmd_byte|kADR_VOLATILE, data_byte);
+
+ if(non_volatile)
+ {
+ // EEPROM write cycles take 4ms each. So we block with delay(5); after any NV Writes
+ write(cmd_byte|kADR_NON_VOLATILE, data_byte);
+ delay(5);
+ }
+}
+
+//---------- public ----------------------------------------------------
+
+float MCP4261::wiper0()
+{
+ return wiper_pos2ohms( wiper0_pos() );
+}
+
+float MCP4261::wiper1()
+{
+ return wiper_pos2ohms( wiper1_pos() );
+}
+
+unsigned int MCP4261::wiper0_pos()
+{
+ return (unsigned int)( 0x01FF & this->read(kADR_WIPER0|kADR_VOLATILE) );
+}
+
+unsigned int MCP4261::wiper1_pos()
+{
+ return 0x01FF & this->read(kADR_WIPER1|kADR_VOLATILE);
+}
+
+void MCP4261::wiper0(float ohms)
+{
+ wiper0_pos( ohms2wiper_pos(ohms) );
+}
+
+void MCP4261::wiper1(float ohms)
+{
+ wiper1_pos( ohms2wiper_pos(ohms) );
+}
+
+void MCP4261::wiper0_pos(unsigned int wiper_pos)
+{
+ this->wiper_pos(kADR_WIPER0, wiper_pos);
+}
+
+void MCP4261::wiper1_pos(unsigned int wiper_pos)
+{
+ this->wiper_pos(kADR_WIPER1, wiper_pos);
+}
+
+
+// // Not implemented
+// bool MCP4261::pot0_connected(bool terminal_a, bool wiper, bool terminal_b)
+// {
+//
+// }
+//
+// bool MCP4261::pot1_connected(bool terminal_a, bool wiper, bool terminal_b)
+// {
+//
+// }
+//
+// void MCP4261::pot0_connect(bool terminal_a, bool wiper, bool terminal_b)
+// {
+//
+// }
+//
+// void MCP4261::pot1_connect(bool terminal_a, bool wiper, bool terminal_b)
+// {
+//
+// }
+//
+// bool MCP4261::pot0_shutdown()
+// {
+//
+// }
+//
+// bool MCP4261::pot1_shutdown()
+// {
+//
+// }
+//
+// void MCP4261::pot0_shutdown(bool shutdown)
+// {
+//
+// }
+//
+// void MCP4261::pot1_shutdown(bool shutdown)
+// {
+//
+// }
+//
+// bool MCP4261::hw_shutdown()
+// {
+//
+// }
+
+
@@ -0,0 +1,96 @@
+
+// MCP4261 2-channel Digital Potentiometer
+// ww1.microchip.com/downloads/en/DeviceDoc/22059b.pdf
+
+#ifndef Mcp4261_h
+#define Mcp4261_h
+
+class MCP4261
+{
+ public:
+ // You must at least specify the slave select pin and the rated resistance
+ MCP4261(uint8_t slave_select, float rAB_ohms);
+
+ // If you have measured wiper resistance, rW
+ MCP4261(uint8_t slave_select, float rAB_ohms, float rW_ohms);
+
+ // The resistance scaling, defaults to rAB_ohms
+ float scale;
+
+ // Read potentiometer values
+ float wiper0();
+ float wiper1();
+ unsigned int wiper0_pos();
+ unsigned int wiper1_pos();
+
+ // Write potentiometer values
+ void wiper0(float ohms);
+ void wiper1(float ohms);
+
+ void wiper0_pos(unsigned int wiper_pos);
+ void wiper1_pos(unsigned int wiper_pos);
+
+ // // Not implemented
+ // // Connect / disconnect potentiometers
+ // bool pot0_connected(bool terminal_a, bool wiper, bool terminal_b);
+ // bool pot1_connected(bool terminal_a, bool wiper, bool terminal_b);
+ // void pot0_connect(bool terminal_a, bool wiper, bool terminal_b);
+ // void pot1_connect(bool terminal_a, bool wiper, bool terminal_b);
+ //
+ // bool pot0_shutdown();
+ // bool pot1_shutdown();
+ // void pot0_shutdown(bool shutdown);
+ // void pot1_shutdown(bool shutdown);
+ //
+ // bool hw_shutdown();
+
+ protected:
+ const static float rW_ohms_typical = 117.50;
+ const static unsigned int resolution_7bit = 128;
+ const static unsigned int resolution_8bit = 256;
+
+ // Other devices can be configured below vv as per the device numbering scheme:
+ // MCP4N-- N=1 single pot, N=2 dual pot
+ // MCP4--N N=1 potentiometer, N=2 rheostat
+ // MCP4-N- N=3 7-bit volatile, N=4 7-bit non-volatile, N=5 8-bit volatile, N=6 8-bit non-volatile
+ const static bool non_volatile = true;
+ const static unsigned int resolution = resolution_8bit;
+
+ float rW_ohms;
+ float rAB_ohms;
+ float rAW_ohms_max;
+
+ uint8_t slave_select_pin;
+
+ const static uint8_t kADR_WIPER0 = B00000000;
+ const static uint8_t kADR_WIPER1 = B00010000;
+
+ const static uint8_t kCMD_READ = B00001100;
+ const static uint8_t kCMD_WRITE = B00000000;
+
+ const static uint8_t kADR_VOLATILE = B00000000;
+ const static uint8_t kADR_NON_VOLATILE = B00100000;
+
+ const static uint8_t kTCON_REGISTER = B01000000;
+ const static uint8_t kSTATUS_REGISTER = B01010000;
+
+ uint16_t byte2uint16(byte high_byte, byte low_byte);
+ byte uint16_high_byte(uint16_t uint16);
+ byte uint16_low_byte(uint16_t uint16);
+
+ void setup_ss(uint8_t slave_select_pin);
+ void setup_resistance(float rAB_ohms, float rW_ohms);
+
+ float step_increment();
+ unsigned int ohms2wiper_pos(float ohms);
+ float wiper_pos2ohms(unsigned int wiper_pos);
+
+ uint16_t read(byte cmd_byte);
+ void write(byte cmd_byte, byte data_byte);
+ void wiper_pos(byte pot, unsigned int wiper_pos);
+};
+
+#endif // Mcp4261_h
+
+
+
Oops, something went wrong.

0 comments on commit c61602f

Please sign in to comment.