Pre-Lab 4A: Polling
Table of Contents
- The ATmega328P is equipped with two 8-bit timer/counters and one 16-bit counter. These Timer/Counters let you…
- Turn on or turn off an external device at a programmed time.
- Generate a precision output signal (period, duty cycle, frequency). For example, generate a complex digital waveform with varying pulse width to control the speed of a DC motor
- Measure the characteristics (period, duty cycle, frequency) of an incoming digital signal
- Count external events
Nomenclature
Frequency
The number of times a particular event repeats within a 1-s period. The unit of frequency is Hertz, or cycles per second. For example, a sinusoidal signal with a 60-Hz frequency means that a full cycle of a sinusoidal signal repeats itself 60 times each second, or every 16.67 ms. For the digital waveform shown, the frequency is 2 Hz.
Period
The flip side of a frequency is a period. If an event occurs with a rate of 2 Hz, the period of that event is 500 ms. To find a period, given a frequency, or vice versa, we simply need to remember their inverse relationship, where F and T represent a frequency and the corresponding period, respectively.
Duty Cycle
In many applications, periodic pulses are used as control signals. A good example is the use of a periodic pulse to control a servo motor. To control the direction and sometimes the speed of a motor, a periodic pulse signal with a changing duty cycle over time is used.
Duty cycle is defined as the percentage of one period a signal is ON. The periodic pulse signal shown in the Figure 1 is ON for 50% of the signal period and off for the rest of the period. Therefore, we call the signal in a periodic pulse signal with a 50% duty cycle. This special case is also called a square wave.
Timer 1 – Normal Mode Operation (default)
In lab you will be using the timer subsystems of the ATmega328P to generate a square wave with a frequency of 2 Hz.
We will be working with 16-bit Timer/Counter 1 due to the large delays (250 msec) needed to generate our 2 Hz frequency square wave. To keep things as simple as possible we will be operating Timer 1 in its default Normal mode. In this mode the counting direction is always up (incrementing). The counter overruns when it passes its maximum 16-bit value (MAX = 0xFFFF) and then restarts from the BOTTOM (0x0000). In normal operation the Timer/Counter Overflow Flag (TOV1) will be set in the same timer clock cycle as the TCNT1 becomes zero.
The TOV1 Flag in this case behaves like a 17th bit, except that it is only set, not cleared.
Maximum Delay
So can TCNT1 generate the 250 ms delay required to generate our 2 Hz square wave? To answer that question we will need to determine the maximum delay possible. Assuming a system clock frequency of 16.000 MHz and a prescale divisor of 64, the largest time delay possible is achieved by setting both TCNT1H and TCNT1L to zero, which results in the overflow flag TOV1 flag being set after 216 = 65,536 tics of the Timer/Counter1 clock.
fT1 = fTclk_I/O/64, given fTclk_I/O = fclk then fT1 = 16.000 MHz / 64 = 250 KHz
and therefore T1max = 65,536 tics / 250 KHz = 262.14 msec
Clearly, Timer 1 can generate a delay of 250 msec. Our next step is to calculate the TCNT1 load value needed to generate a 250 ms delay.
Step to Calculate Timer Load Value (Normal Mode)
To generate a 250 msec delay assuming a clock frequency of 16 MHz and a prescale divisor of 64.
Variables
tclk_T1 – Period of clock input to Timer/Counter1
fclk – AVR system clock frequency
Solution
- Divide desired time delay by tclk_T1 where tclk_T1 = 64/fclk = 64 / 16.000 MHz = 4 µsec
250msec / 4 µs = 62,500 - Subtract 65,536 – step 1
65,536 – 62,500 = 3,036 - Convert step 2 to hex.
3,036 = 0x0BDC
For our example TCNT1H = 0x0B and TCNT1L = 0xDC
Question 1 What values would need to be loaded into TCNT1H and TCNT1L to generate a 38 ms delay with a system clock frequency of 10.000 MHz and a prescale divisor of 8 (show your work)?
Initialization
Applying what we learned lets setup our timer to set overflow flag TOV1 after 250 ms.
ldi r16,0x0B // load value high byte (Sect 15.2-15.3)
sts TCNT1H,r16
ldi r16,0xDC // load value low byte
sts TCNT1L,r16
In the next step we simultaneously turn on the clock to Timer 1, and apply a prescaler of 64, as defined in Table 7.10: Timer1 Clock Select Bit Description in your textbook.
; Initialize Timer/Counter1
ldi r16,(1<<cs11)|(1<<cs10) // prescale of 64 Sect 15.11.2
sts TCCR1B,r16 // Table 15-5 Clock Select Bit Description
The C++ bit-wise left shift operator
The C++ bit-wise left shift operator << is used to move a one (1) into a specified bit location within a byte. In the first half of the expression an 8-bit value is built with the CS1 bit 1 set to 1 ( 0b00000010). In the second half of the expression an 8-bit value is built with the CS1 bit 0 set to 1 ( 0b00000001). The C++ bit-wise or operator | is used to combine these two bytes to form the byte to be stored in register r16 (0b00000011).
Question 2 The first two lines of code set both CS11 and CS10 bits to 1 in Timer 1 register TCCR1B, while setting all other bits to zero. What hexadecimal value is saved in TCCR1B? Register TCCR1B is shown in Figure 9-18 TCCR1B (Timer 1 Control) Register of your textbook. If you do not have the textbook you can also find this register in Section 15.11.2 TCCR1B – Timer/Counter1 Control Register B in the ATmega328P_doc8161 pdf file found in the reference folder on my website. Once you find register TCCR1B locate bits CS11 and CS10 and set these to one (1), set all other bits to zero (0). Convert this binary number to hexadecimal and you have the answer.
Polling
At this point the timer has been initialized so it will set the overflow flag TOV1 in the TIFR1 register after 250 ms, and the timer’s clock has been started.
Polling the overflow flag TOV1 is a very simple way to keep track of time. Specifically, with a polling routine we loop until the overflow flag bits is set (TOV1 = 1), once this event occurs, we know the desired time has elapsed.
Question 3 Write a small assembly subroutine named delay to poll the TOVF1 flag. When the flag is set (TOV1 = 1), clear theTOV1 flag by writing a 1 (sbi TIFR1, TOV1), and reset the timer value (TCNT1H:TCNT1L = 0x0BDC). You may think I just made a mistake by saying write a 1 to the TOV1 flag to clear it – but this is in fact how you clear a flag within the ATmega architecture. Do not ask me why.
Question 4 You have now written a subroutine to generate a delay of 250 ms, now let’s use that delay to toggle a byte in SRAM at a frequency of 2 Hz. I am going to do this by introducing a new variable named next_state whose value toggles between all 0s and all 1s. Complete my code to accomplish this goal. You may assume that next_state is initially equal to zero.
; — 250 msec —-
rcall Delay
; — next_state —
lds r20, next_state // toggle next_state
ldi r16, 0x
___ r20, r16
sts next_state, r20
Question 5 In this lab you will be generating a 2-state FSM. You have now written a subroutine to generate a delay of 250 ms and can toggle variable next_state at a frequency of 2 Hz, but how will you know it really works?
Over the next few labs you will be upgrading your FSM from 2 to 3 states and finally to 4 states. At the present time the LEDs are no longer required, so we are going to use the most significant 2 LEDs to display the current state of the FSM (the value in register r20).
Write a short program 4 to 5 line program to move bits 1 and 0 in register r20, to discrete LEDs (spiLEDS) bits 7 and 6.
What Should I Turn In?
Turn in the following material three pages. Make sure all your original work is in your Lab Notebook. All written material must be typed or neatly done in ink. Once again please do not copy.
Page
- Title page with the pre-lab number, your name and picture, today’s date, and the day your lab meets.
- The problem statements (remove explanatory text) and solutions to all pre-lab questions. Circle and/or highlight your answers. Make sure all your original work is located in your lab notebook.
- Your delay subroutine. This should be done in AVR Studio and assemble without errors.