Categories
8051-8052 Assembly Language Examples

8051 Assembly Frequency Counter Example

Today we are going to make a very simple 8051 Assembly code for a frequency counter example. We are going to make the example very simple and to the point just the way we normally do in our previous examples. Today’s focus is to demonstrate the very simple frequency counting algorithm implementation in 8051 assembly language. With this algorithm we are going to take a simple delay of 1 second using the 8051 timers. Meanwhile we initiate the external interrupt to count the pulses on External Interrupt pin of the 8051 microcontrollers. The External interrupt will count the number of pulses until the internal timer complete it’s one second delay. After the delay is complete the number of counts on external interrupt is our actual frequency.

For the sake of the simplicity, we are going to display the result on the serial terminal. We do not want to make the code goes extra big as the code is in Assembly language. We will output the frequency on the serial terminal. We are going to use the timer @2400 baud rate at the 12Mhz crystal. The simulation is done on the proteus 8 and the microcontroller used in the proteus is AT89c2051 to keep things simple.

8051 frequency counter proteus simulation

What is a Frequency Counter?

A frequency counter is an electronic instrument that measures the frequency of an input signal. The frequency is defined as the number of occurrences of a repeating event per unit of time. In the context of this code, the frequency counter counts the number of pulses or cycles of a signal within a specified time frame (1 second in this case) to determine its frequency.

Frequency Counter Algorithm

The 8051 frequency counter algorithm initializes the microcontroller’s timers and serial communication, then enters a loop where it repeatedly clears the counter, enables interrupts, waits for a specified time (one second), disables interrupts, and transmits the counted pulses. The external interrupt service routine (ISR) increments the counter digits upon each pulse and handles the overflow by advancing to the next digit. The half-second delay subroutine creates precise timing using Timer 0, while the transmission subroutine converts the counter digits to ASCII and sends them serially. This process effectively measures the frequency of input pulses by counting them over a fixed time interval and sending the result for display or further processing.

Calculation of Limits

Given the above setup:

  1. Maximum Count: The maximum count before overflow is 9999.
  2. Time Frame: The code counts pulses in a 1-second interval.

Therefore, the frequency measurement limit is:

  • Maximum Measurable Frequency: 9999 pulses per second (or 9999 Hz).
  • Minimum Measurable Frequency: 1 pulse per second (or 1 Hz).

In practical terms, the actual measurement limits may be slightly lower due to the overhead of executing instructions and handling interrupts. The effective frequency range for accurate measurement will be somewhat less than the theoretical maximum of 9999 Hz.

8051 Assembly code for frequency counter

Let’s dive into the actual code and try to understand the working of the code step by step. Here is the initial macro definitions of the code.

LEDS        EQU     P0

DIGIT1      EQU     30H
DIGIT2      EQU     31H
DIGIT3      EQU     32H
DIGIT4      EQU     33H

ORG         0
LJMP        MAIN

ORG         3H  ;EX0 VECTOR
LJMP        EX0_ISR

LEDS is defined as P0, the port we will use for LEDs. DIGIT1, DIGIT2, DIGIT3, and DIGIT4 are memory locations (30H, 31H, 32H, 33H) where we will store the digits of the counter.ORG 0 and LJMP MAIN set the starting point of our program.ORG 3H and LJMP EX0_ISR define the interrupt vector for external interrupt 0 (EX0).

MAIN:
    ;====== SERIAL INIT =============================
    MOV     TMOD,#22H    ;TIMER 1 , MODE 2
    MOV     TH1,#-13     ;2400 BAUD RATE @ 12MHZ
    MOV     TH0,#-200    ;PRELOAD VALUE
    SETB    TR0
    MOV     SCON,#52H    ;8-BIT , 1 STOP , REN ENABLED
    SETB    TR1    ;START TIMER 1
    SETB    IT0    ;EDGE TRIGGER
    MOV     IE,#10000001B    ;ENABLE EX0
    CLR     IE.7
    ;========== ======================================
Code language: PHP (php)
  • TMOD is set to 22H to configure Timer 1 in mode
  • TH1 is set to -13 to get a baud rate of 2400 at a 12MHz clock.
  • TH0 is preloaded with -200 for timing purposes.
  • TR0 and TR1 are set to start Timer 0 and Timer
  • SCON is set to 52H to configure serial communication.
  • IT0 is set to enable edge-triggered interrupts.
  • IE is set to 10000001B to enable external interrupt 0 (EX0).
AGAIN:
    ACALL   CLEAR_COUNTER
    SETB    IE.7
    ACALL   HALF_SEC
    ACALL   HALF_SEC
    CLR     IE.7
    ACALL   TRANS_DATA
    SJMP    AGAIN
Code language: CSS (css)

The AGAIN loop clears the counter, enables interrupts, waits for half a second twice (total 1 second), disables interrupts, and transmits the counter data. CLEAR_COUNTER subroutine sets the counter digits to zero. HALF_SEC subroutine waits for half a second. TRANS_DATA subroutine transmits the counter digits serially.

EX0_ISR:
    INC     DIGIT1
    MOV     A,#10
    CJNE    A,DIGIT1,EX0_EXIT
    MOV     DIGIT1,#0

    INC     DIGIT2
    CJNE    A,DIGIT2,EX0_EXIT
    MOV     DIGIT2,#0

    INC     DIGIT3
    CJNE    A,DIGIT3,EX0_EXIT
    MOV     DIGIT3,#0

    INC     DIGIT4
    CJNE    A,DIGIT4,EX0_EXIT
    MOV     DIGIT4,#0

EX0_EXIT:
    RETI
Code language: CSS (css)

The EX0_ISR is the interrupt service routine for external interrupt 0. It increments DIGIT1 and checks if it reaches 10. If DIGIT1 reaches 10, it resets DIGIT1 to 0 and increments DIGIT2. The process repeats for DIGIT3 and DIGIT4.

HALF_SEC:
    MOV     R6,#25
L02:    MOV     R7,#100
L01:    JNB     TF0,$
    CLR     TF0
    DJNZ    R7,L01
    DJNZ    R6,L02
    RET
Code language: PHP (php)

The HALF_SEC subroutine uses Timer 0 to create a delay of half a second.

TRANS_DATA:
    MOV     A,DIGIT4
    ADD     A,#48
    ACALL   TX
    MOV     A,DIGIT3
    ADD     A,#48
    ACALL   TX
    MOV     A,DIGIT2
    ADD     A,#48
    ACALL   TX
    MOV     A,DIGIT1
    ADD     A,#48
    ACALL   TX
    MOV     A,#10
    ACALL   TX
    MOV     A,#13
    ACALL   TX
    RET
Code language: CSS (css)

The TRANS_DATA subroutine converts the counter digits to ASCII and transmits them serially.

TX:
    JNB     TI,$
    CLR     TI
    MOV     SBUF,A
    RET

The TX subroutine waits for the transmit interrupt flag (TI) to clear and then loads the accumulator (A) into the serial buffer (SBUF) for transmission.

Conclusion

This 8051 assembly code example demonstrates a simple frequency counter. It counts the number of pulses within a second and transmits the result serially. Understanding each part of the code helps in grasping the functionality of the 8051 microcontroller and assembly programming.

I hope you find this explanation helpful. Keep experimenting and learning. Happy coding!

By Abdul Rehman

My name is Abdul Rehman and I love to do Reasearch in Embedded Systems, Artificial Intelligence, Computer Vision and Engineering related fields. With 10+ years of experience in Research and Development field in Embedded systems I touched lot of technologies including Web development, and Mobile Application development. Now with the help of Social Presence, I like to share my knowledge and to document everything I learned and still learning.

One reply on “8051 Assembly Frequency Counter Example”

I would really like to expand on this code. But when I went to compile it I realised there is a chunk missing. The CLEAR_COUNTER sub-routine. Could you correct the code and repost so that I can go ahead with it?
Thank you

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.