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;
}


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);  
}

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). 

Where to buy:
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!