Tuesday, January 19, 2016

Beginning to Program Arduino in C

To write to a pin, we have to set that pin as an output pin. Then only we can write digital 1 or 0 to that pin. Suppose we need to set the value of Pin 5 in Port B to digital 1. This is how we do it.

We need to import this header to have all the necessary macros
#include <avr/io.h>

Now we have to set the correct pin as an output pin. Whether a pin of a port is set to input or output is decided by the values in "Data Direction Register" of the particular port. The data direction register for the PortB is DDRB. So, to set the pin 5 of PortB as output, we have to set the corresponding pin in DDRB register to logic high. We do that in the following way.

DDRB |= _BV(DDB5);

DDB5 is a macro which gives a byte where the bit that corresponds to PortB Pin5 is set to 1 while the other bits are 0. So, by making the above operation, we are setting the corresponding bit in DDRB register to 1 while making all the other bits to 0. It notify the system that PortB Pin5 is now an output pin.

Tt's time to set the desired output value to the PortB Pin5. If we want to set it to
1, here's how we do it.

PORTB |= _BV(PORTB5);

PORTB5 macro gives us a byte where the bit corresponds to Pin5 is set to 1 while all the other bits are 0. Therefore, the above operation sets the correct bit of the PORTB register to 1 making it's output value to 1.

Similarly, we can set the output value of the PortB Pin5 to 0 by doing the following operation.

PORTB &= ~_BV(PORTB5);

Using the above techniques, we write a LED blink application for Arduino as follows.

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20``` ```#include #include #define BLINK_DELAY_MS 1000 int main (void) { /* set pin 5 of PORTB for output*/ DDRB |= _BV(DDB5); while(1) { /* set pin 5 high to turn led on */ PORTB |= _BV(PORTB5); _delay_ms(BLINK_DELAY_MS); /* set pin 5 low to turn led off */ PORTB &= ~_BV(PORTB5); _delay_ms(BLINK_DELAY_MS); } } ```

We can have a Makefile with the following content to compile and write the above C program into an Arduino Uno board.

 ```1 2 3 4 5``` ```all: avr-gcc -Os -DF_CPU=16000000UL -mmcu=atmega328p -c -o blink.o blink.c avr-gcc -mmcu=atmega328p blink.o -o blink avr-objcopy -O ihex -R .eeprom blink blink.hex avrdude -F -V -c arduino -p ATMEGA328P -P /dev/ttyACM0 -b 115200 -U flash:w:blink.hex ```

References:

[1] https://balau82.wordpress.com/2011/03/29/programming-arduino-uno-in-pure-c/

[2] https://iamsuhasm.wordpress.com/tutsproj/avr-gcc-tutorial/

Saturday, January 9, 2016

Here's a very brief note about an analog accelerometer which I tried recently. It is ADXL335 which is a 3-axis accelerometer and can be very easily used with any microcontroller having three analog interfaces. I used an Arduino Uno board for this purpose. For this work, what I exactly used is a module which contains a ADXL335 chip with correct support circuit components. This module just have five output pins, which are VCC, GND, X, Y and Z.

Here's how we connect ADXL335 module with an Arduino Uno board. Connect the GND pin of ADXL335 with GND of Arduino, VCC pin of ADXL335 with 3.3v pin of Arduino and finally connect the X, Y and Z pins of the ADXL335 with the A0, A1 and A2 pins of the Arduino board. Then we are good to go. We can connect the Arduino board as usual and read the analog pins 0, 1 and 2 using the analogRead() function to get the raw output data of X, Y and Z pins from the accelerometer.

Since the raw data readings from the analog pins provide values within a particular range according to the orientation of the accelerometer, we can get an idea of how it is oriented if we know the maximum and minimum values it can show. Additionally, there are some ways to calculate the exact angle as a degree value using these raw data. Following is such a code I used to see the orientation of the accelerometer in degrees. When you run it, serial monitor will show the orientation as degree values for the three axis.

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52``` ```//Analog read pins const int xPin = 0; const int yPin = 1; const int zPin = 2; //The minimum and maximum values that came from //the accelerometer while standing still //You very well may need to change these int minVal = 265; int maxVal = 402; //to hold the caculated values double x; double y; double z; void setup(){ Serial.begin(9600); } void loop(){ //read the analog values from the accelerometer int xRead = analogRead(xPin); int yRead = analogRead(yPin); int zRead = analogRead(zPin); //convert read values to degrees -90 to 90 - Needed for atan2 int xAng = map(xRead, minVal, maxVal, -90, 90); int yAng = map(yRead, minVal, maxVal, -90, 90); int zAng = map(zRead, minVal, maxVal, -90, 90); //Caculate 360deg values like so: atan2(-yAng, -zAng) //atan2 outputs the value of -π to π (radians) //We are then converting the radians to degrees x = RAD_TO_DEG * (atan2(-yAng, -zAng) + PI); y = RAD_TO_DEG * (atan2(-xAng, -zAng) + PI); z = RAD_TO_DEG * (atan2(-yAng, -xAng) + PI); //Output the caculations Serial.print("x: "); Serial.print(x); Serial.print(" | y: "); Serial.print(y); Serial.print(" | z: "); Serial.println(z); delay(100);//just here to slow down the serial output - Easier to read } ```

Further details of the ADXL335 accelerometer and the description of the above code can be found in the original place from where I learned it. Those places are given as references in the following section.

References:

[1] The original source of the above code I have used.