The ForceTronics blog provides tutorials on creating fun and unique electronic projects. The goal of each project will be to create a foundation or jumping off point for amateur, hobbyist, and professional engineers to build on and innovate. Please use the comments section for questions and go to forcetronics.com for information on forcetronics consulting services.
In part two of this 4 or 5 part series, we look at how the Successive Approximation or SAR ADC architecture works and understand its limitations. Note SAR based ADC architecture is what you typically find in microcontrollers.
In this video series we look at ways or tips to improve ADC measurement accuracy and resolution. In part 1 define what accuracy and resolution is and different types of error that can affect ADC measurements. We also look at the importance of using an accurate ADC reference voltage and why you want to scale the range of the signal you are measuring to the ADC's range.
//***************Arduino code used in video******************************* /*This code demonstrates how to change the ADC voltage reference on an Arduino * This was shown in an ADC tutorial on the ForceTronics YouTube Channel. * This code is free and open for anybody to use at their own risk. */ void setup() { Serial.begin(115200); //setup serial connection while(!Serial); analogReference(AR_EXTERNAL); //sets the ADC reference voltage to external (input is aRef pin) //analogReference(AR_DEFAULT); //set the ADC reference to default which is AVCC (uses power supply voltage or VCC as reference) //analogReference(AR_INTERNAL2V23); //uses 2.23V internal reference in SAMD21 uC analogReadResolution(12); //Set ADC to 12bit resolution, default is 10 burn8Readings(); //make 8 readings but don't use them to ensure good reading after reference change delay(100); for(int i=0;i<500;i++) { //loop through a bunch of ADC readings and print them to serial plotter Serial.println(analogRead(A0)); //Make ADC measurement at A0 } } void loop() { //don't need the loop } //This function makes 8 ADC measurements but does nothing with them //Since after a reference change the ADC can return bad readings at first. This function is used to get rid of the first //8 readings to ensure an accurate one is displayed void burn8Readings() { for(int i=0; i<8; i++) { analogRead(A0); delay(1); } }
Two part tutorial on digital to analog converters (DAC). In part 2 we take a look at the capabilities of the MCP4728 which is a four channel DAC controlled via I2C. See the links below to access the code and get the PCB design from the video at PCBWay.
Link for PCB board at PCBWay: https://www.pcbway.com/project/shareproject/W08904ASW106_DAC_Example_Gerber.html
//**********Arduino Code with MCP4728 examples from video*************** /* * This code was written to demonstrate functions on the MCP4728 4 channel DAC for a video on the ForceTronics YouTube channel * This sketch leverages a library from GitHub made by Hideakitai, link to library: https://github.com/hideakitai/MCP4728 * This code is public domain and free to anyone to use and modify with no restrictions at your own risk */ #include <Wire.h> #include "MCP4728.h" MCP4728 dac; //create object to library //variables for wavform int const sampleCount = 24; //samples to read to have a buffer int signalSamples[sampleCount]; //create array to hold signal or waveform float pi2 = 6.283; //value of pi times 2 const long clkFrequency = 400000; //I2C clock frequency const uint8_t t1 = 3; //pin to setup test 1 fast sinewave const uint8_t t2 = 4; //pin to setup test 2 sync'd sinewaves const uint8_t LDAC = 5; //Output pin on MCU to control LDAC(not) pin on DAC void setup() { //Create sinewave float in; float hBit = 2047.5; for (int i=0;i<sampleCount;i++) { in = pi2*(1/(float)sampleCount)*(float)i; signalSamples[i] = (int)(sin(in)*hBit + hBit); } pinMode(t1,INPUT_PULLUP); //configure test check pins pinMode(t2,INPUT_PULLUP); //configure test check pins pinMode(LDAC,OUTPUT); //configure test check pins digitalWrite(LDAC,HIGH); //turn DAC outputs off Wire.begin(); //start up I2C library Wire.setClock(clkFrequency); //set clock frequency for I2C comm dac.attatch(Wire, 13); //second argument is Arduino pin connected to LDAC(not), we are controlling LDAC manually so just entered pin we are not using dac.readRegisters(); //Used to read current settings from MCP4728 dac.selectVref(MCP4728::VREF::VDD, MCP4728::VREF::VDD, MCP4728::VREF::VDD, MCP4728::VREF::VDD); //setup voltage ref for each DAC channel dac.selectPowerDown(MCP4728::PWR_DOWN::NORMAL, MCP4728::PWR_DOWN::NORMAL, MCP4728::PWR_DOWN::NORMAL, MCP4728::PWR_DOWN::NORMAL); //set power down mode, used for saving power dac.selectGain(MCP4728::GAIN::X1, MCP4728::GAIN::X1, MCP4728::GAIN::X1, MCP4728::GAIN::X1); //set gain on output amp //dac.enable(true); //enables the DAC outputs by controlling LDAC pin, but we are controlling LDAC manually in this example //perform test one if(!digitalRead(t1)) { digitalWrite(LDAC,LOW); //output sinewave as fast as we can for(;;) { //run test for infinitity for(int j=0;j<sampleCount;j++) { dac.analogWrite(MCP4728::DAC_CH::A,signalSamples[j]); } } } else { //perform test 2 for(;;) { //run test for infinitity for(int j=0;j<sampleCount;j++) { int temp = j; digitalWrite(LDAC,HIGH); //turn outputs off // delay(1); dac.analogWrite(MCP4728::DAC_CH::A,signalSamples[temp]); temp += 8; //shift sigal 90 degrees if(temp > 23) temp -= sampleCount; dac.analogWrite(MCP4728::DAC_CH::B,signalSamples[temp]); temp += 8; //shift sigal 90 degrees if(temp > 23) temp -= sampleCount; dac.analogWrite(MCP4728::DAC_CH::C,signalSamples[temp]); temp += 8; //shift sigal 90 degrees if(temp > 23) temp -= sampleCount; dac.analogWrite(MCP4728::DAC_CH::D,signalSamples[temp]); digitalWrite(LDAC,LOW); //turn outputs on all four outputs at same time // delay(1); } } } } void loop() { }
In this video we go over what a digital to analog converter (DAC) is and how it works. We then focus on the MCP4728 4 Channel DAC with some simple examples. In part two we do a deeper dive into the MCP4728.
In this video we unbox Particle's new IoT Mesh Network series (Argon, Boron, Xenon). We take a look both the hardware and the software that allows you to easily create a cloud connected mesh network. Link to product page: https://www.particle.io/mesh
//******************Code from Video***************************************** // ----------------------------------- // Controlling LEDs over the Internet // ----------------------------------- // First, let's create our "shorthand" for the pins // Same as in the Blink an LED example: // led1 is D0, led2 is D7 int led1 = D0; int led2 = D7; // Last time, we only needed to declare pins in the setup function. // This time, we are also going to register our Particle function void setup() { // Here's the pin configuration, same as last time pinMode(led1, OUTPUT); pinMode(led2, OUTPUT); // We are also going to declare a Particle.function so that we can turn the LED on and off from the cloud. Particle.function("led",ledToggle); // This is saying that when we ask the cloud for the function "led", it will employ the function ledToggle() from this app. // For good measure, let's also make sure both LEDs are off when we start: digitalWrite(led1, LOW); digitalWrite(led2, LOW); } // Last time, we wanted to continously blink the LED on and off // Since we're waiting for input through the cloud this time, // we don't actually need to put anything in the loop void loop() { // Nothing to do here } // We're going to have a super cool function now that gets called when a matching API request is sent // This is the ledToggle function we registered to the "led" Particle.function earlier. int ledToggle(String command) { /* Particle.functions always take a string as an argument and return an integer. Since we can pass a string, it means that we can give the program commands on how the function should be used. In this case, telling the function "on" will turn the LED on and telling it "off" will turn the LED off. Then, the function returns a value to us to let us know what happened. In this case, it will return 1 for the LEDs turning on, 0 for the LEDs turning off, and -1 if we received a totally bogus command that didn't do anything to the LEDs. */ if (command=="on") { digitalWrite(led1,HIGH); digitalWrite(led2,HIGH); Particle.publish("LED State", "ON"); return 1; } else if (command=="off") { digitalWrite(led1,LOW); digitalWrite(led2,LOW); Particle.publish("LED State", "OFF"); return 0; } else { return -1; } }
In this series we look at how to design a Thermocouple temperature measurement circuit. In part 2 we look at a real world example of a Thermocouple J Type circuit design and discuss some of the common sources of error and how to avoid them.
In this series we look at how to design a Thermocouple temperature measurement circuit. In part 1 we look at Thermocouple theory, pros and cons versus other temperature measurement techniques, and an overview of a measurement hardware circuit as well as calculations done in software.