$29
Programming environment
For this assignment you must ensure your work executes correctly on Arduino boards in ECS 249. If you have installed AVR Studio on your own computer then you are welcome to do much of the programming work on your machine. If this is the case, however, then you must allow enough time to ensure your solutions work on the lab machines. If your submission fails to work on a lab machine, the fault is very rarely that the lab workstations. “It worked on my machine!” will be treated as the equivalent of “The dog ate my homework!”
Individual work
This assignment is to be completed by each individual student (i.e., no group work). Naturally you will want to discuss aspects of the problem with fellow students, and such discussion is encouraged. However, sharing of code fragments is strictly forbidden without the express written permission of the course instructor (Zastre). If you are still unsure regarding what is permitted or have other questions about what constitutes appropriate collaboration, please contact me as soon as possible. (Code- similarity analysis tools will be used to examine submitted work.) The URLs of significant code fragments you have found and used in your solution must be cited in comments just before where such code has been used.
Objectives of this assignment
Use multiple AVR 16-bit timers.
Write interrupt handlers for two timers.
Output program state onto the Arduino mega2560 board’s LCD display.
Practice more with writing code the implements (and using functions that depend upon) the parameter-passing mechanism based on stack frames.
Page 1 of 8
Interrupts, LCD panel
In this assignment you will use two features of the Arduino boards that may be new to you. Interrupts and interrupt handling will be introduced and discussed in lectures and labs. The handlers required for the assignment will not be long or complex, but they must work precisely. (Their execution will be triggered by several of the board’s timers.) The LCD panel will finally allow you to create board behavior that is richer than simply turning LEDs on and off; the labs during the week of March 12th will introduce you to the LCD panel.
A big challenge of this assignment, however, is that you are now moving into an area of programming where our debugger is of very little help. When handlers are not correctly coded or configured, the result is a mute board. Hence it is crucial you not only complete this assignment in the order of the four parts listed, but also build upon each of the completed parts by coding with successive projects folders. The idea here is that even if you struggled with part 4, your success with parts 1, 2 and 3 will be in those completed project folders for those parts (i.e., the code for those earlier parts can still run successfully).
A brief demonstration illustrating the behavior for each of the parts can be seen in this video:
https://youtu.be/dPHsScGNU9U
The assignment is in four parts, ordered from easier to more difficult, each part building upon the work of previous parts.
Write code to display a “heartbeat” on the LCD panel.
Write code for detecting if any button is pressed, maintaining a count of such presses, and outputting that count on the LCD panel as a button is pressed.
Write the code for detecting that a button is held down, and showing this by outputting a visible message on the LCD panel during that button press.
Write code for detecting if a button press is short or long (i.e., equivalent to a Morse code dot or dash) and displaying the dots and dashes on the LCD panel
(Note: For parts 2, 3, and 4 any button on the shield can be pressed except for the “RST” button.)
The ZIP file distributed with this assignment contains four directories, each
consisting of an AVR Studio 7 project. Directory a3part1/ is meant for part 1,
a3part2/ is for part 2, etc. In each directory are copies of code needed for using the
LCD display. Also in each directory is an A#3 starter file in which you are to write
your solution for that particular part of the assignment. (Note every directory starts out with exactly the same file contents.) The idea is that as you progress from part to
part, you can copy working code from one AVR Studio 7 project to the next. In that way, if a later part is not finished or does not work, it will not interfere with your working solution to an earlier part.
Part 1: Heartbeat
After completing this part, your Arduino board’s LCD display will appear to turn the symbols “<” on and off. For half a second the board will look like this:
and for the next half second the board will look like this:
and this behavior will repeat itself as long as the Arduino runs your program. (The “<” character is written in the cell at row 0 and column 14, while “” is written in the cell at row 0 and column 15.)
This description clearly indicates the need for one timer (i.e., one with a duration of 0.5 seconds), and for this we will use timer1. When the timer’s interrupt handler is executed, it must somehow toggle the state of the heartbeat (should the “<” be showing? should it not?). This state can be kept in the PULSE data memory location (i.e., this is defined towards the end of the a3part1.asm file provided to you) and it is up to you how to represent the state.
However, the interrupt handler for timer1 itself must never call the LCD routines ! In fact, interrupt handlers must have a minimal amount of code. So if the handler is not permitted1 to call lcd_gotoxy and lcd_putchar, how do we update the display?
The answer: Use another timer in main program but use it via the polling technique. This additional timer (timer3 in your program) runs for 50 milliseconds. When the polling loop detects timer3 has reached its TOP value (i.e., 50 ms has occurred), then the code for updating the LCD display can be executed. The latter code will determine whether “<” or “” or a space should appear in the area of the LCD display for the heartbeat based on its examination of the value stored in PULSE. Reminder: timer3 does not use an interrupt handler!
My use of the phrase “is not permitted” is a bit strong. In fact, the assembler will not forbid us from calling the LCD routines from an interrupt handler. However, once the program calls such routines from a handler, the whole program will simply stop working. In general it is a Very Bad Idea for an interrupt handler to call other routines, especially because we cannot always be guaranteed those routines themselves do not depend upon interrupts.
Part 2: Counting button presses
(This part will be based on your solution to the part 1. That is, the code within your a3part2.asm will use code you wrote for a3part1.asm). This semester in lab 4 you examined the way an Analog -to- Digital Converter (ADC) is used to read buttons on the Arduino board. The ADC obtains a value from 0 to 1023 from the buttons – if the value is greater than 900, then no button is being pushed. Code from lab 4 helped you explore how you might write code to detect which button is pressed; polling loops were an important part of your solutions.
Interrupts can help us here but not necessarily in the way we expect. It would be tempting to have a solution where a button press itself results in an interrupt. However, in practice this very rarely done because of an electrical phenomenon known bouncing.
Consider the figure below (found at http://bit.ly/2IdyYRg):
This is a screengrab from an oscilloscope (if you’ve never heard of these, visit http://bit.ly/1RXdkgw for a description) showing the electrical behavior of a button being pressed. The signal does not clearly go from voltage low to voltage high, but goes up and down quickly before settling to a high voltage; we say that the voltage bounces (i.e., like a rubber ball being bounced by a schoolchild on a playground). If we just used an interrupt to detect when a button caused the voltage to go high, then we would have many interrupts for a single button press. So in practice designers implement debouncing, usually in hardware. Our Arduino boards already perform some debouncing on the buttons.
What we will use is a timer to sample the value of the ADC at specific intervals (in our case, timer4 is set at 10 milliseconds, and this will be our interval). Every time the interrupt handler for timer4 is executed, its code must store the previous button-press value in BUTTON_PREVIOUS (i.e., see the .dseg at the end of the assembler file), and then determine the current button value (pressed? or not pressed?) and store that into BUTTON_CURRENT. And before the handler is finished, the it will examine BUTTON_PREVIOUS and BUTTON_CURRENT to determine if the button press has just started; if it so, BUTTON_COUNT will be incremented by one.
And what about our LDC display? When no button has yet been pressed, the LCD display will look something like that below (note the position on the display at which the count must appear):
(The heartbeat is grayed-out in the diagram indicate that it isn’t relevant to this particular discussion, but it will continue to be active when this part 2 code is completed.) When a button has been pressed, the display will look like:
The same loop used to update the heartbeat should be extended to update the count on the display (i.e., the loop which updates the LCD display every 50ms can itself be modified). One problem you will need to solve, however, is how to convert the 16-bit BUTTON_COUNT into its decimal representation as characters. I have suggested an approach in a file named hex_to_decimal.asm.pdf that you will find on conneX (in the “Lectures slides, other files” section within the “Other” folder). If you decide to use this approach in your solution, then please make sure to cite this in a comment. You can use the DISPLAY_TEXT location in data memory as a buffer in which to store – and from which to load – text characters.
Part 3: Displaying a button press
(This part will be based on code you have written for parts 1 and 2. That is, the code within your a3part3.asm will use code you wrote for a3part2.asm).
In the previous part of the assignment you wrote a handler that reads an ADC value (for the buttons) every 10 milliseconds. As part of its work, that handler assigns suitable values to BUTTON_PREVIOUS and BUTTON_CURRENT.
In this third part of the assignment, you do not need to write a new interrupt handler or modify an existing handler. Rather, you will extend the LCD update loop that already exists in your code such that:
when BUTTON_CURRENT indicates a button is currently pressed, the lower-left portion of the display will indicate this by six asterisks
when BUTTON_CURRENT indicates no button is pressed, the lower-right portion of the display will indicate this by keeping the lower-left portion of the display blank.
So if a button is pressed, the display will look something like:
and when no button is pressed, the asterisks will have disappeared. Throughout all this the heartbeat must continue to operate, and the button-press count must be updated. (In the figure above, the heartbeat and button count are greyed out to indicate their values are not important in this part of the assignment discussion.)
Part 4: Detecting dots and dashes
(This part will be based on the code you have written for the previous parts. That is, the code within your a3part4.asm will use code you wrote for a3part3.asm).
In assignment #2 you learned about Morse code and the way letters can be encoded in the form of short signals and long signals (i.e., dots and dashes). In the 19th century these dashes were electrical signals generated by the sender and heard as sounds by the receiver. The sender used a telegraph key like that shown below (from http://bit.ly/2FDR3t0):
A dot was literally a short tap on the key, while a dash was a longer press on the key. For our assignment, a dot corresponds to a short button press, while a dash is a longer button press. In practice “short” means “less than or equal to 200 milliseconds” while “longer” is “more than 200 milliseconds”. You can use work completed in part 2 to help detect the length of a button press.
Consider the figure below:
The top-most row represents the state of a physical button. (Any button may be pressed except for the RST button.) Where the line is thin, no button is pressed; where the line is thick, one of the buttons is pressed. The 10 -millisecond timer interrupts are shown on the second row, where a thick vertical line indicates the running of the interrupt handler. The third and fourth rows (for BUTTON_CURRENT and BUTTON_PREVIOUS) represent values stored in these memory locations; these could be 0 and 1 (i.e., 0 is the line when it is low, 1 is the line when it is high). The last row represents the number of interrupts for which a button has been pressed (BUTTON_LENGTH). Three points in time are also shown:
At point A, the pushed button has just been recognized (i.e., in the previous
interrupt, the button was not pushed). Therefore we can reset BUTTON_LENGTH to 1.
At point B, the button is still being pressed, and BUTTON_LENGTH continues to increase.
At point C, a button release has just been recognized (i.e, in the previous interrupt, a button was indeed pushed down, but now no button is being pushed). At this point we can not only stop incrementing BUTTON_LENGTH, but we can also determine whether or not the button push was long enough to have been a dot or a dash. Since this button press is 70 milliseconds long, it is short enough to be a dot.
In part 4 we will therefore want to modify and extend the handler we first wrote in part 2. This handler is the best place to not only maintain BUTTON_LENGTH but also decide on dots and dashes and record the result as characters (i.e., ‘.’ or a ‘-’) in the BUTTON_PATTERN buffer.
The LCD update loop can now output the BUTTON_PATTERN on the upper-left portion of the display, where a “dash dot dash” looks like:
Up to ten dot/dashes should be shown on the LCD display. If we exceed this number of button presses, then no more dots/dashes will be added, but the rest of the program should continue to work, i.e., button presses will still increase the count; button presses will still be displayed as asterisks in the lower-left of the display; the heartbeat will continue.
What you must submit
Your four completed parts: a3part1.asm, a3part2.asm, a3part3.asm and
a3part4.asm. Do not change the name of these files! Do not submit the LCD files. Submit only the .asm files!
Page 7 of 8
Your work must use the the provided skeleton files. Any other kinds of solutions will not be accepted.
Evaluation
4 marks: Solution for part 1
8 marks: solution for part 2
3 marks: solution for part 3
5 marks: solution for part 4
Therefore the total mark for this assignment is 20.
Some of the evaluation above will also take into account whether or not submitted code is properly formatted (i.e., indenting and commenting are suitably used), and the file correctly named.
Unlike other assignments, A#3 will be evaluated via a code demo. That is, each
student will meet with a member of the teaching team, who will have access to
the student’s submitted code and will ask that student questions about their code. Instructions on how to sign up for a demo will be given sometime during the week of July 15th.
Page 8 of 8