Design a bipolar voltage source using the Microchip DAC MCP4922
The microchip device (MCP4922) is a very easy to use DAC that is accessed via SPI interface. I found it easier to interface with a +5V bus and VCC as opposed to +3.3V despite of what the datasheet says. (http://ww1.microchip.com/downloads/en/DeviceDoc/22250A.pdf)
In addition, I created a simple spreadsheet to enter different values in order to design before layout.
Once you read the datasheet, you'll understand where I got the values from.
DA and DB are the values that control the gain as well as the offset (Maximum 4095 in decimal).
VREFA and VREFB are your input reference sources. I typicaly use 2.5Vdc.
R1-R4 are the gain and offset resistors. I set all to 10k Ohms 1% 1/4Watts.
GA and GB are gain x1 or x2 as desire.
Vo is the output.
Enjoy.
Download worksheet here!!
Ideas for Electronics Projects
Tuesday, May 3, 2016
Monday, March 7, 2016
Control the MCP4922 DAC using an Arduino MEGA2560
Control the Microchip MCP4922-E/P Digital to Analog Converter using an Arduino board.
I've been using the microchip DAC to output a +/-5V output. I used the Arduino MEGA2560 to write to the SPI bus and it worked great. The code is as follows:
//pin# Pin Name Mapped Pin Name
//19 PB0 ( SS/PCINT0 ) Digital pin 53 (SS)
//20 PB1 ( SCK/PCINT1 ) Digital pin 52 (SCK)
//21 PB2 ( MOSI/PCINT2 ) Digital pin 51 (MOSI)
//22 PB3 ( MISO/PCINT3 ) Digital pin 50 (MISO)
////////////////////////////////////////////////////////////////////////////////////////////////////
//Microchip MCP4922-E/P
//Pin No. Symbol Function
//1 VDD Supply Voltage Input (2.7V to 5.5V)
//3 CS Chip Select Input
//4 SCK Serial Clock Input
//5 SDI Serial Data Input
//8 LDAC Synchronization Input. This pin is used to transfer DAC settings (Input Registers)
// to the output registers (VOUT)
//9 SHDN Hardware Shutdown Input
//10 VOUTB DACB Output
//11 VREFB DACB Reference Voltage Input (VSS to VDD)
//12 VSS Ground reference point for all circuitry on the device
//13 VREFA DACA Reference Voltage Input (VSS to VDD)
//14 VOUTA DACA Output
////////////////////////////////////////////////////////////////////////////////////////////////////
// inslude the SPI library:
#include <SPI.h>
// set pin 10 and 11 as the chip select
const int nCS0 = 8;
const int nCS1 = 11;
const int nLDAC = 12;
const int nSHDN = 9;
const int GAINx1 = 1;
const int GAINx2 = 0;
const int Write_to_DACA = 0;
const int Write_to_DACB = 1;
const int BUF = 1;
const int nSHDown = 1;
// analog potentiometer joystick
int joystickBlue = A1;
int AnalogValue = 0; //to store the value here
void setup() {
pinMode(nCS0, OUTPUT);
pinMode(nCS1, OUTPUT);
pinMode(nLDAC, OUTPUT);
pinMode(nSHDN, OUTPUT);
// Set shutdown pin to high
digitalWrite(nSHDN, HIGH);
// initialize the nLDAC to high
pinMode(nLDAC, HIGH);
// initialize SPI:
SPI.begin();
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
Serial.begin(115200);
}
void loop() {
// analog values
AnalogValue = analogRead(joystickBlue);
// Write to DA
String myBinString = String(Write_to_DACA) + String(BUF) + String(GAINx2)+ String(nSHDown) + ConvertInt2Bin12(3000);
// Write to DB
String myBinStringB =String(Write_to_DACB) + String(BUF) + String(GAINx2)+ String(nSHDown) + ConvertInt2Bin12(2048);
Serial.println(myBinString);
int tempA = ConvertBin2Dec(myBinString);
Serial.println(tempA, HEX);
Serial.println(" ");
Serial.println(myBinStringB);
int tempB = ConvertBin2Dec(myBinStringB);
Serial.println(tempB, HEX);
Serial.println(" ");
delay(500);
digitalWrite(nCS0, LOW); //Enable the chip U4 for X output
SPI.transfer16(tempA);
digitalWrite(nCS0, HIGH);
digitalWrite(nCS0, LOW);
SPI.transfer16(tempB);
digitalWrite(nCS0, HIGH);
Latch_DAC_Input();
}
void DAC_Write(int address, int value, int CSNum){
// Do the chip select value
if (CSNum == 0) {
digitalWrite(nCS0, LOW);
}else if (CSNum == 1) {
digitalWrite(nCS1, LOW);
}
// send in the address and value via SPI:
SPI.transfer(address);
SPI.transfer(value);
if (CSNum == 0) {
digitalWrite(nCS0, HIGH);
}else if (CSNum == 1) {
digitalWrite(nCS1, HIGH);
}
}
void Latch_DAC_Input(){
//toggle the nLDAC to output voltage
digitalWrite(nLDAC, LOW);
digitalWrite(nLDAC, HIGH);
}
String ConvertInt2Bin12(int Value){
//this sub will convert any integer value to its corresponding 12 bit
String myString = String(Value, BIN);
int lenString = myString.length();
for ( int i=lenString; i<12; ++i){
myString = "0" + myString;
}
return myString;
}
int ConvertBin2Dec(String BinData){
//this sub will convert a 16 bit binary string to its equivalent HEX
int LenString = BinData.length();
double ValueDec = 1;
int DataOut = 0;
for ( int i = 0; i < LenString; i++){
String MyStr =BinData.substring(LenString-i-1, LenString-i);
if (MyStr == "0"){
// add a zero
}else{
//add a 2^i
ValueDec = pow(2,(float)i) + ValueDec;
}
}
DataOut = ValueDec;
return DataOut;
}
I've been using the microchip DAC to output a +/-5V output. I used the Arduino MEGA2560 to write to the SPI bus and it worked great. The code is as follows:
//pin# Pin Name Mapped Pin Name
//19 PB0 ( SS/PCINT0 ) Digital pin 53 (SS)
//20 PB1 ( SCK/PCINT1 ) Digital pin 52 (SCK)
//21 PB2 ( MOSI/PCINT2 ) Digital pin 51 (MOSI)
//22 PB3 ( MISO/PCINT3 ) Digital pin 50 (MISO)
////////////////////////////////////////////////////////////////////////////////////////////////////
//Microchip MCP4922-E/P
//Pin No. Symbol Function
//1 VDD Supply Voltage Input (2.7V to 5.5V)
//3 CS Chip Select Input
//4 SCK Serial Clock Input
//5 SDI Serial Data Input
//8 LDAC Synchronization Input. This pin is used to transfer DAC settings (Input Registers)
// to the output registers (VOUT)
//9 SHDN Hardware Shutdown Input
//10 VOUTB DACB Output
//11 VREFB DACB Reference Voltage Input (VSS to VDD)
//12 VSS Ground reference point for all circuitry on the device
//13 VREFA DACA Reference Voltage Input (VSS to VDD)
//14 VOUTA DACA Output
////////////////////////////////////////////////////////////////////////////////////////////////////
// inslude the SPI library:
#include <SPI.h>
// set pin 10 and 11 as the chip select
const int nCS0 = 8;
const int nCS1 = 11;
const int nLDAC = 12;
const int nSHDN = 9;
const int GAINx1 = 1;
const int GAINx2 = 0;
const int Write_to_DACA = 0;
const int Write_to_DACB = 1;
const int BUF = 1;
const int nSHDown = 1;
// analog potentiometer joystick
int joystickBlue = A1;
int AnalogValue = 0; //to store the value here
void setup() {
pinMode(nCS0, OUTPUT);
pinMode(nCS1, OUTPUT);
pinMode(nLDAC, OUTPUT);
pinMode(nSHDN, OUTPUT);
// Set shutdown pin to high
digitalWrite(nSHDN, HIGH);
// initialize the nLDAC to high
pinMode(nLDAC, HIGH);
// initialize SPI:
SPI.begin();
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
Serial.begin(115200);
}
void loop() {
// analog values
AnalogValue = analogRead(joystickBlue);
// Write to DA
String myBinString = String(Write_to_DACA) + String(BUF) + String(GAINx2)+ String(nSHDown) + ConvertInt2Bin12(3000);
// Write to DB
String myBinStringB =String(Write_to_DACB) + String(BUF) + String(GAINx2)+ String(nSHDown) + ConvertInt2Bin12(2048);
Serial.println(myBinString);
int tempA = ConvertBin2Dec(myBinString);
Serial.println(tempA, HEX);
Serial.println(" ");
Serial.println(myBinStringB);
int tempB = ConvertBin2Dec(myBinStringB);
Serial.println(tempB, HEX);
Serial.println(" ");
delay(500);
digitalWrite(nCS0, LOW); //Enable the chip U4 for X output
SPI.transfer16(tempA);
digitalWrite(nCS0, HIGH);
digitalWrite(nCS0, LOW);
SPI.transfer16(tempB);
digitalWrite(nCS0, HIGH);
Latch_DAC_Input();
}
void DAC_Write(int address, int value, int CSNum){
// Do the chip select value
if (CSNum == 0) {
digitalWrite(nCS0, LOW);
}else if (CSNum == 1) {
digitalWrite(nCS1, LOW);
}
// send in the address and value via SPI:
SPI.transfer(address);
SPI.transfer(value);
if (CSNum == 0) {
digitalWrite(nCS0, HIGH);
}else if (CSNum == 1) {
digitalWrite(nCS1, HIGH);
}
}
void Latch_DAC_Input(){
//toggle the nLDAC to output voltage
digitalWrite(nLDAC, LOW);
digitalWrite(nLDAC, HIGH);
}
String ConvertInt2Bin12(int Value){
//this sub will convert any integer value to its corresponding 12 bit
String myString = String(Value, BIN);
int lenString = myString.length();
for ( int i=lenString; i<12; ++i){
myString = "0" + myString;
}
return myString;
}
int ConvertBin2Dec(String BinData){
//this sub will convert a 16 bit binary string to its equivalent HEX
int LenString = BinData.length();
double ValueDec = 1;
int DataOut = 0;
for ( int i = 0; i < LenString; i++){
String MyStr =BinData.substring(LenString-i-1, LenString-i);
if (MyStr == "0"){
// add a zero
}else{
//add a 2^i
ValueDec = pow(2,(float)i) + ValueDec;
}
}
DataOut = ValueDec;
return DataOut;
}
Parallax Serial LCD Arduino Subroutines
Parallax Serial LCD
2 rows x 16 characters Non-backlit (#27976)
2 rows x 16 characters Backlit (#27977)
4 rows x 20 characters Backlit (#27979)
http://elmicro.com/files/parallax/seriallcd-v20.pdf
The best way to interface to this Serial LCD is to use the software serial library offered by Arduino environment. Be sure that the following is on your code.
///////////////////////// Libraries ///////////////////////////////
#include <SoftwareSerial.h>
//////////////////////// LCD Variables ///////////////////////////
SoftwareSerial mySerial(10, 11); // RX, TX
Then, write subroutines to initialize the LCD.
void initializeLCD(){
mySerial.begin(19200); //change per LCD
delay(500);
// put your setup code here, to run once:
mySerial.write(12);
delay(5);
}
Subroutines to control the screen
void LCD_clearScreen(){
mySerial.write(12);
delay(10);
}
void Turn_backlight_on_LCD(){
mySerial.write(17);
delay(5);
}
void Turn_backlight_off_LCD(){
mySerial.write(18);
delay(5);
}
void Line_Feed_LCD(){
mySerial.write(12);
delay(5);
}
void Carriage_Return_LCD(){
mySerial.write(13);
delay(5);
}
void Move_Cursor(int line, int pos){
switch (line){
case 0:
mySerial.write(128 + pos);
delay(5);
break;
case 1:
mySerial.write(148 + pos);
delay(5);
break;
case 2:
mySerial.write(168 + pos);
delay(5);
break;
case 3:
mySerial.write(188 + pos);
delay(5);
break;
default:
// do nothing
break;
}
delay(5);
}
To write the a float value onto the LCD, it would work best if it was converted to a string as described below using dtostrf function
void LCD_floatValue(){
int StringLen = 7;
int numVarAfterDec = 3;
static char outstr[15]; // the array to store the results
static float f_val = Lever_Position;
dtostrf(Lever_Position,7, 1, outstr);
Move_Cursor(0,0);
delay(5);
mySerial.print("Value ");
mySerial.println (outstr);
}
2 rows x 16 characters Non-backlit (#27976)
2 rows x 16 characters Backlit (#27977)
4 rows x 20 characters Backlit (#27979)
http://elmicro.com/files/parallax/seriallcd-v20.pdf
The best way to interface to this Serial LCD is to use the software serial library offered by Arduino environment. Be sure that the following is on your code.
///////////////////////// Libraries ///////////////////////////////
#include <SoftwareSerial.h>
//////////////////////// LCD Variables ///////////////////////////
SoftwareSerial mySerial(10, 11); // RX, TX
Then, write subroutines to initialize the LCD.
void initializeLCD(){
mySerial.begin(19200); //change per LCD
delay(500);
// put your setup code here, to run once:
mySerial.write(12);
delay(5);
}
Subroutines to control the screen
void LCD_clearScreen(){
mySerial.write(12);
delay(10);
}
void Turn_backlight_on_LCD(){
mySerial.write(17);
delay(5);
}
void Turn_backlight_off_LCD(){
mySerial.write(18);
delay(5);
}
void Line_Feed_LCD(){
mySerial.write(12);
delay(5);
}
void Carriage_Return_LCD(){
mySerial.write(13);
delay(5);
}
void Move_Cursor(int line, int pos){
switch (line){
case 0:
mySerial.write(128 + pos);
delay(5);
break;
case 1:
mySerial.write(148 + pos);
delay(5);
break;
case 2:
mySerial.write(168 + pos);
delay(5);
break;
case 3:
mySerial.write(188 + pos);
delay(5);
break;
default:
// do nothing
break;
}
delay(5);
}
To write the a float value onto the LCD, it would work best if it was converted to a string as described below using dtostrf function
void LCD_floatValue(){
int StringLen = 7;
int numVarAfterDec = 3;
static char outstr[15]; // the array to store the results
static float f_val = Lever_Position;
dtostrf(Lever_Position,7, 1, outstr);
Move_Cursor(0,0);
delay(5);
mySerial.print("Value ");
mySerial.println (outstr);
}
Labels:
Arduino,
dtostrf,
MEGA2560,
Parallax Code,
Serial LCD
Location:
Pasadena, CA, USA
L298 Motor Driver with Arduino MEGA2560
Arduino MEGA 2560
This is my first blog about the Mega2560. It has become a very useful tool for rapid prototyping and making simple project. When I say simple I mean simple but useful.
I recently connected a DC Motor that required a potentiometer as a sensor and a motor driver (L298).
Arduino, you can buy anywhere nowadays. I usually buy mine from sparkfun $46
(https://www.sparkfun.com/products/11061)
L298 Driver: I also buy this from Sparkfun $35
(https://www.sparkfun.com/products/9670)
Connect the motor signals according to the Arduino declarations below:
////////////////////////// Motor Driver #1 Signals /////////////////////////////
const int MOT1_EN = 26;
const int MOT1_IN1 = 22;
const int MOT1_IN2 = 24;
const int MOT1_CSA = A4;
const int MOT1_CSB = A5;
const int POT = A0;
Initialize the motor signals before using.
pinMode(MOT1_IN1, OUTPUT);
pinMode(MOT1_IN2, OUTPUT);
pinMode(MOT1_EN, OUTPUT);
pinMode(MOT1_CSA, INPUT);
pinMode(MOT1_CSB, INPUT);
Create subroutine to move the motors Clockwise and counter clock wise.
void Motor1_CC(){
digitalWrite(MOT1_EN, HIGH);
delay(1);
digitalWrite(MOT1_IN1, HIGH);
digitalWrite(MOT1_IN2, LOW);
}
void Motor1_CCW(){
digitalWrite(MOT1_EN, HIGH);
delay(1);
digitalWrite(MOT1_IN1, LOW);
digitalWrite(MOT1_IN2, HIGH);
}
Write routines to break and coast motors
void Motor1_FastBrake(){
//this routine will brake the motor A quickly
digitalWrite(MOT1_EN, HIGH);
delay(1);
digitalWrite(MOT1_IN1, LOW);
digitalWrite(MOT1_IN2, LOW);
}
void Motor1_Coast(){
//this routine will coast Motor A
digitalWrite(MOT1_EN, LOW);
delay(1);
digitalWrite(MOT1_IN1, LOW); //irrelevent
digitalWrite(MOT1_IN2, LOW); //irrelevent
}
Now we are ready to write our code according to the project requirements. I would read the analog value for the potentiometer and move the motors using the routines as needed.
Enjoy!
Location:
Pasadena, CA, USA
Subscribe to:
Posts (Atom)