AVR Microcontroller Programming: LCD, Keypad, 7-Segment & Assembly Examples

Posted by Anonymous and classified in Electronics

Written on in English with a size of 11.15 KB

AVR Microcontroller Programming Examples

This collection of embedded C and AVR assembly examples covers common hardware interfacing and programming techniques for AVR microcontrollers, including LCD display control, matrix keypad scanning, 7-segment displays, bit manipulation, delays, and I/O port handling.

LCD Display

The following program initializes a 16x2 LCD in 8-bit mode and prints text on both lines.

#define F_CPU 1000000UL //1 MHz clock
#include <avr/io.h>
#include <util/delay.h>

void lcdCommand(unsigned char cmnd)
{
    PORTA = cmnd;
    PORTB &= ~(1<<0);  //RS = 0 for command
    PORTB &= ~(1<<1);  //RW = 0 for write
    PORTB |= (1<<2);    //EN = 1 for H to L pulse
    _delay_us(1);
    PORTB &= ~(1<<2);  //EN = 0 for H to L pulse
    _delay_us(100);
}

void lcdData(unsigned char data)
{
    PORTA = data;
    PORTB |= (1<<0);    //RS = 1 for data
    PORTB &= ~(1<<1);  //RW = 0 for write
    PORTB |= (1<<2);    //EN = 1 for H to L pulse
    _delay_us(1);
    PORTB &= ~(1<<2);  //EN = 0 for H to L pulse
    _delay_us(100);
}

void lcd_print(char *str)
{
    unsigned char i = 0;
    while(str[i] != 0)
    {
        lcdData(str[i]);
        i++;
    }
}

int main(void)
{
    DDRA = 0xFF;   //LCD data pins connected to Port A
    DDRB = 0xFF;   //LCD control pins connected to Port B
    PORTB &= ~(1<<2);  //EN = 0
    _delay_us(2000);
    lcdCommand(0x38);  //2 line 5x7 matrix
    lcdCommand(0x0E);  //display on, cursor on
    lcdCommand(0x01);  //clear LCD
    _delay_us(2000);
    lcdCommand(0x06);  //shift cursor right
    lcdCommand(0x80);
    lcd_print("Electronics Dept");
    lcdCommand(0xC0);
    lcd_print("GPTC Kottayam");
    while(1);
    return 0;
}

Matrix Keyboard

This program scans a 4x3 matrix keypad connected to Port C and outputs the pressed key value on Port D.

#define F_CPU 1000000UL //1 MHz clock
#include <avr/io.h>
#include <util/delay.h>

unsigned char keypad[4][3] = {'1','2','3',
                              '4','5','6',
                              '7','8','9',
                              '*','0','#'};

int main(void)
{
    unsigned char colloc, rowloc;
    DDRD = 0xFF;
    DDRC = 0xF8;
    PORTC = 0xFF;
    while(1) //repeat forever
    {
        while(1)
        {
            PORTC = 0xEF; //ground row A
            colloc = (PINC & 0x07); //read the columns
            if (colloc != 0x07)
            {
                rowloc = 0;
                break;
            }
            PORTC = 0xDF; //ground row B
            colloc = (PINC & 0x07);
            if (colloc != 0x07)
            {
                rowloc = 1;
                break;
            }
            PORTC = 0xBF; //ground row C
            colloc = (PINC & 0x07);
            if (colloc != 0x07)
            {
                rowloc = 2;
                break;
            }
            PORTC = 0x7F; //ground row D
            colloc = (PINC & 0x07);
            if (colloc != 0x07)
            {
                rowloc = 3;
                break;
            }
        }
        if(colloc == 0x06)
        {
            PORTD = keypad[rowloc][0];
        }
        else if(colloc == 0x05)
        {
            PORTD = keypad[rowloc][1];
        }
        else
        {
            PORTD = keypad[rowloc][2];
        }
    }
    return 0;
}

7-Segment Display

This program counts from 0 to 9 on a common-cathode 7-segment display connected to Port C.

#define F_CPU 1000000UL //1 MHz clock
#include <avr/io.h>
#include <util/delay.h>

char seg_7[10] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

int main(void)
{
    DDRC = 0xFF;  //Port C is output
    PORTC = 0x00;
    int i = 0;
    while(1)
    {
        PORTC = seg_7[i];
        _delay_ms(1000);
        i += 1;
        if(i >= 10)
        {
            i = 0;
        }
    }
    return 0;
}

Usage of For Loop

This example uses a for loop to send values from 0 to 20 to Port B with a 100 ms delay between each value.

#define F_CPU 100000UL
#include <avr/io.h>        // standard AVR header
#include <util/delay.h>  // delay loop function

int main(void)
{
    unsigned char z;
    DDRB = 0xFF;  // setting PORTB as output
    while (1)
    {
        for (z = 0; z <= 20; z++)
        {
            PORTB = z;        // value sent to PORTB
            _delay_ms(100);   // delay 100 ms
        }
    }
    return 0;
}

Bit Manipulation

This program controls a relay and a buzzer using bit manipulation on Port C.

#include <avr/io.h>        // standard AVR header
#include <util/delay.h>  // delay loop function

#define buzzer PC5
#define relay  PC4
#define PORT   PORTC

void InitPort(void)
{
    DDRB = 0xFF;   // PORTB pins defined as output
    DDRC = 0xFF;   // PORTC pins defined as output
    PORT |= (1 << relay);  // relay ON
}

int main(void)
{
    InitPort();    // calling port initialization function
    while (1)      // indefinite loop
    {
        _delay_ms(1000);      // 1 sec delay
        PORTB = 0xFF;         // PORTB on
        PORT |= (1 << buzzer);   // buzzer ON
        _delay_ms(1000);      // 1 sec delay
        PORTB = 0x00;         // PORTB off
        PORT &= ~(1 << buzzer); // buzzer OFF
    }
}

Software Delay

This program toggles PORTB and PORTC every second using a software delay.

#define F_CPU 1000000UL
#include <avr/io.h>        // standard AVR header
#include <util/delay.h>  // delay loop function

int main(void)
{
    DDRB = 0xFF;   // setting PORTB as output
    DDRC = 0xFF;   // setting PORTC as output
    PORTB = 0xFF;  // setting value for PORTB
    PORTC = 0xFF;  // setting value for PORTC
    while (1)      // indefinite loop
    {
        _delay_ms(1000);   // delay of 1 sec
        PORTB = ~PORTB;    // toggle PORTB
        PORTC = ~PORTC;    // toggle PORTC
    }
    return 0;
}

Port Pin as Input and Output

This program reads the state of PORTD and writes it to PORTB.

#include <avr/io.h>  // standard AVR header

void InitPort(void)
{
    DDRB = 0xFF;  // PORTB pins defined as output
    DDRD = 0x00;  // PORTD pins defined as input
}

int main(void)
{
    InitPort();   // calling port initialization function
    while (1)     // indefinite loop
    {
        PORTB = PIND;  // reading PORTD and writing the value to PORTB
    }
}

I/O Port Programming 1: Delay (Assembly)

This ATmega32 assembly program initializes the stack, outputs alternating patterns on PORTB, reads PORTB as input, and displays the value on PORTA.

.INCLUDE "M32DEF.INC"
.ORG 0
LDI R16, HIGH(RAMEND)   ; Initialize the Stack Pointer
OUT SPH, R16
LDI R16, LOW(RAMEND)    ; Initialize the Stack Pointer
OUT SPL, R16
LDI R16, 0XFF           ; R16 = FF
OUT DDRA, R16           ; Make PORTA as output
LDI R17, 0XFF           ; R17 = FF
OUT DDRB, R17           ; Make PORTB as output
LDI R16, 0X55           ; Load R16 with 0x55
BACK:
OUT PORTB, R16          ; Load PORTB = R16
CALL DELAY              ; Time delay
COM R16                 ; Complement R16
OUT PORTB, R16          ; Load PORTB = R16
LDI R20, 0X00
OUT DDRB, R20           ; Make PORTB as input
IN R16, PINB            ; Move from pins of PORTB to R16
OUT PORTA, R16          ; PORTA = PORTB
RJMP BACK
DELAY:
LDI R17, 0XF           ; Load R17 = 0F
LOOP:
NOP                     ; No operation
DEC R17
BRNE LOOP               ; Repeat until R17 becomes 0
RET

LED Blink (Assembly)

This program lights LEDs on PORTB one at a time with a delay between each.

.INCLUDE "M32DEF.INC"
LDI R16, HIGH(RAMEND)   ; Initialize the Stack Pointer
OUT SPH, R16
LDI R16, LOW(RAMEND)    ; Initialize the Stack Pointer
OUT SPL, R16
LDI R20, 0XFF
OUT DDRB, R20           ; Configure PORTB as output
SBI PORTB, 0            ; Set bit PB0
CALL DELAY              ; Delay before next one
SBI PORTB, 1            ; Turn ON PB1
CALL DELAY
SBI PORTB, 2            ; Turn ON PB2
CALL DELAY
SBI PORTB, 3            ; Turn ON PB3
CALL DELAY
SBI PORTB, 4            ; Turn ON PB4
CALL DELAY
SBI PORTB, 5            ; Turn ON PB5
CALL DELAY
SBI PORTB, 6            ; Turn ON PB6
CALL DELAY
SBI PORTB, 7            ; Turn ON PB7
CALL DELAY
HERE: RJMP HERE
DELAY:
LDI R17, 0X5           ; Load R17 = 05
LOOP:
NOP                     ; No operation
DEC R17
BRNE LOOP               ; Repeat until R17 becomes 0
RET

Shift and Rotate (Assembly)

This program demonstrates ROR, ROL, LSL, LSR, ASR, and SWAP instructions on a value stored in SRAM.

.INCLUDE "M32DEF.INC" ; Include the appropriate register definition
.ORG 00                ; Start at address 00
LDI R16, HIGH(RAMEND)  ; Load SPH
OUT SPH, R16
LDI R16, LOW(RAMEND)   ; Load SPL
OUT SPL, R16
LDI R20, 0XD5          ; Load R20 with 0xD5
STS 0x400, R20         ; Store R20 in memory location 0x400
LDS R22, 0X400         ; Load from memory location 0x400 to R22
ROR R22                ; Rotate R22 right through carry
STS 0x301, R22         ; Save the result in location 0x301
LDS R22, 0X400
ROL R22                ; Rotate R22 left through carry
STS 0x302, R22         ; Save the result in location 0x302
LDS R22, 0X400
LSL R22                ; Logical shift left
STS 0x303, R22         ; Save the result in location 0x303
LDS R22, 0X400
LSR R22                ; Logical shift right
STS 0x304, R22         ; Save the result in location 0x304
LDS R22, 0X400
ASR R22                ; Arithmetic shift right
STS 0x305, R22         ; Save the result in location 0x305
LDS R22, 0X400
SWAP R22               ; Swap nibbles
STS 0x306, R22         ; Save the result in location 0x306
OUT PORTA, R22
IN R23, PORTA
STAY: RJMP STAY        ; Stay here forever

Arithmetic Operations (Assembly)

This program performs addition, subtraction, and multiplication on two values and stores the results in SRAM.

.INCLUDE "M32DEF.INC" ; Include the appropriate register definition
.EQU SUM=0X300         ; SRAM location 0x300 for SUM
.EQU SUBB=0X301        ; SRAM location 0x301 for SUB
.EQU MULL=0X302        ; SRAM location 0x302 for MULL
.EQU MULH=0X303        ; SRAM location 0x303 for MULH
.ORG 00                ; Start at address 00
LDI R16, HIGH(RAMEND)  ; Load SPH
OUT SPH, R16
LDI R16, LOW(RAMEND)   ; Load SPL
OUT SPL, R16
LDI R20, 0X55          ; Load R20 with 0x55
LDI R21, 0XAA          ; Load R21 with 0xAA
STS 0x400, R20         ; Store R20 in memory location 0x400
STS 0x401, R21         ; Store R21 in memory location 0x401
ADD R20, R21           ; Add R21 to R20
STS SUM, R20           ; Save the SUM in location 0x300
LDS R16, 0X400         ; Load from memory location 0x400 to R16
LDS R17, 0X401         ; Load from memory location 0x401 to R17
SUB R16, R17           ; Subtract R17 from R16
STS SUBB, R16          ; Save the SUB in location 0x301
MUL R16, R17           ; Multiply R16 and R17
STS MULL, R0           ; Save the low byte of MUL in location 0x302
STS MULH, R16          ; Save the high byte in location 0x303
HERE: JMP HERE         ; Stay here forever

Related entries: