Skip to content

9. Embedded programming

eagle files

This week’s assignment is to program the board we designed 2 weeks ago using low level programming. To do that we have to read the datasheet for the microcontroller we used which is Attiny44.

When I milled and soldered my board two weeks ago, I wanted to make sure everything works fine and to do that I used the Arduino IDE to program it.

Programming Using Arduino ISP I first programmed the Arduino as ArduinoISP using the examples available in the Arduino IDE.

Just like I did two weeks ago, I connected my Echo Hello board to the arduino according to the below schematics.

Then I chose the board to be Attiny, the processor to be 44 and the crystal to 20MHz. The programmer I chose was ArduinoISP and then I burnt the bootloader.

Then I modified the blink example to blink the LED in my board which is connected to pin w. Then I uploaded the code to my echo hello board by choosing upload using programmer. This verifies that my board works.

Programming Using Fab ISP After checking that I have soldered everything correctly and that my board works phew, it’s time to get to the fun not so easy stuff. I decided to take advantge of the FabISP I built weeks ago and use it to give life to my Echo Hello board. To do that, I connected the following pins to each other.

Then I got myself familiar with the datasheet. The datasheet is 238 pages long so you really need to know how to extract the information you need from here cause who has time to read 238 pages, right?! So before I started reading it, I need to know what I’m looking for first. Our instructor told us that in order to program your board using low-level programming, you need 3 things which are:

AVR libraries - which I can download like I did before when I programmed the ISP. A makefile and the make tool. A C code The process for programming the Echo Hello is seen below.

Make is a utility that is designed to start execution of a makefile. A makefile is a bunch of rules that explains how your board reacts based on certain prerequisites which affects the outcome of the program, called “target”. In the end you’ll have an executable file that dictates how your board operates. While in the directory containing this makefile, you will type make and the commands in the makefile will be executed.

To create my makefile, I used Neil’s example and then edited it to have the following:

            PROJECT=nad_echo
            SOURCES=$(PROJECT).c
            MMCU=attiny44
            F_CPU = 20000000
            CFLAGS=-mmcu=$(MMCU) -Wall -Os -DF_CPU=$(F_CPU)     #create set of parameters for the compiler (clock, MCU)

            $(PROJECT).hex: $(PROJECT).out
            avr-objcopy -O ihex $(PROJECT).out $(PROJECT).c.hex;\      #copy and translate object files
            avr-size --mcu=$(MMCU) --format=avr $(PROJECT).out         #size utility lists the section sizes               

            $(PROJECT).out: $(SOURCES)
            avr-gcc $(CFLAGS) -I./ -o $(PROJECT).out $(SOURCES)        #to compile the file

            program-fabISP: $(PROJECT).hex
            avrdude -p t44 -P usb -c usbtiny -U flash:w:$(PROJECT).c.hex       #to upload the file

            program-fabISP-fuses: $(PROJECT).hex
            avrdude -p t44 -P usb -c usbtiny -U lfuse:w:0x1F:m         #to upload the settings of the fuses     

To understand how to set the fuses, I went through this tutorial. Fuses are 3 bytes of permenant storage that can be reprogrammed to dictate the behavior of your MCU. There’s a fuse calculator that we can use that will automatically give you the line of code for the fuses. However it was a bit confusing cause going back to the datasheet, 0 means programmed and 1 means unprogrammed and in the calculator if you choose to program (tick the box) you actually unprogram (set it to zero). So I just did it manually for the lower byte with the help of the datasheet.

Now that the make file is ready, I had to get myself familiar with C programming, luckily I know a bit of C so it wasn’t that hard. It is important to know that the Attiny44 has 2 ports, each port has 8 pins which means that we have 16 GPIO (General Purpose Input Output) pins.

To configure a pin as input or output you have to configure it in the DDRX register, where x is the port. For example, if you want to configure pin 2,5 and 7 in PORTA as input, and the rest as output you have to give it the following: DDRA= 0b 01011011 where 0 means the pin is configured as input and 1 means the pin is configured as output. Let’s say you configured pin 4 as output, how do you set or unset its value?! You do that using PORTX register by giving it a 1 to set high and a 0 to set low. The last thing is reading and input and that is done using PX#, where X is the port and # is the number of the pin.

Now that I’ve got the basics covered, it’s time to write my code. I used Arduino IDE to do it. In my echo hello board I have an LED connected to pin 2 and a button to pin 7. So I have to set the button as input and the LED as output. I wrote my program to have the LED light when the button is pressed.

Next, I switched to Ubunto, I have installed on a flash drive and I just boot my computer from there.

To program my board, I have to install the necessary packages for AVR Programming. AVR is the family of the chip we used in our board Attiny44. To install the packages, I followed the below steps.

The below commands are not for the ISP but for my computer to install the necessary drivers & packages:.

sudo apt-get install flex byacc bison gcc libusb-dev avrdude sudo apt-get install gcc-avr sudo apt-get install avr-libc sudo apt-get install libc6-dev I created a folder with my makefile and my c code in it. It is important to not put an extension on the makefile and to put the extension of the c code to .c .

Next you navigate to that folder and type make in the terminal, this will create a .hex & .out file. This means it successfully compiled. Then you type make (name of program), the name of program should be the same as in your makefile. If you did everything right, your board should come to life!

This week I worked on defining

The code below changes LEDs lighting according to presses count on the push button.

code with Arduino C

#include <avr/io.h>
#include <util/delay.h>

void switchLED(unsigned char);

int main(void) {
    //Clock divider set to one using lfuse bit CKDIV8 = 1
    unsigned char counter = 1; //Counts push button presses
    double Tdebounce = 150; //Delay to remove debouncing

    DDRA |= (1 << DDA2); //Output: Red LED
    DDRA |= (1 << DDA3); //Output: Blue LED
    DDRB &= ~(1 << DDB2); //Input: Push button. Default = 1 (pulled up through external 10k resistor)

    while(1){
        if(!(PINB & (1 << PINB2))){ //If push button pressed
            _delay_ms(Tdebounce);
            while(!(PINB & (1 << PINB2))){} //Looping as long as push button is pressed
            counter++;
            if(counter == 5){
                counter = 1;
            }
        }
        switchLED(counter);
    }
}

void switchLED(unsigned char c){
    switch(c){
        case 1: //Both LEDs ON
        PORTA |= (1 << PORTA2);
        PORTA |= (1 << PORTA3);
        break;
        case 2: //Red LED ON
        PORTA |= (1 << PORTA2);
        PORTA &= ~(1 << PORTA3);
        break;
        case 3: //Blue LED ON
        PORTA &= ~(1 << PORTA2);
        PORTA |= (1 << PORTA3);
        break;
        case 4: //Both LED OFF
        PORTA &= ~(1 << PORTA2);
        PORTA &= ~(1 << PORTA3);
        break;
    }
}

The code below changes LEDs lighting according to presses count on the push button. Here I used macros to changes the output pins value and to test the input pin value.

#include <avr/io.h>
#include <util/delay.h>

#define bitHigh(reg, bit) (reg) |=  (1 << (bit))
#define bitLow(reg, bit) (reg) &= ~(1 << (bit))
#define bitState(reg, bit) (reg) & (1 << (bit))

void switchLED(unsigned char);

int main(void) {
    //Clock divider set to one using lfuse bit CKDIV8 = 1
    unsigned char counter = 1; //counts push button presses
    double Tdebounce = 150; //Delay to eliminate debouncing

    DDRA |= (1 << DDA2); //Output: Red LED
    DDRA |= (1 << DDA3); //Output: Blue LED
    DDRB &= ~(1 << DDB2); //Input: Push button. Default = 1

    while(1){
        if(!(bitState(PINB, PINB2))){ //If push button pressed
            _delay_ms(Tdebounce);
            while(!(bitState(PINB, PINB2))){} //Loop as long as push button pressed
            counter++;
            if(counter == 5){
                counter = 1;
            }
        }
        switchLED(counter);
    }
}

void switchLED(unsigned char c){
    switch(c){
        case 1: //Both LEDs ON
        bitHigh(PORTA, PORTA2);
        bitHigh(PORTA, PORTA3);
        break;
        case 2: //Red LED ON
        bitHigh(PORTA, PORTA2);
        bitLow(PORTA, PORTA3);
        break;
        case 3: //Blue LED ON
        bitLow(PORTA, PORTA2);
        bitHigh(PORTA, PORTA3);
        break;
        case 4: //Both LED OFF
        bitLow(PORTA, PORTA2);
        bitLow(PORTA, PORTA3);
        break;
    }
}

code with Arduino C

const int BUTTON = 2;
const int LED = 3;
int BUTTONstate = 0;

void setup()
{
  pinMode(BUTTON, INPUT);
  pinMode(LED, OUTPUT);
}

void loop()
{
  BUTTONstate = digitalRead(BUTTON);
  if (BUTTONstate == HIGH)
  {
    digitalWrite(LED, HIGH);
  }
  else{
    digitalWrite(LED, LOW);
  }
}

via GIPHY

via GIPHY

via GIPHY

via GIPHY

Program the FabISP 1. Install the necessary packages for AVR Programming. AVR is the family of the chip we used in our board Attiny44. To install the packages, I followed the below steps. The below commands are not for the ISP but for my computer to install the necessary drivers & packages:. sudo apt-get install flex byacc bison gcc libusb-dev avrdude sudo apt-get install gcc-avr sudo apt-get install avr-libc sudo apt-get install libc6-dev 2. Download the firmware The following commands are to download the firmware. Firmwares are kinda like the DNA of the board, it’s something permanent and is burnt on a read-only memory. I downloaded it on the desktop and unzipped it. cd ~/Desktop wget http://academy.cba.mit.edu/classes/embedded_programming/firmware.zip unzip firmware.zip 3. Program an Arduino as an ISP 4. Connect your board to the Arduino ISP as seen below: 5. Open the terminal and type the below commands: sudo make clean : Deletes existing executable files in the directory. sudo make hex : Creates new updated files. 6. Edit the makefile (A makefile is a bunch of rules that explains how your board reacts based on certain prerequisites which affects the outcome of the program, called “target”. In the end you’ll have an executable file that dictates how your board operates.) 7. Comment this line AVRDUDE = avrdude -c avrisp2 -P usb -p $(DEVICE) by adding a hashtag “#” and instead I typed AVRDUDE = avrdude -c stk500v1 -P /dev/ttyACM0 -b19200 -p $(DEVICE) 8. Type the following commands: sudo make fuse : This links the executable file with the makefile. sudo make program: This compiles the program. 9. Type Lsusb to see if your board shows. It should show Multiple Vendors USB Tiny.

Programming ATmega328P Using Arduino UNO Board

Write code using Arduino commands. The target MCU should have the right bootloader burnt to be used on Arduino Uno board. Connect the board to USB and uplad the hex file. To butn a bootloader to a fresh ATmega328P, you can check the built in example from Arduino.

overview of different microcontroller

avr-dude Vs. Arduino¶ Programming in C enables users to have more control and optimized execution. The code written in C occupies less memory than the code written in Arduino. Also, code written in C executes faster. Kepe in mind to program in C, the MCU should not have a bootloader burnt to it, which saves the flash memory needed for the bootloader.

The follwing codes blink a LED on pin PB0 in ATmega328P MCU. The first code using C language and avr-dude and the second using Arduion IDE.

Source

Arduino is easier so I decided to continue with it

for my final project

PCB design and production

after designing the board on eagle and read the pin out

connected the Servo motors and the led

Led Light

via GIPHY

via GIPHY

![](https://i.imgur.com/fb0gV3k.jpg()

via GIPHY

via GIPHY

via GIPHY

programing and networking

and did the code for the Bluetooth

connected to servo and the led light

>
*/code by zaid marji

*/

#include <Servo.h>
#include <FastLED.h>
#include <SoftwareSerial.h>
//moto
Servo mot_one;  // create servo object to control a servo
Servo mot_two;
Servo mot_three;
Servo mot_four;
Servo mot_five;
Servo mot_six;
SoftwareSerial MyBlue(7, 8); // RX | TX
// Leds
#define NUM_LEDS  124
#define LED_PIN   13

CRGB leds[NUM_LEDS];

// twelve servo objects can be created on most boards
int pos = 0;    // variable to store the servo position
int cnt1 = 0;
int mot = 0;
char blueData;  
void setup() {
 FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(1000);



  mot_one.attach(3);  // that's motor one
  mot_two.attach(5);
  mot_three.attach(6);
  mot_four.attach(9);
  mot_five.attach(10);
  mot_six.attach(11); //that's motor 6 on port number two
  mot_six.write(0);
  delay(1000);
  Serial.begin(9600);
  MyBlue.begin(9600);
 Serial.println("Ready to connect\nDefualt password is 1234 or 000");
}

void loop() {

 if (MyBlue.available()>0) {
   blueData = MyBlue.read();
  // Serial.println(blueData);
 if (blueData == 'a')
 {
   mot_one.write(0);
   mot_two.write(0);
   mot_three.write(0);
   mot_four.write(30);
   mot_five.write(30);
   mot_six.write(30);

   fill_rainbow(leds, NUM_LEDS, 0, 255 / NUM_LEDS);
  FastLED.show();
  delay(500);

   Serial.println("rose up cherry closed");
 }
 else if (blueData == 'b')
 {
   mot_one.write(30);
   mot_two.write(0);
   mot_three.write(0);
   mot_four.write(30);
   mot_five.write(30);
   mot_six.write(30);

  fill_solid(leds, NUM_LEDS, CRGB::Red);
  FastLED.show();
  delay(500);

   Serial.println("cherry up rose closed");
 }
   else if (blueData == 'c')
 {
  zero();
   mot_one.write(0);
   mot_two.write(30);
   mot_three.write(0);
   mot_four.write(30);
   mot_five.write(30);
   mot_six.write(30);

     fill_solid(leds, NUM_LEDS, CRGB(50,0,200));
  FastLED.show();
  delay(500);

   Serial.println("roseup whiefull closed");
 }

 else if (blueData == 'd')
 {
  zero();
   mot_one.write(0);
   mot_two.write(0);
   mot_three.write(30);
   mot_four.write(30);
   mot_five.write(30);
   mot_six.write(30);

   fill_solid(leds, NUM_LEDS, CRGB(101,0,11));
  FastLED.show();
  delay(500);

   Serial.println("Motors are in Pos 30");
 }
 else if (blueData == 'e')
 {
  zero();
   mot_one.write(0);
   mot_two.write(0);
   mot_three.write(0);
   mot_four.write(0);
   mot_five.write(30);
   mot_six.write(30);
   Serial.println("Motors are in Pos 30");
 }
 else if (blueData == 'f')
 {
  zero();
   mot_one.write(0);
   mot_two.write(0);
   mot_three.write(0);
   mot_four.write(30);
   mot_five.write(0);
   mot_six.write(30);
   Serial.println("Motors are in Pos 30");
 }
 else if (blueData == 'g')
 {
  zero();
   mot_one.write(0);
   mot_two.write(0);
   mot_three.write(0 );
   mot_four.write(30);
   mot_five.write(30);
   mot_six.write(30);
   Serial.println("Motors are in Pos 30");
 }
 }
/*
  for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
    // in steps of 1 degree
    mot_six.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }
  for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
    mot_six.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }  
*/
/*
  int mot = 0 ; // pin7 is motor 1, pin 6 is motor 2, till pin2 is motor 6

  Serial.println("Monitor cleared, loop Func started");
  int pos = 0;
  Serial.println("pos variable currently = ");
  Serial.println(pos);


  Serial.println("Servos will ALL be sent to zero with 0.5 second delays");

  mot_one.write(pos);
  delay(1500);
  mot_two.write(pos);
  delay(1500);
  mot_three.write(pos);
  delay(1500);
  mot_four.write(pos);
  delay(1500);
  mot_five.write(pos);
  delay(1500);
  mot_six.write(pos);

  Serial.println("Now, All should be at angle: ");
  Serial.println(pos);

  for (pos = 0; pos <= 180; pos += 15) { // goes from 0 degrees to 180 degrees

    Serial.println("servos should now go to angle: ");
    Serial.println(pos);
    Serial.println("Motors will rotate each by ++15 Degrees now");

    mot_one.write(pos);
    Serial.println(pos);
    delay(1500);
    mot_two.write(pos);
    Serial.println(pos);
    delay(1500);
    mot_three.write(pos);
    Serial.println(pos);
    delay(1500);
    mot_four.write(pos);
    Serial.println(pos);
    delay(1500);
    mot_five.write(pos);
    Serial.println(pos);
    delay(1500);
    mot_six.write(pos);
    Serial.println(pos);
    delay(1500);

    delay(1500);// waits 15ms for the servo to reach the position
    Serial.println("servos shoul've ALL moved by ++15 degrees now");
  }
*/

}

void zero(){
  mot_one.write(0);
   mot_two.write(0);
   mot_three.write(0);
   mot_four.write(30);
   mot_five.write(30);
   mot_six.write(30);
   Serial.println("Motors are in Pos Zero");
}

via GIPHY

via GIPHY

input week

ultra sonic as an input, I updated the input design to merge between ultra sonic as an input and servomotor as output I tasted using Arduino

``` #include

Servo myservo;

const int trigPin = 11; const int echoPin = 10;

long duration; int distance; int led = 5; int led_feedBack;

int x; int timer; void setup() { pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); pinMode( led , OUTPUT ); myservo.attach(6); myservo.write(0); Serial.begin(9600); } void loop() {

ultra();

if( distance < 100 ) { state:
ultra(); timer = 0;

 Serial.println( distance );

 if( distance > 100 )
 {
   if( x == 0 ){ x = 1; }else{ x = 0; }
 }
 else
 {
   goto state;   
 }

} else if( x == 1 ) { timer++; }

if( timer >= 500 ) //time to close { x = 0; timer = 0; Serial.println(“Timer end”); }

if( x == 0 ) { myservo.write(0);

 if( led_feedBack == 1 )
 {
   for( int i = 255; i > 0; i-- )
   {
     analogWrite( led , i );
     delay(5);
   }
   led_feedBack = 0;
 }

}

if( x == 1 ) { myservo.write(180);

     if( led_feedBack == 0 )
 {
   for( int i = 0; i < 255; i++ )
   {
     analogWrite( led , i );
     delay(5);
   }
   led_feedBack = 1;
 }

}

}

void ultra() { digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); duration = pulseIn(echoPin, HIGH ); distance= duration*0.034/2; //Serial.println(distance); } ```

#include <Servo.h>

Servo myservo;
Servo myservo2;
const int trigPin = 1;
const int echoPin = 0;

long duration;
int distance;
int led = 5;
int led_feedBack;

int x;
int timer;
void setup() {
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode( led , OUTPUT );
myservo.attach(3);
 myservo2.attach(2);
 myservo.write(0);
myservo2.write(0);
}
void loop() {

ultra();



 if( distance < 100 )
 {
   state:    
   ultra();
   timer = 0;



   if( distance > 100 )
   {
     if( x == 0 ){ x = 1; }else{ x = 0; }
   }
   else
   {
     goto state;   
   }

 }
 else if( x == 1 )
 {
   timer++;
 }



 if( timer >= 500 ) //time to close
 {
   x = 0;
   timer = 0;

 }





 if( x == 0 )
 {
   myservo.write(0);
    myservo2.write(180);
   if( led_feedBack == 1 )
   {
     for( int i = 255; i > 0; i-- )
     {
       analogWrite( led , i );
       delay(5);
     }
     led_feedBack = 0;
   }
 }

 if( x == 1 )
 {
   myservo.write(180);
   myservo2.write(0);
       if( led_feedBack == 0 )
   {
     for( int i = 0; i < 255; i++ )
     {
       analogWrite( led , i );
       delay(5);
     }
     led_feedBack = 1;
   }

 }


}




void ultra()
{
 digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH );
distance= duration*0.034/2;
//Serial.println(distance);
}


Last update: July 7, 2021