Intelligent Lighting Control using AVR Microcontroller

May 12th, 2012 | by | technology

May
12

This dissertation is an effort to learn embedded system development and embedded programming using AVR microcontroller.

This dissertation will look at the working of Analog to Digital conversion (ADC) and the usage of Pulse Width Modulation (PWM) for Digital to Analog conversion (DAC). This dissertation will also cover the features of AVR microcontroller and the usage of timers and ADC conversion in AVR microcontroller.

This dissertation will combine the Analog to Digital conversion (ADC) and Pulse Width Modulation (PWM) to create an intelligent lighting, which will be automatically controlled based on the external ambient lighting. So, at dusk, when the external sunlight gradually decreases, the intelligent light will start, and it brightness will start gradually increasing to its maximum. Similarly, at dawn, the first appearance of light in the sky before sunrise, the intelligent light will slowly start dimming and will automatically switch off in the morning.

#define F_CPU 8000000UL

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

// initialize adc
void adcInit()
{
  // AREF = AVcc
  ADMUX = (1<<REFS0);

  // ADC Enable and prescaler of 128
  // 8000000/128 = 62500
  ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
}

// read adc value
uint16_t adcRead(uint8_t ch)
{
  // select the corresponding channel 0~7
  // ANDing with '7' will always keep the value
  // of 'ch' between 0 and 7
  ch &= 0b00000111;  // AND operation with 7
  ADMUX = (ADMUX & 0xF8)|ch;   // clears the bottom 3 bits before ORing

  // start single conversion
  // write '1' to ADSC
  ADCSRA |= (1<<ADSC);

  // wait for conversion to complete
  // till then, run loop continuously
  // The loop does nothing while ADIF is set to 0,
  // it exits as soon as ADIF is set to one,
  // i.e. conversion is complete.
  while(!(ADCSRA & (1<<ADIF)));

  //Clear ADIF by writing one to it
  ADCSRA|=(1<<ADIF);

  return (ADC);
}

void pwmInit()
{
   /*
   TCCR0 - Timer Counter Control Register (TIMER0)
   -----------------------------------------------
   BITS DESCRIPTION

   NO:   NAME   DESCRIPTION
   --------------------------
   BIT 7 : FOC0   Force Output Compare [Not used in this example]
   BIT 6 : WGM00  Wave form generation mode  [SET to 1]
   BIT 5 : COM01  Compare Output Mode    [SET to 1]
   BIT 4 : COM00  Compare Output Mode    [SET to 0]

   BIT 3 : WGM01  Wave form generation mode  [SET to 1]
   BIT 2 : CS02   Clock Select         [SET to 0]
   BIT 1 : CS01   Clock Select         [SET to 0]
   BIT 0 : CS00   Clock Select         [SET to 1]

   The above settings are for
   --------------------------

   Timer Clock = CPU Clock (No Prescalling)
   Mode    = Fast PWM
   PWM Output  = Non Inverted

   */

   TCCR0|=(1<<WGM00)|(1<<WGM01)|(1<<COM01)|(1<<CS00);

   //Set OC0 PIN as output. It is  PB3 on ATmega16 ATmega32

   DDRB|=(1<<PB3);
}

/******************************************************************
Sets the duty cycle of output. 

Arguments
---------
duty: Between 0 - 255

0 = 0%

255 = 100%

The Function sets the duty cycle of pwm output generated on OC0 PIN
The average voltage on this output pin will be

         duty
 Vout=  ------ x 5v
         255 

This can be used to control the brightness of LED or Speed of Motor.
*********************************************************************/

void setPWMOutput(uint8_t duty)
{
   OCR0=duty;
}

int main()
{
  uint16_t adcResult;
  uint8_t pwmBrightness;

  // initialize adc and pwm
  adcInit();
  pwmInit();

  _delay_ms(50);

  while(1)
  {
    adcResult = adcRead(0);    // read adc value at PA0

    // Mapping the adc value in the range of 0-1024 (2^10 bits)
    // to 0-255, which can be sent to 8 bit OCR0 register.
    // So the adcResult is divided by 4, to make it in the
    // range of 0-255.
    // After that the value is subtracted from 255, so that if
    // the adc value is less, we want to send high value to the
    // OCR0, for increasing brightness, and if the adc value is
    // high, we want to send lower values for the PWM signal
    // generation, to reduce the brightness of the LED.
    pwmBrightness = (uint8_t)(255 - (adcResult/4));

    //Send the pwm value to the OCR0, to control the LED brightness
    setPWMOutput(pwmBrightness);
   }
}

The presentation and the project report can be downloaded from the previous post: Seminar on Embedded System Development using AVR Microcontroller.

No Comments »

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 »