Monday, January 22, 2018

Hello-world - blinking led with atmega8535 avr


As we know how to compile C/C++ avr code on the previous article. Now we let's apply the method again to to make our hello-world program, it is a simple blinking led program. here the explanation will be more concerned about the programming itself. beginning from header file, main() function and _delay_ms() function, register accessing, and a little bit about bitwise operations.
As always, a proteus application will be used as our simulation here and also avr from GNU compiler to compile our code to generate hex file.

That's it!, just make a circuit like below in the proteus program
Figure 1 Blinking Led Circuitry

Then type the program below on your favorite text editor:

#include <avr/io.h>             //DDRA, PORTA
#include <util/delay.h>       //_delay_ms()

int main(){              //“main” function must exist

  DDRA |= 0x01; //activate A register on the first bit

   while(1){ //endless loop

     PORTA |= 0x01; //assign HIGH logic to the first bit of A Register, led turns on
    _delay_ms(250); //wait for 250 milli second

     PORTA &= ~0x01; //assign LOW logic, led turns off
    _delay_ms(500); //wait for 250 milli second
   }

   return 0; //integer return type for our main function
}

Then compile the above program (by previous artile method), and insert the hex file having been generated into the MCU of proteus simulation. Don't forget to set the CPU speed according to the speed when we compile the program (-DF_CPU=2000000UL), in this case, the clock speed is 2MHz.
Figure 2 inserting hex file and setting CPU speed

Run the program to see the result, it must be blinking.


Now let's come back to the program we have made:

  • Header File
    When we are working with C/C++, firstly, we have to include somthing, here we have seen the include syntax:
    #include <…>, this is usually called by header file. the name inside the brackets is just a file name containing configuration of the specific MCU, in this case atmega8535. e.g.,:
    #include <avr/io.h> //contains DDRA, PORTA, that can be accessed directly. but now how about the form of the value accessed??
    The form of the value here is an integer, with 8-bit resolution, meaning that it can hold value of 0 to 255.
  • Main() function and _delay_ms() function
    N
    ext we have seen int main(). this is also called by function name, that must be declared in C/C++ program. This is where the program firstly starts the execution. For the _delay_ms() function, it's in util/delay.h. as the name of the function, this function will stop the program flow for the specified time in unit of millisecond. e.g., we pass parameter of 250 (as the above example above), then the program flow (at where the function is called) will be paused for 0.25 second. For the people being familiar with C/C++ programming language, it will be so easy.
Figure 3 A Register, DDRA (source: Atmega85353 datasheet)
  • Register Accessing
    Data Direction Register A (DDRA) is used to activate or deactivate a particular bit in it, in other words we use it to set pins labeled PORTA on the MCU (proteus simulation) as seen on figure 1. DDRA |= 0x01, or equivalent to DDRA = DDRA | 0x01 in hexa form, or DDRA = DDRA | 0b00000001 in binary form. It means to activate pin 0 in the register. see figure 3. As in figure 3 shows the sequence of the bit number of 0 to 7 with the default value in each is 0. So when we assign the 0th bit of DDRA by 1, so the bit will be active, meaning that we can set the logic in this bit to LOW state (0 volt) or HIGH state (5 volt) via PORTA register.
    See the figure 4.
    Figure 4 A register, PORTA (source: Atmega8535 datasheet)


A little bit about bitwise operator
  1. OR Bitwise Operator '|'
    As the example above:
    PORTA |= 0x01; equivalent to
    PORTA = PORTA | 0x01; equivalent to
    PORTA = PORTA | 0b00000001; binary format (8-bit)
    something that needs to be remembered is that a major number of atmega8535 register such as PORTA and DDRA have 8-bit resolution, if we try to assign it with the value that's bigger than 8-bit e.g., 0b100010001 (9-bit) then there is a big chance of your program to have undefined behavior. From the above example, we can clarify:
    PORTA 00000000 (default register value)
    OR 00000001
    result 00000001 (the 0th bit active, HIGH logic)

  2. AND Bitwise Operator '&'
    As the example above:
    PORTA &= ~0x01; equivalent to
    PORTA = PORTA & ~0x01; equivalent to
    PORTA = PORTA & ~0b00000001; equivalent to
    PORTA = PORTA & 0b11111110; binary binary(8-bit)
    From the above example, we can clarify:
    PORTA 00000001 (the value from the previous operation above)
    AND 11111110 (the result of '~' operator)
    hasil 00000000 (the 0th bit or the whole bit in the resiter not active; LOW logic)

  3. Complement Bitwise Operator '~'
    This operator is usually used to invert the logic stored in a register. for example: 0b00010010, if we place '~' operator in front if it ~0b00010010, so this sequence of value becomes 0b11101101.

  • Note:
    There might be some readers that realize and ask; "why don't we access into the register directly?, without any bitwise operator..". In this case, in this example above, we may do that actually, as:

    PORTA = 0x01; //assign HIGH logic to the first bit and LOW to the rest of
                              //the bit
    _delay_ms(250); //wait for 250 milli second

    PORTA = 0x00; //assign LOW logic to the whole bit of the Register A
    _delay_ms(500); //wait for 250 milli second

    But in the other cases, such accessing 16x2 lcd's register will endanger the process or we would fail to access corectly the register at all, because accessing the register directly means to reset all bit in it and assign it with the new ones. For this reason, I recommend to use the above way even if we just access a single bit in a single register. Such this method is called by mask-bit so that only specific bits that will be updated.


So,, it's how we can make the blinking led, but with an extra explanation on the register :D. May you like it and becomes useful..

No comments:

Post a Comment

Arduino & seven-Segment: Counter-Down / Counter-Up

To be easy to understand, a counter-up or counter-down is a term to mean 'to count by incrementing' or 'to count by decreme...