PWM Signal Generation using AVR Timers

June 22nd, 2010 | by | technology

Jun
22

Microcontrollers can only generate a high voltage of +5V and a low voltage of 0V. Let’s say you need a +2.5V for controlling the brightness of LED or the speed of the DC motor. To handle such situations, we use Pulse Width Modulation (PWM). In PWM, we will vary the output voltage between high and low at a very high speed, such that, the effective output voltage is the desired voltage. For example, for +2.5V, we will switch between high and low voltage alternatively, at a very high speed. The output wave is actually square in nature, but at a very high frequency, we can safely assume the average as the output voltage.

PWM

More information about PWM and the code for this example can be found at:

Comments Closed

Bipolar stepper motor controller using AVR microcontroller and L298N motor driver

June 22nd, 2010 | by | technology

Jun
22

In this video, we’ll see how to control the bipolar stepper motor using the AVR ATMega32 microcontroller and L298N motor driver. Both the motors ports A & B are enabled, by connecting the EnableA and EnableB lines to PB0 and PB1 respectively. Both the PB0 and PB1 pins are always at high volatge. The input lines of the L298N motor driver board 1,2,3,4 are connected to Port PB7, PB6, PB5, PB4 respectively. Now, the voltage is varied on the input lines of the L298N motor driver using the ATMega32 microcontroller, causing the change in voltage at the motor input lines, i.e., the L298N motor driver output lines. This causes the stepper motor to rotate.

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

int main(void)
{
  DDRB=0xFF;
  while(1)
  {
    //Normal Bipolar Stepping
    PORTB = 0b10010011;
    _delay_ms(10);
    PORTB = 0b01010011;
    _delay_ms(10);
    PORTB = 0b01100011;
    _delay_ms(10);
    PORTB = 0b10100011;
    _delay_ms(10);
  }
}

No Comments »

Interfacing DS1307 RTC Chip with AVR Microcontroller

June 19th, 2010 | by | technology

Jun
19

DS1307 is a Real Time Clock Chip, which can manage time without external power, using a +3V lithium cell. It can also store date and year. In the example we will interface DS1307 RTC Chip with ATMega32 microcontroller and create a clock example, that will display the time and date.

This example is based on the sample from:

No Comments »

24C I2C Serial EEPROM Interfacing with AVR

June 14th, 2010 | by | technology

Jun
14

An EEPROM is kinds of novalatile memory, that means it is used for storing digital data permanently, without any power suply. EEPROM stands for Electrically Erasable Programmable Read Only Memory. In this example, we have asked the user to enter a number, then break that number into two bytes, as EEPROM is read/write as one byte at a time. Then we have stored the two bytes into the consecutive memory. Also note, that a +5V needs to be applied through a 10K resistor, between the lines that connect the SCL/SDA of the microcontroller and the EEPROM.

More details can be found at:

No Comments »

Microcontroller based Electronic Lock

June 13th, 2010 | by | technology

Jun
13

/*----------------------------------------------------------------
-------------------------- HEADER FILES --------------------------
-----------------------------------------------------------------*/

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

/*----------------------------------------------------------------
------------------- DEFINITIONS ----------------------------------
-----------------------------------------------------------------*/

#define DATA_DDR             DDRA    // ENTER THE PORT WHICH CONTROLS
#define DATA_PORT            PORTA   // THE DATA PINS D0 TO D7 

#define CONTROL_DDR          DDRD    // ENTER THE PORT WHICH CONTROLS
#define CONTROL_PORT         PORTD   // THE CONTROL PINS
#define Enable               2       // CoNNECTION OF ENABLE TO PIN OF ABOVE PORT
#define RS                   0       // CoNNECTION OF RegisterSelect TO PIN OF ABOVE PORT
#define RW                   1       // CoNNECTION OF Read/~Write TO PIN OF ABOVE PORT
#define CONTROL_MASK         0X07    // CHANGE THIS VALUE CONSIDERING THE PINS ABOVE AS HIGH

#define KB_PORT_OUT PORTB       //Keypad Port
#define KB_PORT_DDR DDRB        //Data Direction Register
#define KB_PORT_IN PINB         //Keypad Port Pins

#define col1 PB0                //Column1 PortA.0
#define col2 PB1                //Column2 PortA.1
#define col3 PB2                //Column3 PortA.2
#define col4 PB3                //Column4 PortA.3

#define TRUE 1
#define FALSE 0

/*----------------------------------------------------------------
----------------------CONTROL BITS OF LCD ------------------------
-----------------------------------------------------------------*/

#define Set_Enable                   CONTROL_PORT |=_BV(Enable)   // THE MACROS HERE ARE
#define Clear_Enable                 CONTROL_PORT &=~_BV(Enable)  // SELF EXPLANATORY
#define Write_Lcd                    CONTROL_PORT &=~_BV(RW)      //
#define Read_Lcd                     CONTROL_PORT |=_BV(RW)       //
#define Select_InstructionRegister   CONTROL_PORT &=~_BV(RS)      //
#define Select_DataRegister          CONTROL_PORT |=_BV(RS)       //
#define Data_Lcd(b)                  DATA_PORT=b                  //
#define delay(b)                     _delay_ms(b)                 //

/*----------------------------------------------------------------
----------------------FUNCTION DECLARATIONS ----------------------
-----------------------------------------------------------------*/

void Init_Ports(void);    // Initialize Ports, for selecting input output pins in the MCU
void Init_Lcd(void);      // Initialize LCD,   for starting and clearing LCD screen
void Lcd_Send(unsigned char a);// For sending a character to the LCD
void GotoNextLine(void);       // For printing characters on the next line in the LCD
void GotoFirstLine(void);      // For printing characters on the first line in the LCD
void ClearDisplay(void);       // For clearing LCD
void key_init();
unsigned char get_key();

/*----------------------------------------------------------------
----------------------MAIN FUNCTION-------------------------------
-----------------------------------------------------------------*/
int main()
{
    int len,len1,len2,len3,len4,len5,len6;
    char str1[] = "Welcome Priyank!";         // String to be printed in 1st line
    char str2[] = "Enter PIN: ";              // String to be printed in 2st line
    char str3[] = "This is invalid";          // String to be printed in 1st line
    char str4[] = "PIN, try again.";          // String to be printed in 2nd line
    char str5[] = "Welcome Home!";            // String to be printed in 1st line
    char str6[] = "Have a nice day.";         // String to be printed in 2nd line
    unsigned char keyval;   //A variable

    len1=strlen(str1);
    len2=strlen(str2);
    len3=strlen(str3);
    len4=strlen(str4);
    len5=strlen(str5);
    len6=strlen(str6);

    Init_Ports();
    Init_Lcd();
    key_init();                       

    while(1)
    {
        for (len=0;len<len1;len++)    // Printing the first string
            Lcd_Send(str1[len]);

        GotoNextLine();               // Go to new line

        for (len=0;len<len2;len++)    // Printing the 2nd string
            Lcd_Send(str2[len]);

        int index = 0;
        unsigned char PIN[4];
        while(index < 4)
        {
            keyval = get_key();
            if(keyval != 'X')
            {
                PIN[index] = keyval;
                Lcd_Send('*');
                index++;
            }
        }
        if(PIN[0] == '1' && PIN[1] == '5' && PIN[2] == '7' && PIN[3] == 'F')
            break;

        ClearDisplay();               // Go to new line

        for (len=0;len<len3;len++)    // Printing the first string
            Lcd_Send(str3[len]);

        GotoNextLine();               // Go to new line

        for (len=0;len<len4;len++)    // Printing the 2nd string
            Lcd_Send(str4[len]);

        delay(1000);

        ClearDisplay();               // Go to new line
    }

    ClearDisplay();                   // Go to new line

    for (len=0;len<len5;len++)        // Printing the first string
        Lcd_Send(str5[len]);

    GotoNextLine();                   // Go to new line

    for (len=0;len<len6;len++)        // Printing the 2nd string
        Lcd_Send(str6[len]);

    DDRC = 0xFF;  //Key-board port, higher nibble - input, lower nibble - output
    PORTC = 0xFF; //pull-up enabled for higher nibble
}

/*----------------------------------------------------------------
------------------SEND A CHARACTER TO LCD-------------------------
-----------------------------------------------------------------*/
void Lcd_Send(unsigned char a)
{
    Select_DataRegister; // Declares information that follows as data and not instruction
    Write_Lcd;           // Declared information is to be written
    Data_Lcd(a);         // Send the character passed to the function to LCD to write
    Set_Enable;          // Sets enable,
    delay(5);            // and then
    Clear_Enable;        // Clears it,
    delay(5);            // to be ready for next character.
}

/*----------------------------------------------------------------
-----------------FUNCTIONS TO INITIALIZE PORTS--------------------
-----------------------------------------------------------------*/
void Init_Ports(void)
{
    DATA_DDR=0XFF;                //  Setting data port for output
    CONTROL_DDR=CONTROL_MASK;     //   Setting selected pins of control port for output
    CONTROL_PORT&=~(_BV(Enable)|_BV(RS )|_BV(RW)); //   Setting values to 0 at start
}

/*----------------------------------------------------------------
-------------------FUNCTION TO INITIATE LCD ----------------------
-----------------------------------------------------------------*/
void Init_Lcd(void)
{
    char init[10];
    int i;
    init[0] = 0x01;           // Initializes the display
    init[1] = 0x38;           // 8 - Bit Operation, 2 Line Display,5*8 Dot Character Font
    init[2] = 0x0e;           // Turns on display and cursor
    init[3] = 0x06;           // Entry Mode Set
    init[4] = 0x80;           // Sets DDRAM address to beginning of screen

    Select_InstructionRegister;

    Write_Lcd;
    delay(15);

    for(i=0;i<5;i++)
    {
        Data_Lcd(init[i]);
        Set_Enable;
        delay(5);
        Clear_Enable;
        delay(5);
    }
}

/*----------------------------------------------------------------
-------------FUNCTION TO GOTO NEXT LINE IN LCD -------------------
-----------------------------------------------------------------*/
void GotoNextLine(void)
{
    delay(5);
    Select_InstructionRegister;   // Declares information to follow as instruction
    Data_Lcd(0xc0);               // Code to go to next line of LCD
    Set_Enable;                   //  --  Enable cycle  --
    delay(5);                     // |                    |
    Clear_Enable;                 // |                    |
    delay(5);                     //  --                --
}

/*----------------------------------------------------------------
----------------FUNCTION TO FIRST LINE IN LCD --------------------
-----------------------------------------------------------------*/
void GotoFirstLine(void)
{
    delay(5);
    Select_InstructionRegister;    // Declares information to follow as instruction
    Data_Lcd(0x80);                // Code to go to next line of LCD
    Set_Enable;                    //  --  Enable cycle  --
    delay(5);                      // |                    |
    Clear_Enable;                  // |                    |
    delay(5);                      //  --                --
}

/*----------------------------------------------------------------
------------------FUNCTION TO CLEAR LCD --------------------------
-----------------------------------------------------------------*/
void ClearDisplay(void)
{
    delay(5);
    Select_InstructionRegister;    // Declares information to follow as instruction
    Data_Lcd(0x01);                // Code to go to next line of LCD
    Set_Enable;                    //  --  Enable cycle  --
    delay(5);                      // |                    |
    Clear_Enable;                  // |                    |
    delay(5);                      //  --                --
}

void key_init(){
    KB_PORT_DDR = 0x0F;
    KB_PORT_OUT = 0xFF;
    //stop errant interrupts until set up
    cli(); //disable all interrupts
    MCUCR = 0x00;
    TIMSK = 0x00; //timer interrupt sources
}

unsigned char get_key(){
    unsigned  char upperNibble, keyCode, keyPressed, i;
    while(1)
    {
        upperNibble = 0xff;

        for(i=0; i<4; i++)
        {
            delay(1);
            KB_PORT_OUT = ~(0x01 << i);
            delay(1); //delay for port o/p settling
            upperNibble = KB_PORT_IN | 0x0f;

            if (upperNibble != 0xff)
            {
                delay(20); //key debouncing delay
                upperNibble = KB_PORT_IN | 0x0f;
                if(upperNibble == 0xff) goto OUT;

                keyCode = (upperNibble & 0xf0) | (0x0f & ~(0x01 << i));

                while (upperNibble != 0xff)
                upperNibble = KB_PORT_IN | 0x0f;

                delay(20); //key debouncing delay

                switch (keyCode) //generating key character to display on LCD
                {
                    case (0xee): keyPressed = '0';
                    break;
                    case (0xde): keyPressed = '1';
                    break;
                    case (0xbe): keyPressed = '2';
                    break;
                    case (0x7e): keyPressed = '3';
                    break;
                    case (0xed): keyPressed = '4';
                    break;
                    case (0xdd): keyPressed = '5';
                    break;
                    case (0xbd): keyPressed = '6';
                    break;
                    case (0x7d): keyPressed = '7';
                    break;
                    case (0xeb): keyPressed = '8';
                    break;
                    case (0xdb): keyPressed = '9';
                    break;
                    case (0xbb): keyPressed = 'A';
                    break;
                    case (0x7b): keyPressed = 'B';
                    break;
                    case (0xe7): keyPressed = 'C';
                    break;
                    case (0xd7): keyPressed = 'D';
                    break;
                    case (0xb7): keyPressed = 'E';
                    break;
                    case (0x77): keyPressed = 'F';
                    break;
                    default : keyPressed = 'X';
                }//end of switch

                return keyPressed;

                OUT:;
            }//end of if
        }//end of for
    }//end of while(1)
}

No Comments »

AVR Development Board

June 10th, 2010 | by | technology

Jun
10

AVR Development Board
Click on the image to zoom.

I recently purchased an AVR Development Board from the NSK electronics located at S.P. Road, Bangalore, opp. to Vishal Electronics. A development board is great way to start embedded programming, especially when you don’t have much electronics component knowledge, or don’t want to struggle with the PCB or breadboard. It gives you an instant jump start. The above one cost me around 550 Rs and the USB programmer comes for another 450 Rs. Though you can get an USB programmer for 370 Rs at OM electronics and a basic 40 PIN AVR prototype board at NSK electronics for 95 Rs. But I like this board, as it had many features like 7 Segment LCD, LED arrays, keyboard Matrix, RS 232 interface, Relay and Stepper motor drive using ULN2003, LCD Display connector, etc. The 12 V adapter cost an extra 90 Rs and the ATMega32 chip costs around 160 Rs. I am completely novice to the embedded and electronics world, so consider these prices as the MRP, you can bargain a lot. At least buying from local shops is much cheaper then those online robotics shops, who charges 3 times more + taxes + courier charges. Also for learning and hobby projects, I found AVR development boards sold at S.P. Road much more useful and cheaper. Some of the, another component prices:


  • AVR development board – 550 Rs
  • 40 Pin prototype board – 95 Rs
  • AVR USB programmer – 370 Rs
  • ATMega32 – 160 Rs
  • 16×2 Character LCD – 120 Rs
  • Breadboard – 55 Rs
  • Resistance Pack – 25 Rs
  • UNI-T digital multimeter – 95 Rs
  • 40 Pin ZIP Socket – 60 Rs
  • 25 Watt Soldron Iron – 150 Rs
  • 12 V Adaptor – 90 Rs

If you have information about good shops, or cheaper electronics components, please do let me know.

The USB AVR programmer and development board comes with software like SinaProg, AVR Dude, AVR Studio, WinAVR. To start programming, just use a sample program and build it to create an Intel HEX file, then connect the USB cable to the laptop and USB programmer, install the USB drivers, that comes with in the CD. After that insert the micro controller into the development board, and connect the FRC cable from the USB programmer to development board in the ISP header, and use SinaProg to burn the Hex file to the micro controller.

That’s it for now, Enjoy Programming!

2 Comments »

Dancing LED

June 9th, 2010 | by | technology

Jun
09

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

#define LED PINA0

int main()
{
  DDRA = 0xff;
  while(1)
  {
    PORTA|=(1<<LED);
    _delay_ms(120);

    PORTA&=~(1<<LED);
    _delay_ms(150);

    PORTA|=(2<<LED);
    _delay_ms(120);

    PORTA&=~(2<<LED);
    _delay_ms(150);

    PORTA|=(4<<LED);
    _delay_ms(120);

    PORTA&=~(4<<LED);
    _delay_ms(150);

    PORTA|=(0x10<<LED);
    _delay_ms(120);

    PORTA&=~(0x10<<LED);
    _delay_ms(150);

    PORTA|=(0x20<<LED);
    _delay_ms(120);

    PORTA&=~(0x20<<LED);
    _delay_ms(150);

    PORTA|=(0x40<<LED);
    _delay_ms(120);

    PORTA&=~(0x40<<LED);
    _delay_ms(150);

    PORTA|=(0x80<<LED);
    _delay_ms(120);

    PORTA&=~(0x80<<LED);
    _delay_ms(150);

    PORTA|=(0x40<<LED);
    _delay_ms(120);

    PORTA&=~(0x40<<LED);
    _delay_ms(150);

    PORTA|=(0x20<<LED);
    _delay_ms(120);

    PORTA&=~(0x20<<LED);
    _delay_ms(150);

    PORTA|=(0x10<<LED);
    _delay_ms(120);

    PORTA&=~(0x10<<LED);
    _delay_ms(150);

    PORTA|=(4<<LED);
    _delay_ms(120);

    PORTA&=~(4<<LED);
    _delay_ms(150);

    PORTA|=(2<<LED);
    _delay_ms(120);

    PORTA&=~(2<<LED);
    _delay_ms(150);
  }
}

No Comments »

Digital Stopwatch

June 9th, 2010 | by | technology

Jun
09

/* Interfacing multiple displays */

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

#define true 1
#define false 0

//Global variable for the clock system
volatile unsigned int   clock_millisecond=0;
volatile unsigned char  clock_second=0;

volatile unsigned char  clock_minute=0;
volatile unsigned char  clock_hour=0;

//Display hiding system
uint8_t hide_display = false;

//Blinking system
uint8_t blink_display = true;

volatile uint8_t digits[4];

void SevenSegment(uint8_t n, uint8_t dp)
{
  uint8_t symbols[]=
  {
    0x3F, 0x06, 0x5B, 0x4F, /* 0,1,2,3 */
    0x66, 0x6D, 0x7D, 0x07, /* 4,5,6,7 */
    0x7F, 0x6F, 0x77, 0x7F, /* 8,9,A,B */
    0x39, 0x3F, 0x79, 0x71, /* C,D,E,F */
    0x00                    /* BLANK   */
  };

  PORTA = symbols[n] | (dp << 7); /* obtain the one's digit and send to display */
}

void Print(uint16_t num)
{
  /*
    This function breaks apart a given integer into separate digits
    and writes them to the display array i.e. digits[]
  */

  uint8_t i=0;
  uint8_t j;
  if(num>9999) return;

  while(num)
  {
    digits[i]=num%10;
    i++;

    num=num/10;
  }

  //Fill with leading 0s
  for(j=i;j<4;j++) digits[j]=0;
}

int main()
{
  DDRA = 0xFF; /* Port A to send a symbol code to a display */
  DDRB = 0x0F; /* Port B for deciding which display is active */
  DDRC = 0x00;

  // Prescaler = FCPU/256
  TCCR0|=(1<<CS02)/*|(1<<CS00)*/;

  //Enable Overflow Interrupt Enable
  TIMSK|=(1<<TOIE0);

  //Initialize Counter
  TCNT0=0;

  //initailly stop the timer by setting clock source = 000
  TCCR1B&=(~((1<<CS12)|(1<<CS11)|(1<<CS10)));

  OCR1A=15;

  //Enable the Output Compare A interrupt
  TIMSK|=(1<<OCIE1A);

  sei(); // enable ALL interrupts

  //Stop blinking the display
  blink_display=false;

  //Show the display
  hide_display=false;

  TCCR1B=(1<<WGM12)|(1<<CS11)|(1<<CS10);

  //Continuasly display the time
  while(1)
  {
    int disp;
    disp=(clock_minute*100)+clock_second;
    //disp=(clock_hour*100)+clock_minute;
    if(!(PINC & (1<<PC1)))
    {
      //halt pressed

      //stop the timer
      TCCR1B&=(~((1<<CS12)|(1<<CS11)|(1<<CS10)));

      //Start blinking the display
      blink_display=true;
    }
    Print(disp);
  }
  return 0;
}

ISR(TIMER0_OVF_vect)
{
  /*
    This interrupt service routine (ISR)
    Updates the displays
  */
}

//The output compute interrupt handler
//We set up the timer in such a way that
//this ISR is called exactly at 1ms interval
ISR(TIMER1_COMPA_vect)
{
  clock_millisecond++;
  if(clock_millisecond % 4 == 0)
  {
    static uint8_t i = 0;
    switch(i)
    {
    case 0:
      PORTB = 0x01; /* turn on Display1 */
      SevenSegment(digits[0], 0);
      break;
    case 1:
      PORTB = 0x02; /* turn on Display2 */
      SevenSegment(digits[1], 0);
      break;
    case 2:
      PORTB = 0x04; /* turn on Display3 */
      SevenSegment(digits[2], 1);
      break;
    case 3:
      PORTB = 0x08; /* turn on Display4 */
      SevenSegment(digits[3], 0);
      break;
    };
    i++;
    if(i == 4)
      i = 0;
  }
  if(clock_millisecond==1000)
  {
    clock_second++;
    clock_millisecond=0;
    if(clock_second==60)
    {
      clock_minute++;
      clock_second=0;
    }
    if(clock_minute==60)
    {
      clock_hour++;
      clock_minute=0;
    }
  }
}

The above code sample is heavily based on the example taken from:
http://extremeelectronics.co.in/avr-projects/avr-project-digital-stop-watch-with-atmega8/,
with slight modification to make it work on my development board, as the crystal frequency may be different (Guess so). Another interesting article that talks about multiplexed 7 segment displays is:
http://extremeelectronics.co.in/avr-tutorials/multiplexed-seven-segment-displays/.

No Comments »

Test Switches

June 9th, 2010 | by | technology

Jun
09

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

void delay_ms(uint16_t t)
{
  while (t--)
    _delay_ms(1);
}

void leds_update(uint8_t index)
{
  uint8_t mask = _BV(PB0) | _BV(PB1) | _BV(PB2) | _BV(PB3) |  _BV(PB4) | _BV(PB5)
               | _BV(PB6) | _BV(PB7);

  if ( index < 8 )
  {
    PORTB = (PORTB & ~mask) | _BV(index);
  }
}

int main (void)
{
  uint8_t selection;
  uint8_t state_sw0, state_sw1;
  uint8_t prev_state_sw0, prev_state_sw1;

  /* Setup PB0-7 as outputs */
  DDRB = _BV(PB0) | _BV(PB1) | _BV(PB2) | _BV(PB3) |  _BV(PB4) | _BV(PB5)
       | _BV(PB6) | _BV(PB7);

  /* Setup PC0 and PC1 as inputs with pull-up */
  DDRC &= ~(_BV(DDC0) | _BV(DDC1));
  PORTC |= _BV(DDC0) | _BV(DDC1);

  /* The first selected led is led 0 */
  selection = 0;
  leds_update(selection);

  /* Init the switches state */
  prev_state_sw0 = 0;
  prev_state_sw1 = 0;

  /* Main loop */
  for(;;)
  {
    /* Read the current switch state */
    state_sw0 = (PINC & _BV(DDC0));
    state_sw1 = (PINC & _BV(DDC1));

    if (state_sw0 && !prev_state_sw0)
    {
      /* The switch 0 has been pressed */
      if (selection < 7)
      {
        selection++;
        leds_update(selection);
      }
    }

    if (state_sw1 && !prev_state_sw1)
    {
      /* The switch 1 has been pressed */
      if (selection > 0)
      {
        selection--;
        leds_update(selection);
      }
    }

    prev_state_sw0 = state_sw0;
    prev_state_sw1 = state_sw1;

    /* Wait for 20ms */
    delay_ms(20);
  }

  return(0);
}

This sample is stolen from http://elasticsheep.com/2009/10/adding-switches/, with minor variations.

No Comments »