arduino

Topics related to arduino:

Getting started with arduino

What is Arduino?

Arduino is an open-source electronics platform based on easy-to-use hardware and software.

Why Use Arduino?

  • Inexpensive. You can also buy clones that are even cheaper.
  • Easy to use and get started with
  • Huge community
  • Completely Open Source

PWM - Pulse Width Modulation

Digital Inputs

If the input pin is not pulled LOW or HIGH, the value will float. That is, it won't be clearly a 1 or a 0, but somewhere in between. For digital input, a pullup or pulldown resistor is a necessity.

Serial Communication

The Arduino Mega has four serial ports which there can be choosed from. They are accesed in the following way

  Serial.begin(9600);
  Serial1.begin(38400);
  Serial2.begin(19200);
  Serial3.begin(4800);

The serial port on an Arduino can be set with additional parameters. The config parameter sets data bits, parity, and stop bits. For example:

8 data bits, even parity and 1 stop bit would be - SERIAL_8E1

6 data bits, odd parity and 2 stop bit would be - SERIAL_6O2

7 data bits, no parity and 1 stop bit would be - SERIAL_7N1

Random Numbers

If randomSeed() is called with a fixed value (eg. randomSeed(5)), the sequence of random numbers generated by the sketch will repeat each time it is run. In most cases, a random seed is preferred, which can be obtained by reading an unconnected analog pin.

Functions

Analog Inputs

Audio Output

Digital Output

Bluetooth Communication

Common Mistake : If you keep the rx and tx pins at default values (0 and 1), you cannot upload new code until and unless you remove it, so it's almost always better to change the tx and rx pins in the SoftwareSerial constructor.

Variables and Data Types

Using Arduino with Atmel Studio 7

Setup

  • Download and install Atmel Studio 7 from here.
  • Purchase a debugger. You can get by with a ISP programmer, but if you want debugging capabilities, which is one of the big advantages of using Atmel Studio, you will want a debugger. I recommend the Atmel ICE, as it provides debugging capabilities for AVR based arduinos (like the Uno, pro mini, etc) and the ARM based Arduinos, such as the Zero and Due. If you are on a budget, you can get it without the plastic case and be careful not to shock it.

Connections

  • For the Uno, use the 6-pin ICSP cable. Plug one side into the Uno as shown. Plug the other side into the debugger's AVR port.

enter image description here

For the Arduino Pro Mini, use the mini squid cable as shown, again connecting the other side the debugger's AVR port.

enter image description here

Debugging considerations

For debugging with the Uno, you will need to cut the Reset-enable trace (you can always solder it back for using with the Arduino IDE):

enter image description here

Using the Pro Mini, if you intend to connect the serial port to your computer using an FTDI board, do not connect the DTR line, as it will interfere with Atmel's Serial Wire Debug (SWD) interface. I simply connect power, ground, Tx and Rx as shown here below. Rx and Tx on Arduino go to Tx and Rx, respectively on FTDI board. Some FTDI boards are labeled differently, so if the serial port doesn't work, swap Rx and Tx.

enter image description here

You will have to provide power separately to the Arduino because the debugger will not power it. This can be done on the Pro Mini through the FTDI board as shown above, or with a USB cable or AC adaptor on the Uno.

Software setup

Plug the Atmel ICE into your computer, start Atmel Studio and you can now import an existing Arduino project.

In Atmel Studio, go to File -> New -> Project and select "Create project from Arduino sketch". Fill out options including board and device dropdown menus.

Go to Project -> yourProjectName Properties, click on Tool, select Atmel ICE under debugger/programmer and debugWire under interface. Go to Debug -> Start debugging and break. You should see a warning and be asked if you want to set the DWEN fuse. Choose OK, unplug the Arduino from power and plug it in again. You can stop debugging by clicking the red square button and start by clicking the green triangle button. To return the Arduino to a state that it can be used in the Arduino IDE, while you're debugging, choose Debug -> disable debugWIRE and close.

Note that any functions you add must include a function prototype as well (loop and setup don't need them). You can see the ones Atmel Studio added at the top of the sketch if there were any functions when you imported your project into Atmel Studio (see sample code for example).

C++11 support is enabled by default in Arduino 1.6.6 and above. This provides more C++ language features and enabling it may increase compatibility with the Arduinio system. To enable C++11 in Atmel Studio 7, right click on your project file, select properties, click on ToolChain on the left, Click on Miscellaneous under AVR/GNU C++ Compiler and put -std=c++11 in the Other flags field.

To include libraries in your sketch

Copy the .cpp library file into C:\Users\YourUserName\Documents\Atmel Studio\7.0\YourSolutionName\YourProjectName\ArduinoCore\src\core, then in Atmel Studio, open the Solution Explorer window right click on the Arduino Core/src/core folder, choose add -> existing item and choose the file you added. Do the same with the .h library file and the YourProjectName/Dependancies folder.

To add the terminal window

You can always have the Android IDE open and use that Serial window (just select the correct serial port), however to add a built in Serial window to Atmel Studio, go to Tools -> Extensions and Updates, click on Available downloads and search for Terminal Window or Terminal for Atmel Studio and install it. Once installed, go to View -> Terminal Window.

Benefits

Programming Arduino with a moder IDE like Atmel Studio 7 gives you numerous advantages over the Arduino IDE, including debugging, autocompletion, jump to definition and declaration, forward/backward navigation, bookmarks and refactoring options to name a few.

You can configure key bindings by going to Tools -> Options -> Environment -> Keyboard. Some that really speed up development are:

  • Edit.CommentSelection, Edit.UncommentSelection
  • View.NavigateForward, View.NavigateBackward
  • Edit.MoveSelectedLinesUp, Edit.MoveSelectedLinesDown
  • Edit.GoToDefinition

Loops

General Remark If you intend to create a loop to wait for something to happen, you're probably on the wrong track here. Rather remember that all code after setup() is run from a method called loop(). So if you need to wait for something, it's easiest to not do anything (or only other independent stuff) and come back to check for the waiting condition next time.

do { } while(condition) will not evaluate the condition statement until after the first iteration. This is important to keep in mind if the condition statement has side effects.

Interrupts

Interrupt Service Routines (ISRs) should be as short as possible, since they pause main program execution and can thus screw up time-dependent code. Generally this means in the ISR you set a flag and exit, and in the main program loop you check the flag and do whatever that flag is supposed to do.

You cannot use delay() or millis() in an ISR because those methods themselves rely on interrupts.

Arduino IDE

Hardware pins

Time Management

Blocking vs. non-blocking code

For very simple sketches, writing blocking code using delay() and delayMicroseconds() can be appropriate. When things get more complex, using these functions can have some drawbacks. Some of these are:

  • Wasting CPU time: More complex sketches might need the CPU for something else while waiting for an LED blinking period to end.
  • unexpected delays: when delay() is called in subroutines that are not obviously called, for example in libraries you include.
  • missing events that happen during the delay and are not handled by an interrupt handler, for example polled button presses: A button might be pressed for 100 ms, but this might be shadowed by a delay(500).

Implementation details

millis() usually relies on a hardware timer that runs at a speed that's much higher than 1 kHz. When millis() is called, the implementation returns some value, but you don't know how old that actually is. It's possible that the "current" millisecond just started, or that it will end right after that function call. That means that, when calculating the difference between two results from millis(), you can be off by anything between almost zero and almost one millisecond. Use micros() if higher precision is needed.

Looking into the source code of elapsedMillis reveals that it indeed uses millis() internally to compare two points in time, so it suffers from this effect as well. Again, there's the alternative elapsedMicros for higher precision, from the same library.

SPI Communication

Chip select signals

Most slaves have an active low chip select input. So proper code to initialize and use a chip select pin is this:

#define CSPIN 1 // or whatever else your CS pin is
// init:
pinMode(CSPIN, OUTPUT);
digitalWrite(CSPIN, 1); // deselect

// use:
digitalWrite(CSPIN, 0); // select
... perform data transfer ...
digitalWrite(CSPIN, 1); // deselect

Deselecting a slave is just as important as selecting it, because a slave may drive the MISO line while it is selected. There may be many slaves, but only one may drive MISO. If a slave is not deselected properly, two or more slaves might be driving MISO, which may lead to shorts between their outputs and might damage the devices.

Transactions

Transactions serve two purposes:

  • tell the SPI when we want to start and end using it within a particular context
  • configure the SPI for a specific chip

The clock line has different idle states in the different SPI modes. Changing the SPI mode while a slave is selected might confuse the slave, so always set the SPI mode before selecting a slave. The SPI mode can be set with an SPISettings object passed to SPI.beginTransaction:

SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
digitalWrite(CSPIN, 0);
... perform data transfer ...
digitalWrite(CSPIN, 1);
SPI.endTransaction();

SPISettings may also be stored elsewhere:

SPISettings mySettings(1000000, MSBFIRST, SPI_MODE0);
SPI.beginTransaction(mySettings);

If another part of the code tries to use the SPI between a pair of calls to beginTransaction() and endTransaction(), an error may be raised - how that is done depends on the implementation.

Also see Arduino Reference: SPISettings

Using the SPI in Interrupt Service Routines

If the SPI has to be used within an ISR, no other transaction may be taking place at the same time. The SPI library provides usingInterrupt(interrupt_number) to facilitate this. It works by disabling the given interrupt whenever beginTransaction() is called, so the interrupt cannot fire between that pair fo calls to beginTransaction() and endTransaction().

Also see Arduino Reference: SPI: usingInterrupt

Servo

How to store variables in EEPROM and use them for permanent storage

Data Storage

How Python integrates with Arduino Uno

I use an Arduino Uno with Arduino IDE 1.6.9 and Python 2.7.12 running in Windows 10.

Libraries

I2C Communication

Liquid Crystal Library

MIDI Communication