Engineers Garage

  • Projects and Tutorials
    • Electronic Projects
      • 8051
      • Arduino
      • ARM
      • AVR
      • PIC
      • Raspberry pi
      • STM32
    • Tutorials
    • Circuit Design
    • Project Videos
    • Components
  • Articles
    • Tech Articles
    • Insight
    • Invention Stories
    • How to
    • What Is
  • News
    • Electronic Products News
    • DIY Reviews
    • Guest Post
  • Forums
    • EDABoard.com
    • Electro-Tech-Online
    • EG Forum Archive
  • Digi-Key Store
    • Cables, Wires
    • Connectors, Interconnect
    • Discrete
    • Electromechanical
    • Embedded Computers
    • Enclosures, Hardware, Office
    • Integrated Circuits (ICs)
    • Isolators
    • LED/Optoelectronics
    • Passive
    • Power, Circuit Protection
    • Programmers
    • RF, Wireless
    • Semiconductors
    • Sensors, Transducers
    • Test Products
    • Tools
  • EE Resources
    • DesignFast
    • LEAP Awards
    • Oscilloscope Product Finder
    • White Papers
    • Webinars
  • EE Learning Center
  • Women in Engineering

Threading and Timers in Atmega328p

By Varun Kumar

Requirements:

1.Bread Board
 
2.Arduino Uno with Atmega328p
 
3.LCD JHD162A
 
4.Jumper Wires
 

Summary:

My motivation for this project was to minimize the usage of functions such as _delay_ms(), _delay_us() and their derivatives with some exceptions, like delays to control the LCD.
 
Delay pauses the whole program, so if one is using  it for 10 seconds everything will pause  and nothing can be done within that time duration. Although if we use interrupt, there is a separate hardware known as timer which counts the clock ticks and generates interrupt, after specified number of clock ticks have been counted.
 
In this project I’m using LCD JHD162A which has 2 rows and 16 columns.
 
I built a task scheduler which switches between two threads in an interval of 5.5 seconds.
 
First task (thread 1) is to increment an integer value displayed on first row of LCD every second.
 
Second task (thread 2) is to decrement an integer value displayed on second row in every two seconds.
 
Both the integers start from Zero.
 
 
Example:
 
1) t1 is running and increments the integer in the first row every second
 
2) After 5.5 seconds, t1 stops and t2 starts decrementing the integer in the second row in every 2 seconds
 
3) After 5.5 seconds, stop t2, start t1, go back to 1)

Timing Diagram showing Multiple Threads running on Arduino

Fig. 1: Timing Diagram showing Multiple Threads running on Arduino

A thread is a lightweight process that is executed independently. But due to hardware limitation let’s assume that a thread is simply a function manipulating one of the integers mentioned above. Since Atmega328P is equipped with only one ALU, either thread1 or thread2 is able to run. They can never run at the same time.

For this project, I have used Arduino equipped with atmega328p. You can learn about port mapping at  Arduino Port Manipulation Arduino Port Manipulation which refers to atmega168. Although atmega328 is the newer chip, both follow the same pin out. 

For more detailed information and references you can checkout  the Atmega328p documentation

Description:

 

 

Image showing Arduino interfaced character LCD displaying different values from two threads

 Fig. 2: Image showing Arduino interfaced character LCD displaying different values from two threads

How I am uploading code into arduino:

f = <source_code’s_file_name>
avr-gcc -g -mmcu=atmega328p -Wall -Os $(f).c -o $(f).elf
avr-objcopy -j .text -j .data -O ihex $(f).elf $(f).hex
sudo avrdude -F  -V -c arduino -p m328  -P /dev/ttyUSB* -b 57600 -e -U flash:w:$(f).hex
 
Just type these four commands, in the same order, in your terminal and remember to put the source code’s filename in variable “f”. These commands are for Linux users only.
 
First command stores the filename in variable “f”, second command converts source code to .elf file, third command converts .elf file to .hex file which can be uploaded on atmega328p,  and fourth command uploads  the .hex file.
 

Intro to Atmega328p and it’s timers:

 

 

Image of Arduino interfaced LCD Circuit used for testing built-in timers

Fig. 3: Image of Arduino interfaced LCD Circuit used for testing builtin timers

 
Atmega328p is equipped  with timer0, timer1, timer2; out of which two are 8-bits and one is 16-bit. Maximum number of clock ticks that a timer can count depends on the size of the register.
Timer 0 and timer 2 use two different 8-bit registers, whereas timer 1 uses a 16-bit register.
An 8-bit register can count up to 2^8 = 256(0 to 255). Similarly 16-bit register can count up to 2^16 = 65536(0 to 65535). With the available resources, I can generate an interrupt at every (65536/clock freq) 65536/1,60,00,000 = 4.0959375ms.
 
To increase this maximum time, every timer is given a set of pre-scalars, which are in power of 2’s. A  pre-scalar divides the clock freq by that number. In 16-bit timer, maximum pre-scalar available is 1024, therefore now I can generate an interrupt
 
(65536/(clk freq/1024))  65536*1024/1,60,00,000 = 4.19424 sec
 
Same goes for 8-bit timer.
A simple formula
Count = (Required Delay * Clock Frequency)/Prescaler – 1
 
 

Little bit of description about timer being used:

 

 

Bit Values of TCCR1B Register in Arduino Uno

Fig. 4: Bit Values of TCCR1B Register in Arduino Uno

 
• Bit 7 – ICNC1: Input Capture Noise Canceller
Setting this bit (to one) activates the Input Capture Noise Canceller after which the input from the Input Capture pin (ICP1) is filtered.
 
• Bit 6 – ICES1: Input Capture Edge Select
This bit selects which edge on the Input Capture pin (ICP1) is used to trigger a capture event.
 
 Bit 5 – Reserved Bit
This bit is reserved for future use. For ensuring compatibility with future devices, this bit must be written to zero when TCCR1B is written.
 
• Bit 4:3 – WGM13:2: Waveform Generation Mode
See TCCR1A Register description.
 
• Bit 2:0 – CS12:0: Clock Select
 
The three Clock Select bits select the clock source to be used by the Timer/Counter

 

 

Bit Values of TCCR2B Register in Arduino Uno

Fig. 5: Bit Values of TCCR2B Register in Arduino Uno

• Bit 7, 6 – Res: Reserved Bits
These bits are unused bits in the ATmega48PA/88PA/168PA/328P, and will always be read as zero.
 
• Bit 5 – ICIE1: Timer/Counter1, Input Capture Interrupt Enable
When this bit is written to one, and the I-flag in the Status Register is set (interrupts globally enabled), the Timer/Counter1 Input Capture interrupt is enabled.
 
• Bit 4, 3 – Res: Reserved Bits
These bits are unused bits in the ATmega48PA/88PA/168PA/328P, and will always be read as zero.
 
• Bit 2 – OCIE1B: Timer/Counter1, Output Compare B Match Interrupt Enable
When this bit is written to one, and the I-flag in the Status Register is set (interrupts globally enabled), the Timer/Counter1 Output Compare B Match interrupt is enabled. The corresponding Interrupt Vector is executed when the OCF1B Flag, located inTIFR1, is set.
 
• Bit 1 – OCIE1A: Timer/Counter1, Output Compare A Match Interrupt Enable
When this bit is written to one, and the I-flag in the Status Register is set (interrupts globally enabled), the Timer/Counter1 Output Compare A Match interrupt is enabled. The corresponding Interrupt Vector is executed when the OCF1A Flag, located in TIFR1, is set.
 
• Bit 0 – TOIE1: Timer/Counter1, Overflow Interrupt Enable
When this bit is written to one, and the I-flag in the Status Register is set (interrupts globally enabled), the Timer/Counter1 Overflow interrupt is enabled.
 
Description about the task:
● What’s my task
My task is to simulate threading. I designed two tasks- one in which a counter increments after every second and another in which counter decrements after every two seconds.
Both the tasks are switched every 5.5 seconds and previous state of the task is preserved.
 
â—Ź Timers relation
In this project I’m using timer1, which is a 16 bit timer therefore the maximum count it can go for is 2^16 = 65536.
 
Minimum value of time that I want is 0.5 seconds.
 
My Arduino is equipped with a frequency oscillator, having freq. 1,60,00,000Hz.
 
Therefore to generate an interrupt at every 0.5 seconds
Count = (0.5 * 1,60,00,000)/1 – 1 = 79,99,999
 
I need a register capable of counting 79,99,999 (which is not available).
 
So I decided to use a pre-scalar with a value of 256. Now to generate an interrupt at every 0.5 seconds
Count = (0.5 * 1,60,00,000)/256 – 1 = 31249
 
I need a register capable of counting 31249(16 bit timer with a  pre-scalar of 256 can easily do that).
 
Therefore, after every 0.5 seconds an interrupt is generated
 
â—Ź logic
Both the threads follow a pattern which can be simulated by generating an interrupt of 0.5 seconds. Thread 1 repeats itself after every 22 seconds (including the time of other thread which will be executed in between) and thread 2 repeats itself after every 77 seconds (including the time of other thread which will be executed in between).
 
Therefore, if a variable is  initialized to keep track on the pattern for a specific thread, it can be reset  to zero after every complete cycle of that specific thread.
As seen below, thread 1 repeats its pattern after two iterations.
 

 

 

Table showing Interrupts for Thread 1

Fig. 6: Table showing Interrupts for Thread 1

And thread 2 repeats its pattern after four iterations.

 

 

Table showing Interrupts for Thread 2

Fig. 7: Table showing Interrupts for Thread 2

Description of Source Code:

I used my own library lcd.h to display integer value of thread 1 and thread 2 on 16×2 LCD.
 
First I initialised timer() function and defined relevant variables globally, then in main() function I declared pin 4,5,6,7,8,9 as output and I initialized lcd via start() allowed global interrupt via sei() and initialised timer via timer().
 
After initializing and defining necessary things I displayed 0 on both rows of lcd, and started an infinite loop.
 
Algorithm that I’m using is in ISR() block, which is executed  in every 0.5 second interrupt.
 
For more details please refer to the source code, it has been explained along with the comments. 

 

Project Source Code

###


 

/***************************************  Varun Kumar  ***************************************/

#define F_CPU 16000000UL

#include<avr/io.h>

#include<util/delay.h>

#include<stdlib.h>

#include<string.h>

#include<avr/interrupt.h>

#include"lcd.h"

 

void timer();

int in_counter=0;  // keeps track on both the threads and resets when one complete cycle is over

int in_counter1=0; // keeps track on one cycle of thread1 and resets after one cycle of thread1 is over

int in_counter2=0; // keeps track on one cycle of thread2 and resets after one cycle of thread2 is over

 

int count1=0;

int count2=0;

 

int main(void)

{

             DDRB = 0x03;              // Declare Pin 8,9 as output

    DDRD = 0xF0;          // Declare Pin 4,5,6,7 as output

   

    _delay_ms(500);

    start();          // Initialises LCD

   

    sei();            // Allows interrupt

    timer();                      // Initialises Timer

   

    command(0x80);       // moves the cursor to (1,1)

    Send_A_String("0");   // Initialize the LCD by writing Zero at (1,1)

    command(0xC0);       // moves the cursor to (2,1)

    Send_A_String("0");   // Initialize the LCD by writing Zero at (2,1)

 

    while(1)

             {}

    return 0;

}

 

void timer()

{

    OCR1A = 31249;                   // One tick is used to return to zero

    TCCR1B |= (1 << CS02);        // prescalar 256

    TCCR1B |= (1 << WGM12);   // turns on CTC mode for timer1

   

    TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt

    TCNT1 = 0;                // 16 bit register

}

 

/********************************** ISR ******************************/

ISR(TIMER1_COMPA_vect)

{

 

    in_counter++;

   

    /************* Thread1 Starts **************/

    if(in_counter<=11)

    {

             in_counter1++;

             if(in_counter1%2==0)

                         {

                                     count1++;

                                     command(0x80);

                         Send_An_Integer(count1);

             }

             if(in_counter1==22){in_counter1=0;}  // One cycle of thread1 is over when in_counter1 equals 22               

    }

    /*************** Thread1 Ends **************/

   

   

    /************* Thread2 Starts **************/

    if(in_counter>11)

    {

             in_counter2++;

             if(in_counter2%4==0)

                         {

                         count2--;

                         command(0xC0);

                         Send_An_Integer(count2);

             }

             if(in_counter2==44){in_counter2=0;}  // One cycle of thread2 is over when in_counter2 equals 44

    }

    /*************** Thread2 Ends **************/        

   

   

    if(in_counter==22)

    {

             in_counter=0;                           // One complete cycle is over when in_counter equals 22

    }        

}

/*********************************************** END *******************************************************/

###

 


Circuit Diagrams

Circuit-Diagram-Arduino-Character-LCD

Project Video


Filed Under: Electronic Projects

 

Questions related to this article?
👉Ask and discuss on EDAboard.com and Electro-Tech-Online.com forums.



Tell Us What You Think!! Cancel reply

You must be logged in to post a comment.

HAVE A QUESTION?

Have a technical question about an article or other engineering questions? Check out our engineering forums EDABoard.com and Electro-Tech-Online.com where you can get those questions asked and answered by your peers!


Featured Tutorials

  • Designing Gate Driver Circuit and Switching Mechanism for Modified Sine Wave Inverter – (Part 9/17)
  • Completing Modified Sine Wave Inverter Design with Full Bridge Circuit and Step Up Transformer – (Part 10/17)
  • Designing an Offline UPS – Part (12 /17)
  • How to reduce Switching Time of a Relay – (Part 15/17)
  • Testing MOSFET – (Part 16/17)
  • Driving High Side MOSFET using Bootstrap Circuitry – (Part 17/17)

Stay Up To Date

Newsletter Signup

Sign up and receive our weekly newsletter for latest Tech articles, Electronics Projects, Tutorial series and other insightful tech content.

EE Training Center Classrooms

EE Classrooms

Recent Articles

  • Infineon offers DC-DC controller for full LED headlamps without a microcontroller
  • Vishay launches new high-precision, thin-film wraparound chip resistor
  • STMicroelectronics’ common-mode filters ensure signal integrity in serial interfaces
  • Renesas’ RA Family microcontrollers earn CAVP certification for cryptographic algorithms
  • MicroPython: Serial data communication in ESP8266 and ESP32 using UART

Most Popular

5G 555 timer circuit 8051 ai Arduino atmega16 automotive avr dc motor display Electronic Part Electronic Parts Fujitsu ic infineontechnologies integratedcircuit Intel IoT ir lcd ldr led maximintegratedproducts microchip microchiptechnology Microchip Technology microcontroller microcontrollers mosfet motor powermanagement Raspberry Pi remote renesaselectronics Research robot samsung semiconductor sensor software STMicroelectronics switch Technology vishayintertechnology wireless

RSS EDABOARD.com Discussions

  • PS4 chip replacement not going to plan
  • Voltage reference level - how to choose?
  • Boost converter, 3W...shielded or unshielded inductor?
  • What is the function of the long stub?
  • HV Relays - Power Capacity

RSS Electro-Tech-Online.com Discussions

  • Dog Scarer
  • Unusual phenomenon
  • Audio equalizer
  • Background of Members Here
  • Adding Current Limit Feature to a Buck Converter
Engineers Garage
  • Analog IC TIps
  • Connector Tips
  • DesignFast
  • EDABoard Forums
  • EE World Online
  • Electro-Tech-Online Forums
  • Microcontroller Tips
  • Power Electronic Tips
  • Sensor Tips
  • Test and Measurement Tips
  • 5G Technology World
  • About Us
  • Contact Us
  • Advertise

Copyright © 2022 WTWH Media LLC. All Rights Reserved. The material on this site may not be reproduced, distributed, transmitted, cached or otherwise used, except with the prior written permission of WTWH Media
Privacy Policy | Advertising | About Us

Search Engineers Garage

  • Projects and Tutorials
    • Electronic Projects
      • 8051
      • Arduino
      • ARM
      • AVR
      • PIC
      • Raspberry pi
      • STM32
    • Tutorials
    • Circuit Design
    • Project Videos
    • Components
  • Articles
    • Tech Articles
    • Insight
    • Invention Stories
    • How to
    • What Is
  • News
    • Electronic Products News
    • DIY Reviews
    • Guest Post
  • Forums
    • EDABoard.com
    • Electro-Tech-Online
    • EG Forum Archive
  • Digi-Key Store
    • Cables, Wires
    • Connectors, Interconnect
    • Discrete
    • Electromechanical
    • Embedded Computers
    • Enclosures, Hardware, Office
    • Integrated Circuits (ICs)
    • Isolators
    • LED/Optoelectronics
    • Passive
    • Power, Circuit Protection
    • Programmers
    • RF, Wireless
    • Semiconductors
    • Sensors, Transducers
    • Test Products
    • Tools
  • EE Resources
    • DesignFast
    • LEAP Awards
    • Oscilloscope Product Finder
    • White Papers
    • Webinars
  • EE Learning Center
  • Women in Engineering