Programming microcontrollers


Contents




1       Microcontrollers, development boards, Arduino - what is it?

[Werbung ohne Auftrag / unpaid advertisement]
Microcontroller units (MCU) integrate the calculation power of a CPU with a clock, EEPROM and memory, inputs, outputs in one chip. For prototyping, development boards with a microcontroller at their heart are available. They make soldering obsolete by adding sockets, peripherals and security measures (e.g. voltage regulators and optocouplers) to the pins of the microchip. The standard for simple tasks is a 8 bit MCU. The Arduino UNO became a very popular development board because the schematics are open-source and it was designed for ease of use. The Arduino UNO Rev.3 features a Microchip Atmega328P 8bit microcontroller clocked at 16 MHz with a preloaded Arduino bootloader, as well as a Microchip ATmega16U2 microcontroller with a preloaded Device Firmware Update (DFU) bootloader and the Arduino USB-to-Serial firmware for ATmega16U2 that enables USB-to-Serial conversion (serial communication via USB1.0 (used a virtual serial port) and programming of the Atmega328P via USB. The Atmega328 microcontroller can be programmed by uploading custom firmware via USB or via ISP. The firmware (“sketch”) can be written in Assembler, C  (ANSI-C, ISO/IEC 9899:1990 and parts of C99 with compiler extensions, compare with the Rationale for International Standard— Programming Languages— C, ISO WG14 Document Number N897 and the latest C99 standard with technical corrigendum 3, ISO/IEC 9899:1999 Cor. 3:2007(E) - The latest publicly available draft of the C99 standard with corrigenda is WG14 Document Number N1256 from 2007) or C++14 (ISO/IEC 14882:2014, see publicly available working draft: Document Number N4296 by the ISO/IEC JTC1 (Joint Technical Committee 1) / SC22 (Subcommittee 22) / WG21 (Working Group 21)). Be aware of the limitation, that the AVR-GCC C compiler avr-gcc.exe does not fully support C99: there is no ISO/IEC 9899:1990- and ANSI/IEEE Std 754-1985 / IEC 60559:1989-compliant double prescission floating point arithmetic and complex types and missing implementation of standard pragmas for AVR-gcc with AVR-libC. For C++, an additional limitation of the compiler AVR-g++ = AVR-c++ is, that AVR-libC does not support exception handling using the commands try{}, throw{} and catch{}
AVRDUDE is a command line interface for uploading compiled and linked programs (via USB and other connections) to Microchip Atmel AVR MCUs using ISP. It was created by Brian S. Dean and is now part of the open source avr-toolchain by Microchip Atmel. Hernando Barragán developed the open source development platform Wiring with the Wiring library and the USB development board “Wiring board” during his Master’s thesis at Interactive Design Institute Ivrea under the supervision by Massimo Banzi and Casay Reas. The Wiring library provides a high level hardware abstraction layer (HAL) on top of the avr/io.h C++ library by Microchip Atmel and uses an API that closely mimicked the API of Reas’ programming language Processing. Banzi and Reas who had developed the simple Processing integrated development environment (IDE) that was distributed together with the Wiring and Processing development environments, forked the Wiring repository and founded Arduino Inc. They made more affordable USB development boards that come with a DFU bootloader burned into a USB-to-Serial bridge chip. Together with the adapted Processing IDE (called Arduino IDE) and resources that document the Wiring API (called the “Arduino language reference”) and it’s application, the Arduino framework became popular. Together with the Arduino UNO development board, a rich ecosystem has evolved. A manifold of extension modules, called “shields”, fit the Arduino UNO pin layout exactly and can be stacked on top of each other and onto the sockets of the Arduino UNO compatible development boards. The success of Arduino led to the advent of a huge variety of no-name development boards that are compatible to the Arduino UNO or Arduino MEGA and even cheap clones that sometimes use the trade name Arduino without being authorized. They are advertised as having the same pin layout, same microprocessor, same functions as the Arduino UNO plus sometimes extra functions and improvements). Because the Arduino UNO compatible development boards are so readily available, a rich ecosystem has evolved around it. A manifold of extension modules, called “shields”, fit the Arduino UNO pin layout exactly and can be stacked on top of each other and onto the sockets of the Arduino UNO compatible development boards. A cheaper alternative is the mbed ecosystem. For projects that require more periphery and calculation power, 32 bit microcontrollers are a better choice. The Teensy 3.6 comes with a 12 bit Digital-Analog converter (DAC) and 10 bit ADC and supports many libraries, including an advanced audio library with a graphical user interface that enables additive- and wavetable sound synthesis. The Arduino Due and cheaper Arduino Due compatible boards provide similar periphery and come with USB2.0 functionality that is capable of high speed USB (480 Mbit/s) in device mode and host mode. If more flexibility and speed for bigger projects is needed, one should consider using an FPGA alongside- or instead of a microcontroller. Big FPGAs are built around a CPU and/or can be programmed to contain softcores (integrated microcontrollers made from the logic gates of the FPGA).

1.1       Microcontrollers and electric circuits: a customized starter kit

You may consider the following items for your customized starter kit:
Artikel
#
Price/€
1
22,90
1
9,17
1
17,88
1
11,99
0
9,99
0
9,99
1
15,99
1
12,99
0
22,00
1
29,95
1
10,50
1
16,64
1
1,79
2
3,10
2
2,20
8
9,60
8
8,40

2       Using Sloeber and Bio7 / Eclipse for physical programming in C++

In my opinion, physical programming in C++ is a great way to get to know the principles of programming. There are many practical example projects available online that make use of the Arduino Uno or compatible development boards to which programs written in C++ (without error handling using try{}, throw{} or catch{}, see section 1) can be uploaded. Most importantly you get instant real-world feedback from your program when you upload it to the microcontroller device. If you want to learn programming or test your code, you can use simulator software where you can build a virtual circuit including a microcontroller device, load your code and simulate the program execution. Autodesk circuits feature of the tinkercad online tool by Autodesk (tinkercad.com) contains a digital circuit simulator that supports a virtual Arduino Uno Rev.3 development board building block that can be integrated into virtual circuits. The Arduino Simulator 1.5 by Xevro.be is a standalone program for offline-use and available for free. Similarly, Proteus is commercially available from labcenter.com and contains a more sophisticated simulator that makes use of Splice models of various microcontrollers.

2.1       Installation of the Sloeber plugin

The Sloeber product bundle for physical programming of microcontroller devices is easy to install. Under Microsoft Windows you simply have to unpack the downloaded folder and move the folder “sloeber” directly to the system partition to do so. For Bio7, move the folder into the folder Bio7/plugins or install the plugin via the Eclipse marketplace client or via Help à Install New Software. On computers with Microsoft Windows as the operating system, it comes with MinGW which provides the GNU compiler collection (gcc) and the GNU Debugger (GDB). Depending on the system, the environment variables might have to be edited to add MinGW and the gcc.exe, eclipse and Sloeber to the system Path. Start Eclipse with the sloeber add-on by double clicking the file sloeber.exe in the folder sloeber or by double-clicking a short-cut to the Bio7.exe. In the Eclipse menu select Windows -> preferences -> C/C++ -> file types -> new and enter *.ino as filename and C++ source file as type and click “Apply”. In Bio7, the same menu entry can be found by clicking Preferences -> Preferences -> ….
In addition, inside Bio7/Eclipse, specify the path the executable file MinGW.exe in the menu Preferences -> Preferences -> C/C++ -> Build -> Environment -> Add. In the text field for the variable, type “PATH” (without “”), in the text field for the value, type the path to the executable files mingw32-c++.exe, mingw32-g++.exe, mingw32-gcc and gdb.exe, in my case “C:/Bio7/arduinoPlugin/packages/Jantje/tools/MinGW/5.3.0” (without “”) and click “Apply”.

2.2       Creation of a new “Arduino Sketch” project


Go to Preferences -> Arduino and add folders with private libraries and hardware definitions. In Preferences -> Arduino -> LibraryManager you can add online libraries, in Platforms and Boards, you can add board definitions and Platforms. Select the following boards:
Arduino -> Arduino AVR boards as well as all boards from the folder Jantje.

If you want to use the hardware abstraction layer of the Arduino IDE within Eclipse, add the following code at the top of the project main fileProjectname.ino: (compare section 5.2):
#include <Arduino.h>

#include <stdlib.h> #include <string.h> #include <math.h> #include <avr/interrupt.h> #include "wiring.h" #ifdef __cplusplus #include "HardwareSerial.h" #endif

As soon as a program is complete and does not contain any syntax error, it can be verified and then compiled. In the Sloeber toolbar, first click on verify, then click on upload sketch and choose the option to build before uploading. During compilation, the compiler creates a program in machine code that is executable by hardware. Sloeber uses the AVR-GCC toolchain which includes the GNU compiler collection (GCC, consisting of the GNU C compiler (gcc) and the GNU C++ compiler (g++)) for translation of the C/C++ code into machine language that is executable by the Atmel AVR chips, as well as the programmer AVRDUDE for uploading scripts onto the Atmel AVR chip. If files with the file extension .ino are compiled using Sloeber (or the Arduino IDE), header files (.h) and a source file (main.cpp) with the code main(void) {init(); setup(); for(;;) loop(); return 0} is added to the main.cpp file before compilation.

I recommend to have a look the following online libraries that are supported by Sloeber: Encoder, ArduinoJSON, CaptureTimer, Gaussian, HardWire, LinkedList, OctoPrintAPI, TMRpcm, CONNECTIONS -> Adafruit_mp3, ArduinoFFT, Neurona, Plotter, pRNG, RAMP, DEVICE CONTROL -> absmouse, AccelStepper, Brushless Servo, Dynamixel_Servo, EEPROMextend, Firmata, FirstBuild – Relay, MIDIUSB, Mouse, MP3Player, PWMServo, Relay, Servo, Stepper, StepperControl, XYZrobotServo, OTHER -> PlotPlus, Voltage Reference, SIGNAL INPUT/OUTPUT -> FreqCount, FreqMeasure, HalfStepper, MorePins, Pin, ResponsiveAnalgRead, RotaryEncoder, SmoothADC, SoftPWM.

2.3       Local debugging and unit testing of code for microcontrollers

If you are new to coding, consider skipping this chapter for now and continue reading below. Based on a tutorial for an older version of Sloeber I found out how to perform software debugging code for compatible microcontrollers locally on a personal computer. The instructions for unit testing are based on this tutorial and included in square brackets, if deviating. A more advanced tutorial can be found on http://mitchtronic.blogspot.com/2017/03/setting-up-google-test-google-mock.html . Unit tests can be used in test-driven development (test-first development) to prevent both, bugs and bad code structure.

1)      [For unit testing, make sure that under Preferences -> Preferences -> Arduino the library gtest is installed (see paragraph 3). In the project explorer, rightclick on the Project and from the context menu choose Import -> Import Arduino libraries into the current project -> gtest. (Alternative: Arduino -> Add a library to the current project -> gtest). Right-click on the project and left-click New -> Source file. Keep the project name as the source folder, enter a name, e.g. projectnamegtest.cpp and enter at least the following code:
// Do not remove the include below
#ifdef UNITTEST
#include "gtest.h"
#include "projectname.h"

// Enter your tests here using the command
// TEST(testname, state) {
// …
// EXPECT_EQ (variable, expectvalue);
// }

#endif


]
2)     In the project explorer, rightclick on the Project and from the context menu choose Properties -> Arduino -> Manage configurations -> New). Enter the name of the debug configuration (e.g. {“LocalDebug”} [“UnitTest”]). Keep the default options (copy settings from: existing configuration: Release) and leftclick OK.
3)     Leftclick the newly created configuration and leftclick Set Active.
4)     Leftclick Verify/Compile
5)     For the setting Configuation, choose the newly created configuration from the dropdown menu and for the setting platform folder, select …/packages/Jantje/hardware/pc/1.0.2. Select the correct board, e.g. Arduino Uno and the upload protocol Default and for the setting Debug or unit test, select {“Debug”} [“unit test”] from the dropdown menu and leftclick “Apply and Close”.
6)     Leftclick Verify/Compile in the Sloeber toolbar.
7)     In the toolbar on top, leftclick the tool “Launch configuration” to choose “New Launch configuration” from the dropdown menu. Choose Launch Mode {“Debug”} [“Run”] and Launch Configuration Type {“C/C++ Application”} [C/C++ Unit] -> Next. Browse for the correct project. Change the {C/C++ Application to LocalDebug\<Projectname>.exe} [C/C++ Unit to UnitTest\<Projectname>.exe] where <ProjectName> is the name of the project. For the setting “Build Configuration” choose {“LocalDebug”} [“UnitTest”] from the dropdown list and left-click OK. In the Toolbar at the top leftclick the tool “launch mode” to select {“Debug”} [“Run”] from the dropdown menu. From the toolbar at the top leftclick “build”. From the toolbar at the top leftclick {“Launch in debug mode”} [“Launch in Run mode”].
(or: rightclick on the project and in the context menu left-click {“Debug as” -> “Debug configurations …-> C/C++ Application -> … (see above) -> Debug} [“Run as” ->Run configurations … -> C/C++ Unit -> … (see above) -> Run])
8)     {Change to the debug perspective. Leftclick to the left of a line in the code to set a breakpoint, e.g. at the first line of the code. Then Debug the code. In the debug toolbar at the top, leftclick on the tool “resume”, “step into” (go through the code instructions by instruction), “strep over” (to step over debugged procedures) etc. View variables and disassembly code to find bugs that produce unexpected behaviour. Leftclick “Terminate” and then “Stop” in the toolbars at the top. Then change back to the Arduino perspective,} rightclick on the project and in the context menu leftclick Build Configurations -> Set Active -> Release. Then in the Sloeber toolbar leftclick “Verify/compile”.

If the debugging / unit test run is aborted due to an error, try the following: a) In the Arduino perspective Leftclick Arduino -> Reattach libraries b) Rightclick on the project and from the context menu leftclick Index -> Re-resolve unresoved includes. c) Restart Bio7/Eclipse.

Now let’s consider the following code example:

The file blink.h:
/*
 * blink.h
 *
 *  Created on: Nov 27, 2015
 *      Author: jan
 */

#ifndef BLINK_H_
#define BLINK_H_
#include "Arduino.h"
#define INTERVAL 500 //The blinking interval

uint8_t calcLedState(uint32_t currentMillis, uint8_t ledState);


#endif /* BLINK_H_ */

//Added by Sloeber
#pragma once



The file blink.cpp
/*
 * blink.cpp
 *
 *  Created on: Nov 27, 2015
 *      Author: jan
 */

#include "blink.h"
#include "Arduino.h"

void setup() {
       pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
       static uint8_t ledState = LOW;
       ledState = calcLedState(millis(), ledState);
       digitalWrite(LED_BUILTIN, ledState);
}

uint8_t calcLedState(uint32_t currentMillis, uint8_t ledState) {
       static uint32_t previousMillis = 0;
       if (currentMillis - previousMillis >= INTERVAL) {
             previousMillis = currentMillis;

             if (ledState == LOW)
                    return HIGH;
             else
                    return LOW;
       }
       return ledState;
}

For the files above, the unit test file would be called e.g. blinkgtest.cpp . It could contain the following code:
#ifdef UNITTEST
#include "gtest.h" // Provides methods for unit tests including TEST()
                   // and EXPECT_EQ()
#include "blink.h"

TEST(blink, start) {
       EXPECT_EQ(HIGH, calcLedState(0, HIGH));
       EXPECT_EQ(LOW, calcLedState(0, LOW));
       EXPECT_EQ(HIGH, calcLedState(1, HIGH));
       EXPECT_EQ(LOW, calcLedState(1, LOW));
//     EXPECT_EQ(2, calcLedState(INTERVAL-2, HIGH));
//     EXPECT_EQ(2, calcLedState(INTERVAL-1, HIGH));
//     EXPECT_EQ(2, calcLedState(INTERVAL, HIGH));
//     EXPECT_EQ(2, calcLedState(INTERVAL+1, HIGH));
//     EXPECT_EQ(2, calcLedState(INTERVAL+2, HIGH));

}

TEST(blink, on) {
       uint32_t mill=0;
       for (mill = 0; mill < INTERVAL; mill++) {
             EXPECT_EQ(HIGH, calcLedState(mill, HIGH)) << mill;
       }
       EXPECT_EQ(LOW, calcLedState(INTERVAL, HIGH)) << INTERVAL;

}

TEST(blink, off) {
       uint32_t mill=0;
       for (mill = 0; mill < INTERVAL; mill++) {
             EXPECT_EQ(LOW, calcLedState(INTERVAL+mill, LOW)) << INTERVAL+mill;
       }
       EXPECT_EQ(HIGH, calcLedState(2*INTERVAL, LOW)) << INTERVAL;
}

#endif

In the code above, a local variable with scope limited to the loop() function was declared using the keyword static.
Citing the ISO document number N4296 (Working Draft, Standard for Programming Language C++) which later became ISO/IEC 14882:2014 (most relevant to users of AVR-GCC 7.3.0, but officially replaced by ISO/IEC 14882:2017): “1. All variables which do not have dynamic storage duration, do not have thread storage duration, and are not local have static storage duration. The storage for these entities shall last for the duration of the program (3.6.2, 3.6.3). […].
3. The keyword static can be used to declare a local variable with static storage duration. […] 4. The keyword static applied to a class data member in a class definition gives the data member static storage duration.” (ISO document number N4296 (draft of the C++ standard ISO/IEC 14882:2014), §3.7.1
Static storage duration.)
And:
“Destructors (12.4) for initialized objects (that is, objects whose lifetime (3.8) has begun) with static storage duration are called as a result of returning from main and as a result of calling std::exit (18.5).” (ISO document number N4296 (draft of the C++ standard ISO/IEC 14882:2014), §3.6.3
Termination.)
This means, the value assigned to variables declared with the keyword static is stored until either return 0; (preferred) or std::exit(); is called from the body of the main() function, which is called by the setup() function of the Arduino core and which closes the program. Even if the local scope is exited because the function ends and the same function with that local static variables is called again later, the static variables remain accessible under their original identifier from within that function.

More in depth debugging can be done with Atmel Studio 7 by Microchip Inc. which comes with a simulator for several Microcontrollers: https://www.youtube.com/watch?v=tScXBU5VFDo .

2.4       AVR Plugin for Eclipse, AVR toolchain and AVRDUDE

While the Eclipse plugin Sloeber installs the suboptimally designed Arduino IDE and the Python package PlatformIO needs outdated Python 2.7, the AVR Plugin for Bio7 / Eclipse in conjugation with the plain AVR toolchain comes without ovearhead. The downside is, that the setup is more difficult:

2.4.1     Setup of the AVR Plugin for Eclipse

1.      Install mingw-w64. Edit the system variables to add the directories …/mingw-w64/mingw-w64/bin and  …/mingw-w64/mingw-w64/x86_64-w64-mingw32/bin to the beginning of the system path. 
2.      Install the AVR toolchain. For Microsoft Windows 64bit, I recommend the updated AVR toolchain avr-gcc-7.3.0-x64-mingw which can be downloaded as a .7zip archive from https://forum.arduino.cc/index.php?topic=556557.0 and extracted using 7zip. Move the contained folder avr-gcc-7.3.0-x64-mingw to the system partition. Duplicate the file mingw32-make.exe and rename the copy make.exe. Edit the system variables to add the directories …/avr-gcc-7.3.0-x64-mingw/bin and …/ avr-gcc-7.3.0-x64-mingw/avr/bin to the system path after …/mingw-w64/mingw-w64/x86_64-w64-mingw32/bin.
3.      Install and run the freeware Zadig, use it to install libusb / WinUSB.
4.      If problems with avrdude.exe occur, search your computer for a libusb0_x86.dll in a folder with a name ending with x86. Copy that file to the Windows directory in your system partition. Rename that file to libusb0.dll
5.      Install AVRDude-mingw32 in the folder …/avr-gcc-7.3.0-x64-mingw/bin
6.      Download the AVR Plugin 2.4.2 or newer as a .zip archive, open Bio7 / Eclipse left-click Help -> Install new software” -> Add -> Archive and select the .zip Archive to install te Plugin. The AVR Plugin is not well configured: Always change the optimization level for the debug build configuration to “Slight Optimizations (-O1)”: For each project that was set up using the AVR plug-in and that has a Debug build configuration, right-click the project and in the context menu that appears, left-click Preferences -> AVR and activate “Enable individual settings for build configurations”
7.      Preferences -> AVR -> AVRDude and activate the option “Use custom configuration file for AVRDude” and set AVRDude config file: …\avr-gcc-7.3.0-x64-mingw\bin\avrdude.conf . Left-click “Apply an Close”
8.      Right-click the project and in the context menu that appears left-click Properties -> C/C++ Build -> Settings -> Tool Settings -> AVR C++ Compiler -> Optimization. Select Configuration: “Debug” and then select Optimization Level: “Slight Optimizations (-O1)”. Left-click “Apply and Finish”.
9.      In Bio7 / Eclipse, go to Preferences -> AVR -> Paths and for each entry, select “custom” from the drop down menu. Specify the path of the …/ avr-gcc-7.3.0-x64-mingw/bin/ directory for all entries, except for AVR header files where you have to specify the /avr-gcc-7.3.0-x64-mingw/bin/ directory in the directory of the AVR toolchain and except for the Atmel Part Description Files where no value has to be entered.
10.   Left-click Preferences -> AVR
11.   If you want to use Arduino libraries, you have several options:
a.      Download LoseAVR from https://forum.arduino.cc/index.php?topic=556557.0  and extract the .7zip archive using 7zip. Use the included precompiled static Arduino libraries in the ArduinoCore subfolder.
b.      Or precompile the Arduino libraries as static libraries yourself:
                                                     i.     retrieve the folder ArduinoCore-avr/tree/master/cores/arduino of the ArduinoCore-avr repository either by downloading and extracting the repository or by using git fork / clone the repository.
                                                   ii.     Instructions for Global AVR Configuration (section 2.3.5) and Software Organisation (section 3) using the AVR Plugin are available online. Follow until (including) section 3.1 and click on the compile errors that occur during the build process. Replace the indicated occurences of <Arduino.h> with “Arduino.h” and replace <IPadress.h> with “IPAddress.h”, then repeat until the build process is successful without errors.
                                                  iii.     Copy the files Arduino.h, HardwareSerial.h and binary.h to the folder ArduinoCore/ArduinoUnoRev3_Release
                                                  iv.     Right-click the Project “ArduinoCore” and in the context-menu that appears left-click “Refresh (F5)”. Now the folder ArduinoCore/ArduinoUnoRev3_Release should contain the fikes Arduino.h, HardwareSerial.h, binary.h, libArduinoCore.a and the subdirectory src/Arduino which contains all relevant object (.o) files
                                                   v.     While following the instructions of section 3.2, create a new C++ project for each extra library (e.g. ArduinoServo) and only import the desired library (excluding example folders and other utility folders that depend on that library) and do not import the Arduino core or Arduino variants:
·        Do not import the Arduino core files or variants files to the extra-library’s project. In the extra-libraries’ project properties, when adding paths and symbols, only add the project’s src folder and any subfolders from the working directory.
·        Then right-click the extra-library project and in the context menu that appears left-click Properties -> C/C++ General -> Add. Select “Add to all languages” and then left-click “File System” -> “browse”. Select the Arduino core directory on your computer (not in the Bio7 / Eclipse working space)
·        and repeat the previous step in order to add the Arduino/variants/standard folder to the project’s path.
·        build the project.
·        Copy the file Servo.h to the folder ArduinoServo/ArduinoUnoRev3_Release and add a new folder ArduinoServo/ArduinoUnoRev3_Release/src/arduino to which the contents of the Arduino core library have to be copied.
·        In the Bio7 / Eclipse program directory there should be now some lib[extralibraryname].a archive file in the extra-library’s project folder (e.g. …/workingspace/ArduinoServo/ArduinoUnoRev3_Release/libArduinoServo.a) next to the extra-librarie’s header (.h) file as well as folders containing the relevant object (.o) files and the sorce-code of the arduino core library.
c.      Copy the respective modules into your project and compile everything together
d.      Use a link to the local Arduino core directory to the project:
                                                     i.     Right-click on the project and in the context menu that appears left-click Properties -> C/C++ General -> Paths and Symbols -> Source Location -> Link folder -> Advanced. Select “Link to folder in the File System”, set Folder name: Arduino. Left-click “Browse” and navigate to the directory of the Arduino core library (folder “arduino” containing the Arduino.h and other files). Left-click “Ok”
                                                   ii.     Right-click on the project and in the context menu that appears left-click Properties -> C/C++ General -> Paths and Symbols -> Includes -> Add -> Workspace. Select the folder <projectname>/arduino of the current project. Select “Add to all configurations” and “Add to all languages”. Left-click “OK”
                                                  iii.     Left-click Add -> Filesystem and navigate to the directory ...hardware/arduino/variants/standard . Select “Add to all configurations” and “Add to all languages” and left-click “OK”. Left-click “Apply and close”
e.      Alternatively, do the following:
                                                     i.     Downlod the base makefile from https://gist.github.com/entrity/5424505 and specify the correct paths for each of the …DIR variables. E.g. ARDDIR = <my Arduino folder> is the folder with the subfolder /hardware/arduino/cores/arduino
                                                   ii.     In Bio7 / Eclipse, create a new C++ project with a project-specific makefile:
# This is the name of the file that shall be created. (It is also the name of my primary source file, without the file extension.)
TARGET = temp

# create a variable that only pertains to this project
MY_OWN_LIBRARY_DIR = /usr/home/MJ/Arduino/libraries/mj_midi

# "EXTRAINCDIRS" is a variable used by the base makefile. The base makefile creates a -I compiler flag for every item in the "EXTRAINCDIRS" list.
EXTRAINCDIRS = $(MY_OWN_LIBRARY_DIR)

# specify *.c source files pertaining to my project
SRC =

# specify *.cpp source files pertaining to my project
PSRC = temp.cpp $(MY_OWN_LIBRARY_DIR)/midi-listener.cpp $(MY_OWN_LIBRARY_DIR)/midi-song.cpp

# specify additional (non-core) Arduino libraries to include
ARDLIBS = SoftwareSerial

# include my base makefile
include /d/dev/avr/Makefile.base

2.4.2        Use oft the AVR Plugin with libraries

The precompiled libraries generated using option a) in section 2.4.1 can be used in the following way:
1.      Create a new C++ project and select AVR appication.
2.      Add a source folder src
3.      Add a source file src/main.cpp
4.      Add code to the src/main.cpp. You can add the following minimum example to src/main.cpp for testing the AVR plugin (uncomment for serial communication):

/**
 * @title: Eclipse AVR Plugin test without serial communication
 * @author: DerAndere
 * @year: 2018
 * // Copyright (c) 2018 DerAndere
 * // SPDX-License-Identifier: MIT
 * @license: MIT
 * @about: using https://github.com/zkemble/millis
 */

#include <avr/io.h>
#include <util/delay.h>
//#include "Arduino.h" // Arduino core library. License: LGPL 2.1 or later
#include "Servo.h" // Arduino Servo library. License: LGPL 2.1 or later
#include "millis.h" // https://github.com/zkemble/millis . License: MIT
#include <avr/interrupt.h>

#ifndef F_CPU
#define F_CPU 16000000UL
#endif // F_CPU



static const int delayms = 500;
static const int servo1Pin = 12; // PB4 is servo1Pin
Servo servo1;

int main(void){
       millis_init();     // setup millis() timers. Always the first thing in main().

       PORTB &= ~_BV(PB5); // set pin PB5 (digital pin 13 with
                                       // built-in LED) = 0 (low) by clearing
                                       // bit PB5 of register PORTB (for
                                       // register PORTB clear bit PB5 = 0:
                                       // Negated (bitwise not) setting of bit
                                       // PB5=1 (_BV(PB5) means bitwise right
                                       // shifting (1<<PB5)) bitwise
                                       // and-equals register PORTB)
       DDRB |= _BV(PB5);  // set pin PB5 (digital pin 13 with
                                       // built in LED) as digital output by
                                       // setting bit PB5 of the data
                                       // direction register for port B (for
                                       // register DDRB5 set bit PB5)

//       Serial.begin(9600); // baudrate = 9600
       servo1.attach(servo1Pin);        // set digital pin 12
                                       // (ATmega328P pin PB4) as servo1Pin


       sei();                    // enable interrupts

       millis_t lastChangedLEDms = 0; // when timing starts, counter starts at 0


       for (;;) {
             millis_t currentms = millis();

             // Has it been 500ms since last change for LED1?
             if(currentms - lastChangedLEDms >= 500)
             PORTB ^= _BV(PB5); // toggle built-in LED at pin 13 on/off by
                                              // toggling pin PB5 (digital pin
                                              // 13 with built-in LED) between 0
                                              // (low) and 1 (high) by toggling
                                              // (bitwise XOR-equal) bit PB5 of
                                              // the register PORTB between 0
                                              // (low) and 1 (high)
             servo1.write(200);
//             Serial.print("Hello");

             // Store time
             lastChangedLEDms = currentms;
             _delay_ms(delayms);

       }
       return 0;
}


With serial communication:
/**
 * @title: Eclipse AVR Plugin test with serial communication
 * @author: DerAndere
 * @year: 2018
 * // Copyright (c) 2018 DerAndere
 * // SPDX-License-Identifier: MIT
 * @license: MIT
 */

#include <avr/io.h>
#include <util/delay.h>
#include "Arduino.h" // Arduino core library. License: LGPL 2.1 or later
#include "Servo.h" // Arduino Servo library. License: LGPL 2.1 or later
//#include "millis.h" // https://github.com/zkemble/millis . License: MIT
#include <avr/interrupt.h>

#ifndef F_CPU
#define F_CPU 16000000UL
#endif // F_CPU



static const int delayms = 500;
static const int servo1Pin = 12; // PB4 is servo1Pin
Servo servo1;

int main(void){
       init();      // initialize timers and enable interrupts. See
                    // https://github.com/arduino/ArduinoCore-
                    // avr/blob/master/cores/arduino/wiring.c

       PORTB &= ~_BV(PB5); // set pin PB5 (digital pin 13 with
                                       // built-in LED) = 0 (low) by clearing
                                       // bit PB5 of register PORTB (for
                                        // register PORTB clear bit PB5 = 0:
                                       // Negated (bitwise not) setting of bit
                                       // PB5=1 (_BV(PB5) means bitwise right
                                       // shifting (1<<PB5)) bitwise
                                       // and-equals register PORTB)
       DDRB |= _BV(PB5);  // set pin PB5 (digital pin 13 with
                                       // built in LED) as digital output by
                                       // setting bit PB5 of the data
                                       // direction register for port B (for
                                       // register DDRB5 set bit PB5)

uint32_t lastChangedLEDms = 0; // when timing starts, counter starts at 0

       Serial.begin(9600); // baudrate = 9600
       servo1.attach(servo1Pin); // set digital pin 12
                                 // (ATmega328P pin PB4) as servo1Pin

       sei();                    // enable interrupts

      
       for (;;) {
             uint32_t currentms = millis();

             // Has it been 500ms since last change for LED1?
             if(currentms - lastChangedLEDms >= 500)
             PORTB ^= _BV(PB5); // toggle built-in LED at pin 13 on/off by
                                 // toggling pin PB5 (digital pin
                                 // 13 with built-in LED) between 0
                                 // (low) and 1 (high) by toggling                                                   // (bitwise XOR-equal) bit PB5 of
                                 // the register PORTB between 0
                                 // (low) and 1 (high)
             servo1.write(200);
             Serial.print("Hello");

             // Store time
             lastChangedLEDms = currentms;
             _delay_ms(delayms);

       }
       return 0;
}



5.      For each uncompiled library (e.g. that was precompiled by you according to section 2.4.1 above and that is #include d in your project, do the following: Left-cick C/C++ Build -> Settings -> AVR C++ Linker. To the list Libraries (-l), add an entry, e.g. “ArduinoCore” (including “”) and to the list Libraries Path (-L), add an entry and navigate to the path to the folder in which the file libArduinoCore.a was saved (see final step of option a) in section 2.4.1).
If that library relies on the Arduino core, right-click the project and in the context menu left-click Properties -> C/C++ General -> Paths and Symbols -> Add -> File System. Browse for the Arduino cores/arduino. Select “Add to all languages”. Left-click Apply. Repeat this for the path variants/Standard. Left-click “Apply and Close”.
6.      Left-click on the project and in the AVR Plugin toolbar left-click “build”.
7.      Then in the AVR Plugin toolbar left-click “Upload current project to Atmel target MCU (Ctrl + Alt + U)”

3       My first project: Knitting images -  computerizing knitting machines using the AYAB hack

[Werbung ohne Auftrag / unpaid advertisement]
After a long time, a new vendor at the marketplace Etsy, called redpinkgreen, ships the All Yarns Are Beautiful (AYAB) shield kit version 1.3 for 37,40 €. It is a DIY self-soldering kit for an extension shield that fits on an Arduino UNO compatible development board and provides an interface to control Brother / Jones & Brother / KnitKing / CompuKnit / Defendi / Topical / Electroknit knitting machines from a personal computer via USB. The shield of the All Yarns Are Beautiful (AYAB) Project was developed by Christian Obersteiner (chris007), Andreas Müller (Andz), Sebastian Oliva, and Christian Gerbrandt (derchris) from the Chaos Computer Club München. They also developed the AYAB software for Windows, Linux and MacOS. which has to be downloaded from http://ayab-knitting.com/ayab-software/ and installed as described at documentation -> quick start on the AYAB project homepage. This software provides a graphical user interface for uploading of image files from the computer to the Arduino-compatible development board / microcontroller device. The AYAB software as well as schematics and EAGLE files for the AYAB shield are open source. An instruction how to assemble the shield is available from the AYAB project homepage. A video tutorial for connecting the AYAB shield with the knitting machine can be found, too. I used it to hack a Brother Electroknit KH 910 (equal to KnitKing CompuKnit II). I highly recommend to also change the old transistors of the power supply of the knitting machine. I am not the first one who experienced the old transistors being destroyed after powering on the knitting machine. In order to prevent further damage of the knitting machine, you can purchase replacement transistors from redpinkgreen at Etsy or from a vendor called kadash24 at ebay. Replacing the transistors is easy: Unplug the knitting machine, remove the batteries, unfasten the 5 rightmost screws on the top of the Brother KH 910 (2 at the rear, 3 at the needle bed) and remove the 3 small round plastic pins that hold the right part of the cover in place. Remove the printed circuit board of the power supply, unsolder the two old transistors and connect the new ones to the respective holes of the printed circuit board using though-hole-soldering techniques.

3.1       Computer-controlled knitting of Rib Jacquard using the AYAB hack

I contributed some additions to the AYAB manual. The current status can be obtained from the branch "master" of the AYAB-manual repository at github.com.

4        My second project: DIY MIDI-controller by DerAndere

[Werbung ohne Auftrag / unpaid advertisement]
My second project related to pragramming and electronics is a MIDI-controller based on an Arduino UNO-compatible development board. I took inspiration from Goetz Mueller-Duerholt’s MIDI-Controller (https://goo.gl/I1ipZj , http://www.goetzmd.de). Similar projects are http://www.instructables.com/id/Convert-Rockband-Controller-to-MIDI-Drums/ and https://github.com/evankale/ArduinoMidiDrums.

4.1       Building the DIY MIDI-controller by DerAndere: The circuit

The following schematic circuit diagram was created using the free version of EAGLE by Autodesk Inc. with the Adafruit EAGLE library.



Fig. 1: Schematic circuit diagram for the MIDI controller by DerAndere. Created using the free version of EAGLE by Autodesk Inc with the Adafruit EAGLE library. Arduino UNO R3 can be replaced with any compatible development board. The potentiometers R1-R6 have 10 kOhm nominal resistance and linear taper. I chose vertical rotary potentiometers with 16 mm shaft and DIP terminals for through-hole soldering or use with solder-less breadboards. Copyright © DerAndere 2018. Image is licensed under the terms of the Creative Commons Attribution 4.0 International license (CC BY 4.0).

The potentiometers R1-R6 have 10 kOhm resistance and linear taper. I chose vertical rotary potentiometers with 16 mm shaft and DIP terminals for through-hole soldering or use with solder-less breadboards such as Alpha RV0600DF-43 (Mono) or Alpha RV16AD1F-41 by Taiwan Alpha Electronic Inc., Ltd. They are distributed by www.musikding.de

4.2       Programming the DIY-MIDI-controller by DerAndere

In Bio7 / Eclipse with the Sloeber plug-in, left-click File -> New. Type the name of the project, e.g. ArduinoMIDIcontroller. Left-click “finish”.
Below is the complete Program code for the files ArduinoMIDIcontroller/ArduinoMIDIcontroller.h and ArduinoMIDIcontroller/ArduinoMIDIcontroller.cpp (change .cpp to .ino file extension (for compatibility with original Arduino IDE):
/**
 * @title: ArduinoMIDIcontroller.h
 * @version: 4.0
 * @reference: This code is derived work from code for a MIDI controller from
 * https://goetzmd.de/tontechnik/ab-damit-auf-die-lochraster-platine#more-1021
 * (Copyright (c) Götz Müller-Dürholt 2015; adapted with significant changes by
 * DerAndere).
 * @author: DerAndere
 * @created: 2018
 * Copyright (c) DerAndere 2018
 * This code is protected by copyright. You are not allowed to
 * redistribute this code or derived work without explicit approval by
 * Götz Müller-Dürholt and the author of this derived work (DerAndere).
 * Downloading and copying the code or parts of it is only allowed for private,
 * non-commercial use.
 * @info: https://it-by-derandere.blogspot.com/p/blog-page_46.html
 * @language: C++ for AVR-GCC
 * @description: Sketch for an Arduino Uno Rev.3 or a compatible development
 * board that is used inside the DIY-MIDI-controller by DerAndere. Based on
 * ideas from https://goo.gl/I1ipZj and
 * https://goetzmd.de/tontechnik/ab-damit-auf-die-lochraster-platine#more-1021
 * (Copyright (c) Götz Müller-Dürholt 2015)
 */

/** include Arduino.h standard library header that provides functions to use
 * with Arduino/Genuino-compatible development boards or Atmel microprocessors
 */
#include "MIDIcontrollerCB.h"
#include "Arduino.h"
/**
 * declare and define / initialize byte for ControlChange command (176 for
 * sending on MIDI channel 1)
 */
uint8_t controlChange = 176;

/**
 * declare and define / initialize array containing the selected MIDI controller
 * numbers
 */
uint8_t midiCCselect[] = { 22, 23, 24, 25, 26, 27 };

/**
 * declare and define / initialize array containing Pin numbers of Pins
 * to which potis are connected
 */
uint8_t analogPin[] = { 0, 1, 2, 3, 4, 5 };

// declare and define byte for the count of MIDI controller messages to be sent
const int8_t ccCount = sizeof(midiCCselect) / sizeof(int8_t);

// declare variables and arrays with size equal to count of potis
int analogVal[ccCount] = { 0 };
int potiVal[ccCount] = { 0 };
int8_t controllerVal[ccCount] = { 0 };
int8_t controllerValPrevious[ccCount] = { 0 };
uint32_t midiSendTime = (uint32_t) 0;
uint32_t midiSendTimePrevious = (uint32_t) 0;

/**
 * newmap Funktion by Bill Perry aka bperrybap.
 * @reference:
 * http://forum.arduino.cc/index.php?topic=417690.msg2877460#msg2877460
 * Copyright © Bill Perry 2015.
 * @license: Creative Commons Attribution ShareAlike 3.0 (CC-BY-SA-3.0).
 * @param: long x = raw input value
 * @param: long in_min = minimum of possible raw input range
 * @param: long in_max = maximum of possible raw input range
 * @param: long out_min = minimum of possible scaled output range
 * @param: long out_min = maximum of possible scaled output range
 * @return: long (out_min – out_max)
 * @fn: maps in equal intervals (using linear interpolation) as opposed to
 * flawed map() function from the Arduino.h library.
 */
long newmap(const long x, const long in_min, const long& in_max,
             const long out_min, const long out_max)
             {
       if (x == in_max)
             return out_max;
       else if (out_min < out_max)
             return (x - in_min) * (out_max - out_min + 1) / (in_max - in_min)
                          + out_min;
       else
             return (x - in_min) * (out_max - out_min - 1) / (in_max - in_min)
                          + out_min;
}

// Function for sending a MIDI command:
void sendMIDI(uint8_t statusByte, uint8_t dataByte1, uint8_t dataByte2) {
       Serial.write(statusByte);
       Serial.write(dataByte1);
       Serial.write(dataByte2);
}

/**
 * @fn: Smoothes values depending on the smoothingFactor.
 * @param: valLast = last value from reading an analog pin.
 * @param: analogPinNum = pin to be read
 * @param: smoothingFactor between 0 (none, fast) and 99 (maximum, slow)
 * @returns: int
 */
int smoothRead(const int valLast, const int8_t analogPinNum,
             const uint8_t& smoothingFactor) {
       return (long) smoothingFactor * (long) valLast / 100L
                    + (100L - (long) smoothingFactor / 100L) * analogRead(analogPinNum);
}

void setup() {
       Serial.begin(9600);
}

/**
 * loop goes through indices of the potiVal, successively reads smoothed
 * analog pin values, converts into MIDI-controller values and upon change
 * sends MIDI ControlChange messages
 */
void loop() {
       for (int8_t i = 0; i < ccCount; ++i) {
             midiSendTime = micros();
             if ((midiSendTime - midiSendTimePrevious) >= 100) {
                    potiVal[i] = smoothRead(potiVal[i], analogPin[i], 20);
                    controllerVal[i] = newmap(potiVal[i], 0, 1023, 0, 127);
                    if (controllerVal[i] != controllerValPrevious[i]) {
                          sendMIDI(controlChange, midiCCselect[i], controllerVal[i]);
                          controllerValPrevious[i] = controllerVal[i];
                    }
                    midiSendTimePrevious = midiSendTime;
             }
       }
}

The above C++ code follows the paradigm of procedural programming and could therefore easily be rewritten in AVR-GCC compatible C according to the outdated standard ISO/IEC 9899:1999. For this so called C99 dialect, variables cannot be declared inside the control part of functions. Declaration before the function is required. Variables can only be declared at the beginning of blocks (inside brackets) or in the control part of for loops. For complex programs, it makes sense to follow the principle of modular programming. The above code can also be rewritten following the paradigm of object-oriented programming. The result can be found in section 5.3 below. Be aware of the fact, that classes and implicit passing variables by reference is not possible in C.

5       Microcontrollers and object oriented programming

5.1       Modular programming: Header file, source file and #include “Headerfile.h”

As already seen in the code above (section 4.2), it makes sense to organize program code in a modular manner. This allows for parts of the code to be reused in different applications. Variables and functions that are used several times should be declared in a header file and defined in a source file. The definition includes the code for the implementation.

The header file should be saved under the name CustomLibrary.h (.h is the file extension for header files) and contain the following code including include guides and function declaration for function prototypes:
#ifndef CustomLibrary_H
#define CustomLibrary_H

type func(type paramA, type paramB);

#endif


The source file for the modules should be saved under the file name LibraryModuleAImplementationSource.cpp (.cpp is the file extension for source code files written in C++) and contain the following code:
#include “CustomLibrary.h”

type func(type paramA, type paramB)
{
function body (dependent on paramA, paramB)
}


Now all the functions in the CustomLibrary (declared in CustomLibrary.h) can be easily used ("called") from within any source file that contains the command #include “CustomLibrary.h” at the top. In our example, the function func can be called from within the main program file that includes that header file by adding the following code:
#include “CustomLibrary.h”

type varA = 0;
type varB = 3;
type varC = 4;

void(){
varA = func(varB, varC);
}

In the above program, varA is initially declared as being a variable of the given type and immediately defined as being zero. Then varA becomes overwritten with a value that is the result of func(varB, varC). The latter means that the first argument of the function func, that is paramA, is substituted by varB and that the argument paramB is substituted by varC. From the definition of varB = 3 and varC = 4, varA is calculated according to the method defined in the function body of func() in the source file containing the implementation.

For modular programming using Sloeber, right click on the project in the and click New -> source folder. Give it some name (e.g. src). Right click on the source folder and click New -> folder. Name the folder like the module (e.g. ModuleA). Right click on the folder ModuleA and click New -> *.h file. Give it the same name as the folder with a .h file extension (ModuleA.h). Then click New -> *.cpp file. Give it the same name as the folder with a .cpp file extension (ModuleA.cpp). Add #include <Arduino.h> to all files if not done. Add #include “ModuleA.h” to the ModuleA.cpp file. Add #include “src/ModuleA/ModuleA.h” to the main program *.h and *.cpp file.

5.2       Use and creation of custom libraries

Because of memory restrictions on Arduino/Genuino-compatible development boards, neither the C/C++ standard library nor the standard template library (STL) is included in the Arduino.h standard library. However, the ArduinoSTL library implements the most important features like the advanced containers for this hardware. In order to use libraries, you have to create a folder where such private libraries are to be stored (in a directory with reading- and writing permission). Additionally, this folder has to be specified in Sloeber by clicking preferences -> Arduino -> Add.
Download the latest ArduinoSTL library (a .zip archive can be downloaded from https://www.arduinolibraries.info/libraries/arduino-stl ) and extract it to your private library folder. Rename the extracted folder to ArduinoSTL. Then, the library can be imported into an existing Arduino Sketch in Sloeber by right-clicking on the project folder in the project manager and clicking Import -> Arduino -> Import Arduino libraries into the current project. In each file that makes use of this library, add the following code:
#include "ArduinoSTL.h"

Refer to the documentation for the chosen library for use and syntax. For examples, use vectors with the following command:
std::vector<T> (n) vectornameA

where T is the type of the vector elements and n is a size_t (unsigned integer) defining the size of the vector (the total number of elements in the vector).
std::vector<T> vectornameB {4,5,6,7};

vectornameB.size() gives the size of vector vectornameB as a size_t (unsigned integer). This can be saved in a variable:
size_t varA = vectornameB.size();

In order to create your own library to make its classes and functions publicly available, refer to the guide at

5.3       Object oriented programming in modern C++: Code for the MIDI-controller by DerAndere using classes and class inheritance

As a showcase of object oriented programming for microcontrollers usingmodern C++, I chose the code for the MIDI-controller by DerAndere (see section 4.3.2). The sketch can be rewritten in modern C++ as follows. My C++ libraries map2 (https://gitlab.com/RobotsByDerAndere/LibrariesByDerAndereForDevelopmentboards/NuMap) and ArdUnoRev3API1 (https://gitlab.com/RobotsByDerAndere/LibrariesByDerAndereForDevelopmentboards/ArduUnoRev3API1) have to be installed. Create an Arduino project with a default .cpp file in Bio7/Eclipse CDT with the plug-in Sloeber. Also, download the files of the repository https://gitlab.com/RobotsByDerAndere/USBInterfacesByDerAndere/MIDIControllerByDerAndere and in Bio7 / Eclipse create a new Project of type Arduino Sketch and import the downloaded files into the project. Alternatively, clone the repository using Bio7 / Eclipse with the plug-in Egit, then open the Git perspective and right-click on the repository and in the context menu left-click Import project. Select “import submodules” and left-click Finish. 
Open the Arduino perspective and verify/compile the code using the verify button in the Sloeber toolbar. Then click on the upload button in the Sloeber toolbar and choose the option to build before uploading. The code should compile without error messages.

6       More

Auto:

Range-based loops:


Copyright © 2018-2019 DerAndere

Popular posts from this blog

Scalable knitting patterns with open source software: Textile design with Inkscape and GIMP.

AYAB shield - self soldered circuit board for a computer-controlled knitting machine

GGCGen - Graphical G-code Generator for robot control