This lab explored the process of planning, designing, building, and programming a computer system with a variety of memory and I/O devices. The goal is to serve as a manifestation of concepts taught in lecture such as memory organization and types of electronic communication. At the end of this lab, a full computer system was demonstrated with all of the composite functionality of each of the previous labs given in the course.
This report is divided into logical sections. The Objective provides a holistic overview of the lab, including several key deliverables. The Introduction provides background information, theories, or specialized hardware and tools required to understand the lab procedures. The Hardware Discussion reviews both the schematic and generated circuit board, as well as describing relationships within. The Software Discussion discusses each piece of software functionality provided by the system, as well as explaining program flow. The Problem Discussion provides a look into several problems encountered during lab, and how they were fixed or worked around. The Conclusion has some final thoughts regarding the entire project. Finally, the Appendix contains all code and other artifacts required to reproduce the lab.
The desired outcome of this lab was a microprocessor computer system using the 8051 platform to run RAM functions defined in Labs 1-4. The system would take user input via two methods: directly via the attached keypad, and serially from the attached ESP8266’s web server. The output includes a high-quality LCD display as well as a 7-segment display. Each of the success criterion are enumerated specifically below (drawn from lab handouts):
The microprocessor platform used in the design shall be the AT89C51RC.
The microprocessor shall use a memory decoding scheme to interface with 64K of ROM as well as 64K of RAM.
The microprocessor shall communicate with several I/O devices:
16 button matrix keypad
7-segment common cathode display
2.8" TFT LCD
Real-time clock
Analog to digital converter
ESP-8266
The code must implement and support the following RAM functionality:
Check
Dump
Move
Find
Edit
Count
Once these functionalities were completed, they would be demonstrated to the lab TA for project completion.
During research for this project, some concepts became vital to complete the lab.
The 8051 has the ability to address 64K of memory using 16 address lines, but half of the lines (AD0-AD7) are multiplexed with the incoming data bus, and must be demultiplexed before being able to use either bus.
This is done with the addition of a small address latch. The 8051 provides an ALE signal to indicate whether it’s intending to send a 16-bit address using all 16 lines, or receive 8 bits of data through the 8 data lines. This signal can be fed to the latch to hold address lines high when data is being received, and to pass them through to the controller when it’s calling an address.
In this lab, both serial and parallel communication were used in different areas for different reasons.
As discussed above, address and data fetching used parallel communication across the board. Having a wide bus made communication quick and simple, as the minimum unit of data was a byte. The disadvantages were the amount of lines required (which became slightly unruly during routing) as well as the requirement of multiple components sharing a data bus. This issue was solved using a GAL decoder, which served as a meta-addressor and only activate the specific chip being addressed. This would keep the data bus clear for communication.
Serial communication was added on to the board as an example of communicating with hardware that used a more standardized communication protocol (in this case, RS232). In most cases, parallel communication is cost-prohibitive or impossible, so serial communication is possible with only two lines.
SDCC (small device C compiler) was used extensively during the lab to assemble and compile C code into 8051 assembly. SDCC differs from other C compilers (like those on the desktop) by allowing the developer to choose where in memory (or on external hardware, such as the ROM chips) each variable or constant was stored. This allowed for optimization for specific routines. For example, a section of internal RAM was designated specifically to hold incoming serial, to avoid having to make a trip out to the external memory during a serial interrupt. This was also used to fit image data onto the second ROM specifically, to keep it separate from the rest of code memory.
.
.
For this lab, the code was divided into logical groupings based off functionality. Each of these logical groupings are explained in detail below.
The main module is where main program flow resides in the program. First, an interrupt is scheduled (explained further in Serial). Once the LCD, clock, and serial communication have been initialized, all functionality is delegated to other modules. The main function calls the menu whenever no other functionality is happening (on boot, and after exiting another menu) and calls the function depending on the user input.
The menu module is used to present options to the user. The main menu prints out a list of predefined menu options, waits for the user to press a key, validates that it is within the bounds of available options, then finally returns the chosen option as an exit code. This allows for the main module to call the correct functionality.
The other menu defined in the menu module is to choose block size. Multiple different functionalities featured elsewhere in the program take a block size for their datatype, and this functionality was collected into the block size menu function. Just as the main menu, the program lists out the possible block sizes and returns the user’s choice to the calling function.
Finally, the menu module is also responsible for printing the intro screen and updating the clock when the system boots.
The LCD driver was provided as a part of the lab materials as a means to control the LCD display. These functions include printing text, shapes like circles and squares, as well as housekeeping functions such as clearing the display or manipulating the cursor.
One interesting implementation detail of the LCD library is a
maintained state within the library that can be accessed from other
libraries. For example, the cursor_x
variable, containing
the cursor’s current x position, has a static position in internal RAM.
Then, instead of querying for the cursor position from the LCD, external
libraries can call the getCursorX()
function to determine
where they are drawing on the screen.
The LCD driver also contains the pixel data for the picture, as well as the code to display it. The pixel data is encoded as an array of 16bit RGB565 values, and printed row-by-row as a set of 2x2 squares (resulting in a 2x upscaling of a 160x120 image).
The keypad library collects functions that revolve around the keypad (or user input in general). It provides both a blocking and non-blocking function for getting the button the user pressed on the keypad, whether the calling function needs to determine the user isn’t pressing a key, or wait for them to do so.
The keypad library also includes prompting functions, which use the LCD to prompt the user for a byte or word in hex, taking care of sanitization and conversion before the calling function receives the hex input. The library also contains stubs for inserting serial input (from the ESP virtual keypad) into the regular keypad input routines.
The utilities library contains helper functions that are utilized by almost all libraries. The first is a pair of functions to print hex characters to the display given a byte or a word. This function is used everywhere when needing to translate an address or piece of data to the user.
The second is a set of generic I/O write routines. These helper functions make sure that the IO/M pin is set correctly when addressing I/O devices, since the 8051 does not have hardware support for this pin.
Predictably, the constants library contains no executable code, instead holding lookup tables for ASCII and 7-segment decoding, as well as menu options for the menu library.
The segment library contains functions for interacting with the 7-segment display on the board. The library can draw a character (this is used in the keypad library to echo the user’s input) or display a small moving animation (this is used to show the board is powering on).
The memory module is used to provide helper functions to the other memory manipulation functions like Count and Find. The module provides generic ‘readFromExternalAddress()‘ and ‘writeToExternalAddress()‘ so that the calling function doesn’t have to perform the assembly operations required to move the data pointer. The library also provides functions to page through (forward or backward) memory, finding or counting
The ADC module is responsible for interfacing with the ADC. Since ADC functionality is limited in the current form of the system, this module is only responsible for printing the ADC menu as well as the current read voltage value.
The count module is responsible for controlling the count menu and functionality. It prompts the user for the necessary inputs and then performs the count operation. The user is presented with the report depending on the returned results. At the end, the user can choose to jump into the find routine with the current arguments to show the location of the counted values.
The find module is responsible for the find menu and the actual finding operations. The find module is split into three layers, the find menu, the find operation, and the find page in which the results are displayed.
The find menu is how the user normally accesses find, from the main menu. It prompts the user for the neccessary inputs and then jumps into the find operation.
The find operation uses the memory library to scan forward and backward for the user’s selected value. To avoid holding too many found values in memory, this operation stops once it has reached the specified value, and displays it in the find page. The find operation is abstracted from the menu in cases where another function (like count) needs to jump right into finding the value it just displayed to the user. This avoids prompting the user again for the same information.
The find page takes the found value at a specific address and displays it to the user. Then, it searches forward and backward for another address to jump to, giving the user a previous and next page option if available.
The dump module works in a similar manner to the find module. It asks for the required information through the keypad, then reads that section of memory and passes it to the dump page.
The dump page prints the current address and value to the screen, then does a bounds check for the chosen bounds as well as the start & end of memory to give the user previous and next page indicators so they can scroll to see a new page of memory.
The edit module is responsible for guiding the user to editing a section of memory with the keypad. The function will first prompt the user for the required address to edit, then pass that to an edit page.
An edit page will display the current address and the values to be edited, then let the user type over the displayed values to overwrite the actual memory location. Once this value is entered, the edit page will return this new edited value.
Stepping out of the page, the edit function will write the user value to memory and prompt the user to either go to the next byte to edit or return to the menu.
The move module is responsible for the move menu as well as the memory move operation. It will prompt the user for required input such as source and destination, perform error checks to ensure the move is logical, and finally run through a simple loop to move values from source to destination.
The RamCheck module is responsible for performing the RAM check across all of the memory space. First, it prompts the user for a byte to write, which it passes to a set of inline assembly functions which write and check the entire memory chip with the value. If that succeeds, the module will invert the value and run again, printing the status out to the user.
The RTC module is responsible for controlling the RTC and providing its value to the rest of the system (eg. the title screen). The module contains functions for encoding and decoding date/time values back and forth from the RTC. It also contains the RTC menu, which allows the user to view the current time as well as edit it, using helper functions to convert user input into the correct values to be placed in the RTC registers.
The Serial module contains only one function, the initialization of the serial port on the 8051 to the correct baud rate. SDCC dictated that the serial interrupt must be included in the main module to be compiled and placed in the interrupt vector table.
Throughout this project, most problems were transient, and fixed with a quick continuity test or recompile. However, there were some problems that plagued the project for multiple lab sessions.
Early on in development, in the breadboarding stage, an issue arose in which the circuit would appear to turn on correctly after reset, but would quickly stop functioning soon after without doing anything. Each component was tested, but with each piece of evidence the conclusion was that the processor simply stopped issuing commands soon after boot-up. The chip selection for ROM would stop selecting, and the system would simply freeze.
The solution ended up being to change the decoding. In error, the decoding for the ROM chip select had included IO/M. Due to this error, each time the chip would switch that pin to attempt to access an I/O device, it would lose access to its ROM and cease function.
The keypad used in this project had a lot of issues, most of which were related to noise and debouncing. Essentially, input from the keypad could rarely be trusted, as noise through the lines would press several "phantom" keys immediately after.
The solution to this was to add a delay to the non-blocking keypad read before taking any more input. This would allow the noise to subside and
Throughout the course, all of the design lectures and labs built towards one final system. This system was planned, designed, prototypes on the breadboard, and finally manufactured on a printed circuit board. It began with conceptual labs, writing assembly and later C code targeted against an 8051 simulator. As the lectures turned to systems design, the board began to take shape, finalizing a decoding and operation schema. Finally, the course pivoted to PCB design, and the final output of the lab depended heavily on one’s design and routing.
I could be considered lucky in that my board was routed well enough that I had to make no corrections to my final printed board. I learned a lot about designing a system from the ground up, using my preliminary theoretical knowledge of gates and logic to slowly construct a device that computes. I learned about how to troubleshoot efficiently, learning about the expected output of each part and dialing-in debugging on pieces that didn’t, making each issue an exercise in precision. I learned that while continuing to add pieces on and onto a system works, having a plan and executing it top-to-bottom extensively makes for an easier process. Finally, I learned about all of the ways that machine code can be converted and executed by a system, as well as the advantages and disadvantages of each.
Overall, I had much success in the course and greatly enjoyed the process. There were definitely difficulties, in which troubleshooting seemed daunting. How could I possibly figure out what’s wrong, without seeing the internals of the entire system at the same time? I learned skills to help me work through this paralysis and deduce how to move towards "better," not necessarily jumping to perfect.
.
// including standard headers and portable datatypes
#include "8051.h"
#include <stdint.h>
#include "LCD.h"
#include "Constants.h"
#include "Bool.h"
#include "RamCheck.h"
#include "Utils.h"
#include "Menu.h"
#include "Dump.h"
#include "Move.h"
#include "Find.h"
#include "Edit.h"
#include "Count.h"
#include "Memory.h"
#include "Keypad.h"
#include "Segment.h"
#include "include/LCD.h"
#include "main.h"
#include "RTC.h"
#include "ADC.h"
#include "Serial.h"
void serial_receive_interrupt(void) __interrupt (4)
{
volatile uint8_t data = SBUF;
(data);
setSerialData&= ~(1<<0);
SCON return;
}
void main(void) {
= 0x02;
AUXR ();
serialInit(2);
loadingLoop();
initLCD// rtcInit();
(3);
setRotation(2);
setTextSize(WHITE, GREEN);
setTextColor();
clearLCD();
titleScreenwhile (1) {
uint8_t choice = menu();
switch (choice) {
case 0x0A: // RAM Check
();
ramCheckbreak;
case 0x0B: // Move
();
movebreak;
case 0x0C: // Count
();
countbreak;
case 0x0D: // Dump
();
dumpbreak;
case 0x0E: // Edit
();
editbreak;
case 0x0F: // Find
();
findbreak;
case 0x01: // Clock
();
rtcMenubreak;
case 0x02: // ADC
();
adcMenubreak;
case 0x03: // Fry
();
fryScreenbreak;
}
}
}
#ifndef MAIN_H
#define MAIN_H
#include "8051.h"
(0x8E) AUXR;
__sfr __at
#endif
#include "ADC.h"
#include "Constants.h"
#include <stdint.h>
#include "LCD.h"
#include "Keypad.h"
#include "Utils.h"
void adcMenu(void) {
();
readKeypad(10, 10);
setCursor("Reading voltage...");
printString(7, 216);
setCursor("<E Exit (hold)");
printStringuint8_t keypadIndex = 0;
while (keypadIndex == 0) {
(130, 120);
setCursor();
adcPrint= readKeypad();
keypadIndex }
}
void adcPrint(void) {
uint8_t adcVal;
uint8_t adcVoltageVal;
= ioread8((uint8_t __xdata*) 0xC000);
adcVal = (adcVal * 500) / 255;
adcVoltageVal (asciiLookup[adcVoltageVal / 100]);
printChar(".");
printString(asciiLookup[adcVoltageVal % 10]);
printChar("V");
printString}
#include "Constants.h"
char asciiLookup[17] = "0123456789ABCDEF";
__code char menuCount = 8;
__code char* menuOptions[8] = {"A | RAM Check",
__code "B | Move",
"C | Count",
"D | Dump",
"E | Edit",
"F | Find",
"1 | Clock",
"2 | ADC"};
char blockSizeMenuCount = 4;
__code char* blockSizeMenuOptions[4] = {"A Byte ",
__code "B Word ",
"C Double Word ",
"D Quad Word "};
char segconvert[16] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71}; __code
// associated header file
#include "Count.h"
// including standard headers and portable datatypes
#include "8051.h"
#include <stdint.h>
#include "LCD.h"
#include "Keypad.h"
#include "Utils.h"
#include "Bool.h"
#include "Memory.h"
#include "Find.h"
void count(void) {
uint16_t startAddress = promptForWord("Count Address?");
uint16_t blockQuantity = promptForWord("Byte Quantity?");
uint8_t searchValue = promptForByte("Count Value?");
// quick check to make sure they didn't want zero blocks
while (!blockQuantity) {
= promptForWord("Quantity > 0!");
blockQuantity }
// quick check to see if we will overflow address
if (startAddress + blockQuantity < startAddress) {
= promptForWord("Overflow! Try less blocks.");
blockQuantity return;
}
();
clearLCD(10, 10);
setCursor("Counting 0x");
printString(searchValue);
printHexByteToASCIIArray("...");
printString
// iterate through memory using searchForwardForExternalValue
// every time we find an address, increment a counter and then search again from the next address
uint16_t currentAddress = startAddress;
uint16_t endAddress = startAddress + blockQuantity;
uint8_t count = 0;
= countValueInRange(startAddress, endAddress, searchValue);
count
(10, 35);
setCursor("Matches: ");
printString(count);
printHexByteToASCIIArray
(10, 216);
setCursor
if (count) {
("<E Exit View 1>");
printStringuint8_t choice = waitForKeypad();
if (choice == 1) {
(0, blockQuantity, searchValue);
findArgs}
} else {
("<E Exit |");
printString();
waitForKeypad}
return;
}
// associated header file
#include "Dump.h"
// including standard headers and portable datatypes
#include "8051.h"
#include <stdint.h>
#include "LCD.h"
#include "Keypad.h"
#include "Utils.h"
#include "Memory.h"
#include "Menu.h"
uint8_t dumpPage(uint16_t address, uint8_t byteCount, bool pagesBefore, bool pagesAfter) {
(10, 10);
setCursor("Dumping... E to exit");
printString// back indicator
(7, 216);
setCursorif (pagesBefore) {
("<1");
printString} else {
("| ");
printString}
// current memory address
(120, 216);
setCursor("0x");
printString(address);
printHexWordToASCIIArray
// next indicator
(295, 216);
setCursorif (pagesAfter) {
("0>");
printString} else {
(" |");
printString}
// data at memory location
(150 - byteCount*12, 120);
setCursorwhile (byteCount > 0) {
(readFromExternalAddress(address));
printHexByteToASCIIArray--;
byteCount++;
address}
while (1) {
uint8_t pageChoice = waitForKeypad();
if ((pageChoice == 0 && pagesAfter) || (pageChoice == 1 && pagesBefore) || pageChoice == 0x0E) {
return pageChoice;
}
}
}
void dump(void) {
uint16_t startAddress = promptForWord("Dump Address?");
uint8_t blockSize = blockSizeMenu();
uint16_t blockQuantity = promptForWord("Block Quantity?");
// quick check to make sure they didn't want zero blocks
while (!blockQuantity) {
= promptForWord("Quantity > 0!");
blockQuantity }
// turns the user's block size from a letter choice to a number
switch (blockSize) {
case 0x0B: // word
= 2;
blockSize break;
case 0x0C: // double word
= 4;
blockSize break;
case 0x0D: // quad word!
= 8;
blockSize break;
default: // byte
= 1;
blockSize break;
}
();
clearLCD
// begin our pagination
uint8_t pageChoice = 0;
uint16_t currentPage = 1;
while (pageChoice != 0x0E) {
bool pagesBefore = currentPage > 1;
// check both for if the user requested this many pages, and also make sure we don't overflow
bool pagesAfter = (currentPage < blockQuantity) && ((startAddress + blockSize) > startAddress);
= dumpPage(startAddress, blockSize, pagesBefore, pagesAfter);
pageChoice if (pageChoice == 0 && currentPage < blockQuantity) { // next page
++;
currentPage+= blockSize;
startAddress }
if (pageChoice == 1 && currentPage > 1) { // prev page
--;
currentPage-= blockSize;
startAddress }
}
}
// associated header file
#include "Edit.h"
// including standard headers and portable datatypes
#include "8051.h"
#include <stdint.h>
#include "LCD.h"
#include "Keypad.h"
#include "Utils.h"
#include "Memory.h"
#include "Constants.h"
uint8_t editPage(uint16_t address) {
();
clearLCD
// current memory address
(10, 10);
setCursor("Editing 0x");
printString(address);
printHexWordToASCIIArray("...");
printString(10, 35);
setCursor("Type to replace value");
printString
// data at memory location
(140, 120);
setCursor(readFromExternalAddress(address));
printHexByteToASCIIArray
// let the user write a value
(140, 120);
setCursor
// first nibble
uint8_t firstCharacter = waitForKeypad();
(asciiLookup[firstCharacter]);
printChar
// second nibble
uint8_t secondCharacter = waitForKeypad();
(asciiLookup[secondCharacter]);
printChar
// combine and return
return (firstCharacter << 4) | secondCharacter;
}
void edit(void) {
uint16_t startAddress = promptForWord("Edit Address?");
// lets show the memory at that address
uint8_t userChoice = 2;
while (userChoice != 0xE) {
= 2;
userChoice uint8_t userByte = editPage(startAddress);
(startAddress, userByte);
writeToExternalAddress(10, 216);
setCursor("<E Exit Next 0>");
printStringwhile (userChoice != 0 && userChoice != 0xE) {
= waitForKeypad();
userChoice }
// overflow check
if (startAddress + 1 < startAddress) {
("End of memory!");
errorBackToMenureturn;
} else {
++;
startAddress}
}
return;
}
// associated header file
#include "Find.h"
// including standard headers and portable datatypes
#include "8051.h"
#include <stdint.h>
#include "LCD.h"
#include "Keypad.h"
#include "Utils.h"
#include "Memory.h"
#include "Bool.h"
uint8_t findPage(uint16_t address, bool pagesBefore, bool pagesAfter) {
// back indicator
(7, 216);
setCursorif (pagesBefore) {
("<1");
printString} else {
("| ");
printString}
// current memory address
(120, 216);
setCursor("0x");
printString(address);
printHexWordToASCIIArray
// next indicator
(295, 216);
setCursorif (pagesAfter) {
("0>");
printString} else {
(" |");
printString}
while (1) {
uint8_t pageChoice = waitForKeypad();
if ((pageChoice == 0 && pagesAfter) || (pageChoice == 1 && pagesBefore) || pageChoice == 0x0E) {
return pageChoice;
}
}
}
void findArgs(uint16_t startAddress, uint16_t blockQuantity, uint8_t searchValue) {
();
clearLCD
(10, 10);
setCursor("Finding 0x");
printString(searchValue);
printHexByteToASCIIArray("... E to exit");
printString
// start searching
bool found = false;
uint16_t foundAddress = searchForwardForExternalValue(startAddress, searchValue, &found);
if (foundAddress < startAddress || foundAddress > startAddress + blockQuantity) {
// we couldn't find anything
("Byte not found!");
errorBackToMenureturn;
} else {
uint8_t userChoice = 0xF;
while (userChoice != 0xE) {
// see if we have before
bool pagesBefore = false;
uint16_t beforeAddress = searchBackwardForExternalValue(foundAddress - 1, searchValue, &pagesBefore);
// make sure the address we found is actually within our range
if (pagesBefore) {
= beforeAddress >= startAddress;
pagesBefore }
// see if we have after
bool pagesAfter = false;
uint16_t afterAddress = searchForwardForExternalValue(foundAddress + 1, searchValue, &pagesAfter);
// make sure the address we found is actually within our range
if (pagesAfter) {
= afterAddress <= startAddress + blockQuantity;
pagesAfter }
= findPage(foundAddress, pagesBefore, pagesAfter);
userChoice if (userChoice == 0) {
= afterAddress;
foundAddress } else if (userChoice == 1) {
= beforeAddress;
foundAddress }
}
return;
}
}
void find(void) {
uint16_t startAddress = promptForWord("Find Address?");
uint16_t blockQuantity = promptForWord("Byte Quantity?");
uint8_t searchValue = promptForByte("Search For?");
// quick check to make sure they didn't want zero blocks
while (!blockQuantity) {
= promptForWord("Quantity > 0!");
blockQuantity }
(startAddress, blockQuantity, searchValue);
findArgs}
// associated header file
#include "Keypad.h"
// including standard headers and portable datatypes
#include "8051.h"
#include <stdint.h>
#include "LCD.h"
#include "Constants.h"
#include "Segment.h"
#define KEYPAD_PORT P1
uint8_t __idata serialData;
// flashes the rows of the matrix keypad and returns a byte representing the current row pressed (if any)
uint8_t checkRows(void) {
= 0xF0;
KEYPAD_PORT return KEYPAD_PORT;
}
// flashes the columns of the matrix keypad and returns a byte representing the current column pressed (if any)
uint8_t checkColumns(void) {
= 0x0F;
KEYPAD_PORT return KEYPAD_PORT;
}
// non-blocking function to read the current button pressed
// if none is pressed, return 0
uint8_t readKeypad(void) {
uint8_t rowValue = checkRows();
if (rowValue != 0xF0) {
uint8_t columnValue = checkColumns();
if (columnValue != 0x0F) {
return rowValue | columnValue;
}
}
// check our serial
if (serialData != 0) {
uint8_t incomingSerial = serialData;
= 0;
serialData return incomingSerial;
}
return 0;
}
// converts the incoming keypad index into the numerical value of the button pressed
uint8_t decodeKeypadToHex(uint8_t keypadIndex) {
switch(keypadIndex) {
case 0xD7: // 3
return 3;
break;
case 0xEE: // D
return 13;
break;
case 0xDE: // E
return 14;
break;
case 0xBE: // 0
return 0;
break;
case 0xED: // C
return 12;
break;
case 0xDD: // 9
return 9;
break;
case 0xBD: // 8
return 8;
break;
case 0xEB: // B
return 11;
break;
case 0xDB: // 6
return 6;
break;
case 0xBB: // 5
return 5;
break;
case 0x7E: // F
return 15;
break;
case 0x7D: // 7
return 7;
break;
case 0x7B: // 4
return 4;
break;
case 0x77: // 1
return 1;
break;
case 0xB7: // 2
return 2;
break;
case 0xE7: // A
return 10;
break;
default:
return 16;
break;
}
}
// blocking function, returns the numerical value of the key the user pressed
uint8_t waitForKeypad(void) {
uint8_t keypadIndex = 0;
while (keypadIndex == 0) {
= readKeypad();
keypadIndex }
uint8_t keypadValue = decodeKeypadToHex(keypadIndex);
(keypadValue);
hexToSegment(500);
delaywhile (keypadIndex != 0) {
= readKeypad();
keypadIndex }
return keypadValue;
}
// blocking function to wait for a specific key to be pressed
void waitForKey(uint8_t key) {
uint8_t keypadValue = 16;
while (keypadValue != key) {
= waitForKeypad();
keypadValue }
}
// prompts for a byte using the passed string and returning a single byte
uint8_t promptForByte(char* prompt) {
// print instructions
();
clearLCD(20, 10);
setCursor(prompt);
printString(20, 35);
setCursor("Byte: 0x");
printStringint oldCursorX = getCursorX();
("__");
printString(oldCursorX, 35);
setCursor
// first character
uint8_t firstCharacter = waitForKeypad();
(asciiLookup[firstCharacter]);
printChar
// second character
uint8_t secondCharacter = waitForKeypad();
(asciiLookup[secondCharacter]);
printChar
// combine and return
return (firstCharacter << 4) | secondCharacter;
}
uint16_t promptForWord(char* prompt) {
// print instructions
();
clearLCD(20, 10);
setCursor(prompt);
printString(20, 35);
setCursor("Word: 0x");
printStringint oldCursorX = getCursorX();
("____");
printString(oldCursorX, 35);
setCursor
// first character
uint8_t firstCharacter = waitForKeypad();
(asciiLookup[firstCharacter]);
printChar
// second character
uint8_t secondCharacter = waitForKeypad();
(asciiLookup[secondCharacter]);
printChar
// third character
uint8_t thirdCharacter = waitForKeypad();
(asciiLookup[thirdCharacter]);
printChar
// fourth character
uint8_t fourthCharacter = waitForKeypad();
(asciiLookup[fourthCharacter]);
printChar
// combine and return
return (firstCharacter << 12) | (secondCharacter << 8) | (thirdCharacter << 4) | fourthCharacter;
}
void setSerialData(uint8_t data) {
= data;
serialData }
uint8_t getSerialData(void) {
return serialData;
}
/*
author: Matthew Boeding
version: v1.0
README
/// TFT-LCD (ILI9341) Driver code for the 8051. Can be repurposed for other drivers controllers :)
/// I optimized the code quite a bit for speed, utilizing internal pointers
/// Please do not post any of the code from this course to GITHUB.
*/
#include "LCD.h"
#include "bmp_image.h"
#include "font.h"
#include "Keypad.h"
uint8_t* lcd_address = (uint8_t __xdata*) LCD_ADDRESS;
__xdata /* cursor_y and cursor_x globals*/
uint16_t __idata* cursor_x = (uint16_t __idata*)(0xC2);
uint16_t __idata* cursor_y = (uint16_t __idata*)(0xC4);
/* textsize and rotation*/
uint8_t __idata* textsize = (uint8_t __idata*)(0xC6);
uint8_t __idata* rotation = (uint8_t __idata*)(0xC7);
/* text color and background */
uint16_t __idata* textcolor = (uint16_t __idata*)(0xC8);
uint16_t __idata* textbgcolor = (uint16_t __idata*)(0xCA);
/* lcd width and height */
uint16_t __idata* _width = (uint16_t __idata*)(0xCC);
uint16_t __idata* _height = (uint16_t __idata*)(0xCE);
uint8_t intro1[9] = {"Welcome\n",0};
__code
void delay (int16_t d)
{
int16_t i, j = 0; /* declare for backwards compatibility with older C standards */
for (i=0;i<d;i++) /* this is For(); loop delay used to define delay value in Embedded C*/
{
for (j=0;j<80;j++)
{
}
}
}
inline void lcdWrite8Reg(uint8_t d) {
= 0;
CD = 1;
IOM *lcd_address = d;
= 0;
IOM }
inline void lcdWrite8Data(uint8_t d) {
= 1;
CD = 1;
IOM *lcd_address = d;
= 0;
IOM }
inline void lcdWrite8DataBlocking(uint8_t d)
{
*lcd_address = d;
}
inline void lcdWriteRegData8(uint8_t a, uint8_t d) {
= 0;
CD = 1;
IOM *lcd_address = a;
= 0;
IOM = 1;
CD = 1;
IOM *lcd_address = d;
= 0;
IOM }
uint16_t getCursorX(void)
{
return *cursor_x;
}
uint16_t getCursorY(void)
{
return *cursor_y;
}
uint8_t getTextSize(void)
{
return *textsize;
}
void setCursorx(uint16_t x)
{
*cursor_x = x;
}
void setCursory(uint16_t y)
{
*cursor_y = y;
}
void lcdWriteRegData16(uint16_t a, uint16_t d){
uint8_t hi, lo;
= (a) >> 8;
hi = (a);
lo (hi);
lcdWrite8Reg(lo);
lcdWrite8Reg= (d) >> 8;
hi = (d);
lo (hi);
lcdWrite8Data(lo);
lcdWrite8Data}
void setCursor(uint16_t x, uint16_t y){
*cursor_x = x;
*cursor_y = y;
}
void setTextColor(uint16_t x, uint16_t y){
*textcolor = x;
*textbgcolor = y;
}
void setTextSize(uint8_t s){
if (s > 8) return;
*textsize = (s>0) ? s : 1 ;
}
void setRotation(uint8_t flag){
*rotation = flag;
switch(flag) {
case 0:
= (ILI9341_MADCTL_MX | ILI9341_MADCTL_BGR);
flag *_width = TFTWIDTH;
*_height = TFTHEIGHT;
break;
case 1:
= (ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR);
flag *_width = TFTHEIGHT;
*_height = TFTWIDTH;
break;
case 2:
= (ILI9341_MADCTL_MY | ILI9341_MADCTL_BGR);
flag *_width = TFTWIDTH;
*_height = TFTHEIGHT;
break;
case 3:
= (ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR);
flag *_width = TFTHEIGHT;
*_height = TFTWIDTH;
break;
default:
= (ILI9341_MADCTL_MX | ILI9341_MADCTL_BGR);
flag *_width = TFTWIDTH;
*_height = TFTHEIGHT;
break;
}
(ILI9341_MEMCONTROL, flag);
lcdWriteRegData8}
void setAddress(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2){
(ILI9341_COLADDRSET);
lcdWrite8Reg(x1 >> 8);
lcdWrite8Data(x1);
lcdWrite8Data(x2 >> 8);
lcdWrite8Data(x2);
lcdWrite8Data
(ILI9341_PAGEADDRSET);
lcdWrite8Reg(y1 >> 8);
lcdWrite8Data(y1);
lcdWrite8Data(y2 >> 8);
lcdWrite8Data(y2);
lcdWrite8Data}
void initLCD(void){
*_width = TFTWIDTH;
*_height = TFTHEIGHT;
(ILI9341_MADCTL_RGB);
lcdWrite8Reg(0x00);
lcdWrite8Data(0x00);
lcdWrite8Data(0x00);
lcdWrite8Data
(200);
delay
(ILI9341_SOFTRESET);
lcdWrite8Reg(50);
delay(ILI9341_DISPLAYOFF);
lcdWrite8Reg(10);
delay
(ILI9341_POWERCONTROL1, 0x23);
lcdWriteRegData8(ILI9341_POWERCONTROL2, 0x11);
lcdWriteRegData8(ILI9341_VCOMCONTROL1);
lcdWrite8Reg(0x3d);
lcdWrite8Data(0x30);
lcdWrite8Data(ILI9341_VCOMCONTROL2, 0xaa);
lcdWriteRegData8(ILI9341_MEMCONTROL, ILI9341_MADCTL_MY | ILI9341_MADCTL_BGR);
lcdWriteRegData8(ILI9341_PIXELFORMAT);
lcdWrite8Reg(0x55);lcdWrite8Data(0x00);
lcdWrite8Data(ILI9341_FRAMECONTROL, 0x001B);
lcdWriteRegData16
(ILI9341_ENTRYMODE, 0x07);
lcdWriteRegData8
(ILI9341_SLEEPOUT);
lcdWrite8Reg(150);
delay(ILI9341_DISPLAYON);
lcdWrite8Reg(500);
delay(0,0,*_width-1,*_height-1);
setAddress/************* Start Initial Sequence ILI9341 controller **********/
}
void drawPixel(uint16_t x3,uint16_t y3,uint16_t color1)
{
(x3,y3,x3+1,y3+1);
setAddress(ILI9341_MEMORYWRITE);
lcdWrite8Reg(color1>>8);
lcdWrite8Data(color1);
lcdWrite8Data}
void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color){
int f = 1 - r;
int ddF_x = 1;
int ddF_y = -2 * r;
int x = 0;
int y = r;
(x0 , y0+r, color);
drawPixel(x0 , y0-r, color);
drawPixel(x0+r, y0 , color);
drawPixel(x0-r, y0 , color);
drawPixel
while (x<y) {
if (f >= 0) {
--;
y+= 2;
ddF_y += ddF_y;
f }
++;
x+= 2;
ddF_x += ddF_x;
f
(x0 + x, y0 + y, color);
drawPixel(x0 - x, y0 + y, color);
drawPixel(x0 + x, y0 - y, color);
drawPixel(x0 - x, y0 - y, color);
drawPixel(x0 + y, y0 + x, color);
drawPixel(x0 - y, y0 + x, color);
drawPixel(x0 + y, y0 - x, color);
drawPixel(x0 - y, y0 - x, color);
drawPixel}
}
void fillRect(uint16_t x,uint16_t y,uint16_t w,uint16_t h,uint16_t color){
if ((x >= *_width) || (y >= *_height))
{
return;
}
if ((x+w-1) >= *_width)
{
= *_width-x;
w }
if ((y+h-1) >= *_height)
{
= *_height-y;
h }
(x, y, x+w-1, y+h-1);
setAddress
(ILI9341_MEMORYWRITE);
lcdWrite8Reg= 1;
CD for(y=h; y>0; y--)
{
for(x=w; x>0; x--)
{
(color>>8);
lcdWrite8Data(color);
lcdWrite8Data}
}
}
void fillScreen(void){
long len = 76800;
int blocks = 1200;
uint8_t i, hi =*textbgcolor >> 8;
uint8_t lo = *textbgcolor;
(0,0,*_width-1,*_height-1);
setAddress
(ILI9341_MEMORYWRITE);
lcdWrite8Reg(hi);
lcdWrite8Data(lo);
lcdWrite8Data--;
len= 1;
IOM while(blocks--) {
= 16;
i do {
*lcd_address = hi;*lcd_address = lo;
*lcd_address = hi;*lcd_address = lo;
*lcd_address = hi;*lcd_address = lo;
*lcd_address = hi;*lcd_address = lo;
} while(--i);
}
for(i = (char)len & 63; i--; ) {
*lcd_address = hi;*lcd_address = lo;
}
= 0;
IOM
}
void clearLCD(void){
();
fillScreen(0, 0);
setCursor}
void drawChar(uint8_t c){
int16_t x = *cursor_x;
int16_t y = *cursor_y;
uint16_t color = *textcolor;
uint16_t bg = *textbgcolor;
int8_t size = *textsize;
int8_t i, j;
uint8_t line;
for (i=0; i<6; i++)
{
if (i == 5)
{
= 0x0;
line }
else
{
= pgm_read_byte(font+(c*5)+i);
line }
for (j = 0; j<8; j++)
{
if (line & 0x1)
{
if (size == 1)
{
(x+i, y+j, color);
drawPixel}
else {
(x+(i*size), y+(j*size), size, size, color);
fillRect}
} else if (bg != color)
{
if (size == 1)
{
(x+i, y+j, bg);
drawPixel}
else
{
(x+i*size, y+j*size, size, size, bg);
fillRect}
}
>>= 1;
line }
}
}
void printChar(uint8_t c)
{
if (c == '\n')
{
*cursor_y += *textsize*8;
*cursor_x = 0;
}
else if (c == '\r')
{
}
else
{
(c);
drawChar*cursor_x += *textsize*6;
}
}
void printString(char *str)
{
int16_t i;
for(i=0;str[i]!=0;i++) /* Send each char of string till the NULL */
{
(str[i]); /* Call transmit data function */
printChar}
}
uint16_t reverse(uint8_t d) {
uint16_t rev = 0;
uint16_t val = 0;
while(d >= 1){
= d%10;
val = d/10;
d = rev * 10 + val;
rev }
return rev;
}
void asciiToDec(uint8_t d) {
uint8_t val;
uint16_t id;
= reverse(d);
id while (id >= 1){
= id % 10;
val = id/10;
id (val + '0');
printChar}
}
void asciiToHex(uint8_t d) {
uint8_t val;
uint8_t store[2];
[0] = 0;
store[1] = 0;
store= d & 0x0F;
val = d >> 4;
d if (val <= 9) {
[0] = val + '0';
store}
else {
[1] = (val%10) + 'A';
store}
if (d <= 9) {
[0] = d + '0';
store}
else {
[1] = (d%10) + 'A';
store}
(store[1]);
printChar(store[0]);
printChar}
void errorBackToMenu(char* message) {
(10, 191);
setCursor(message);
printString(10, 216);
setCursor("<1 Back to Menu");
printString(1);
waitForKey}
// associated header file
#include "Memory.h"
// including standard headers and portable datatypes
#include "8051.h"
#include <stdint.h>
#include "Bool.h"
#include "LCD.h"
uint8_t readFromExternalAddress(uint16_t address) {
// load our data pointer with the incoming address before we jump to assembly
= (address >> 8);
DPH = address;
DPL
__asm, @DPTR
MOVX A;
__endasmuint8_t value = ACC;
return value;
}
void writeToExternalAddress(uint16_t address, uint8_t value) {
// load our data pointer with the incoming address and A with the value before we jump to assembly
= (address >> 8);
DPH = address;
DPL = value;
ACC
__asm, A
MOVX @DPTR;
__endasmreturn;
}
uint16_t searchForwardForExternalValue(uint16_t address, uint8_t value, bool* success) {
// starting at our current address, we'll compare each byte to our value
// if we find it, we'll set success true and return with the current address
// otherwise, we'll increment the address and continue
// if we reach the end of the memory block, we'll set success false and return
for (address; address + 1 > 0; address++) {
uint8_t currentValue = readFromExternalAddress(address);
if (currentValue == value) {
*success = true;
return address;
}
}
= false;
success return 0;
}
uint16_t searchBackwardForExternalValue(uint16_t address, uint8_t value, bool* success) {
for (address; address - 1 < 0xFFFF; address--) {
uint8_t currentValue = readFromExternalAddress(address);
if (currentValue == value) {
*success = true;
return address;
}
}
= false;
success return 0;
}
uint16_t searchRangeForValue(uint16_t startAddress, uint16_t endAddress, uint8_t value, bool* success) {
for (startAddress; startAddress <= endAddress; startAddress++) {
uint8_t readValue = readFromExternalAddress(startAddress);
if (readValue == value) {
*success = true;
return startAddress;
}
}
*success = false;
return 0;
}
uint16_t countValueInRange(uint16_t startAddress, uint16_t endAddress, uint8_t value) {
uint16_t count = 0;
for (startAddress; startAddress < endAddress; startAddress++) {
uint8_t readValue = readFromExternalAddress(startAddress);
if (readValue == value) {
++;
count}
}
// quick final check
if (startAddress == 0xFFFF) {
uint8_t readValue = readFromExternalAddress(startAddress);
if (readValue == value) {
++;
count}
}
return count;
}
// associated header file
#include "Menu.h"
// including standard headers and portable datatypes
#include "8051.h"
#include <stdint.h>
#include "LCD.h"
#include "Keypad.h"
#include "Utils.h"
#include "Constants.h"
#include "RTC.h"
uint16_t futurama[] = {0x10C3,0x2146,0x2146,0x2146,0x1945,0x2146,0x2146,0x2146,0x2146,0x2146,0x1945,0x1945,0x2146,0x2146,0x2146,0x2146,0x1945}; // full array omitted for brevity
__code
void titleScreen(void) {
(60, 70);
setCursor(" Carter Brehm ");
printString(60, 150);
setCursor(" ECEN 433 *> ");
printString// we don't care what button they press here
while (readKeypad() == 0) {
(50, 216);
setCursor();
rtcPrint}
();
clearLCD}
void fryScreen(void) {
uint16_t i = 0;
uint16_t j = 0;
uint16_t k = 0;
while (i < 19200) {
//drawPixel(2*j, 2*k, futurama[i]);
(2*j, 2*k, 2, 2, futurama[i]);
fillRect++;
j++;
iif (j == 160) {
= 0;
j ++;
k}
}
(30, 216);
setCursor(WHITE, BLACK);
setTextColor("I.C. Wiener? Oh, crud.");
printStringwhile (readKeypad() == 0);
(WHITE, GREEN);
setTextColor}
uint8_t menu(void) {
();
clearLCD(85, 5);
setCursor("Menu Options");
printString
for(int i = 0; i < menuCount; i++) {
(80, (i+2)*24);
setCursor(menuOptions[i]);
printString}
while (1) {
uint8_t menuChoice = waitForKeypad();
if ((menuChoice >= 0x0A && menuChoice <= 0x0F) || (menuChoice >= 0x01 && menuChoice <= 0x03)) { // return the user's choice
();
clearLCDreturn menuChoice;
} else {
= waitForKeypad();
menuChoice break;
}
}
return 0;
}
uint8_t blockSizeMenu(void) {
();
clearLCD(85, 10);
setCursor("Block Size");
printString
for(int i = 0; i < blockSizeMenuCount; i++) {
(70, (i+3)*25);
setCursor(blockSizeMenuOptions[i]);
printString}
while (1) {
uint8_t menuChoice = waitForKeypad();
if (menuChoice >= 0x0A && menuChoice <= 0x0F) { // return the user's choice
();
clearLCDreturn menuChoice;
} else {
= waitForKeypad();
menuChoice break;
}
}
return 0;
}
// associated header file
#include "Move.h"
// including standard headers and portable datatypes
#include "8051.h"
#include <stdint.h>
#include "LCD.h"
#include "Keypad.h"
#include "Utils.h"
#include "Menu.h"
#include "Memory.h"
void move(void) {
uint16_t srcAddress = promptForWord("Src Address?");
uint8_t blockSize = blockSizeMenu();
uint16_t blockQuantity = promptForWord("Block Quantity?");
// quick check to make sure they didn't want zero blocks
while (!blockQuantity) {
= promptForWord("Quantity > 0!");
blockQuantity }
// turns the user's block size from a letter choice to a number
switch (blockSize) {
case 0x0B: // word
= 2;
blockSize break;
case 0x0C: // double word
= 4;
blockSize break;
case 0x0D: // quad word!
= 8;
blockSize break;
default: // byte
= 1;
blockSize break;
}
();
clearLCD
uint16_t totalBytes = 0;
// check for if our block of memory will be too big
if (blockSize * blockQuantity < blockSize) {
("Block Overflow!");
errorBackToMenureturn;
} else {
= blockSize * blockQuantity;
totalBytes }
// sanity checks to make sure we won't overflow
if (srcAddress + (totalBytes) < srcAddress) {
("Src Overflow!");
errorBackToMenureturn;
}
uint16_t destAddress = promptForWord("Dest Address?");
if (destAddress + (totalBytes) < destAddress) {
("Dest Overflow!");
errorBackToMenureturn;
}
();
clearLCD
// XXXX * Y bytes
(20, 10);
setCursor("Moving ");
printString(blockQuantity);
printHexWordToASCIIArray(" * ");
printString(blockSize);
printHexByteToASCIIArray(" bytes");
printString
// 0xAAAA -> 0xBBBB
(20, 35);
setCursor("from 0x");
printString(srcAddress);
printHexWordToASCIIArray(" -> 0x");
printString(destAddress);
printHexWordToASCIIArray
// for each byte in totalBytes, copy from src to dest, then increase pointers
while (totalBytes > 0) {
(destAddress, readFromExternalAddress(srcAddress));
writeToExternalAddress--;
totalBytes++;
srcAddress++;
destAddress}
("Move Complete!");
errorBackToMenu
}
#include "RTC.h"
#include "LCD.h"
#include <stdint.h>
#include "Utils.h"
#include "Keypad.h"
#include "Constants.h"
// void rtcInit(void)
// {
// uint8_t mon_ctrl = __MON_E32K_SET__ | 0x05; // Set month to May (05)
// uint8_t ctrl_a = __CTRLA_PAB_SET__; // Control A settings (no changes needed here)
// uint8_t ctrl_b = (__CTRLB_TE_SET__ | __CTRLB_BME_SET__); // Control B settings (no changes needed here)
// iowrite8((uint8_t __xdata *)(__RTC_CTRL_A_REG__), ctrl_a); // Set Control A register
// iowrite8((uint8_t __xdata *)(__RTC_CTRL_B_REG__), ctrl_b); // Set Control B register
// iowrite8((uint8_t __xdata *)(__RTC_MONTH_REG__), mon_ctrl); // Set month to May
// iowrite8((uint8_t __xdata *)(__RTC_YEAR_REG__), 0x24); // Set year to 24 (2024 in BCD)
// iowrite8((uint8_t __xdata *)(__RTC_DATE_REG__), 0x09); // Set date to 08 (for May 8th)
// iowrite8((uint8_t __xdata *)(__RTC_HOURS_REG__), 0x01); // Hours in 24-hour format, 14 for 2 PM
// iowrite8((uint8_t __xdata *)(__RTC_MINUTES_REG__), 0x00); // Set minutes to 30
// iowrite8((uint8_t __xdata *)(__RTC_SECONDS_REG__), 0x00); // Set seconds to 00
// // Additional setup can be done below if needed (e.g., alarms)
// }
uint8_t rtcBcdToAscii(uint8_t bcd)
{
= bcd & 0x0F;
bcd if (bcd < 10)
{
= 0x30 + bcd;
bcd }
return bcd;
}
uint8_t rtcAsciiToBcd(uint8_t ascii)
{
if(ascii >= 0x30 && ascii < 0x3A)
{
= ascii & 0x0F;
ascii }
return ascii;
}
void rtcRegToLCD(uint8_t __xdata * reg, uint8_t mask)
{
uint8_t rtcTemp,rtcCurrent;
= ioread8(reg);
rtcCurrent = rtcCurrent & mask;
rtcCurrent = rtcCurrent >> 4;
rtcTemp (rtcBcdToAscii(rtcTemp));
printChar(rtcBcdToAscii(rtcCurrent));
printChar}
void rtcPrint(void)
{
uint8_t __xdata * ptr = (uint8_t __xdata *)(__RTC_MONTH_REG__);
(ptr, 0x1F);
rtcRegToLCD('/');
printChar= (uint8_t __xdata *)(__RTC_DATE_REG__);
ptr (ptr, 0x3F);
rtcRegToLCD('/');
printChar= (uint8_t __xdata *)(__RTC_YEAR_REG__);
ptr (ptr, 0xFF);
rtcRegToLCD(' ');
printChar= (uint8_t __xdata *)(__RTC_HOURS_REG__);
ptr (ptr, 0x3F);
rtcRegToLCD(':');
printChar= (uint8_t __xdata *)(__RTC_MINUTES_REG__);
ptr (ptr, 0x7F);
rtcRegToLCD(':');
printChar= (uint8_t __xdata *)(__RTC_SECONDS_REG__);
ptr (ptr,0x7F);
rtcRegToLCD}
void rtcMenu(void) {
();
readKeypad(10, 10);
setCursor("Current date and time:");
printString(7, 216);
setCursor("<0 Exit (hold) E Edit>");
printStringuint8_t keypadIndex = 0;
while (keypadIndex == 0) {
(40, 120);
setCursor();
rtcPrint= readKeypad();
keypadIndex }
// they pressed edit
if (keypadIndex == 0xDE) {
(10, 10);
setCursor("Editing date and time...");
printString(40, 120);
setCursor("__/__/__ __:__:__");
printString(40, 120);
setCursor
// month
uint8_t firstCharacter = waitForKeypad();
(asciiLookup[firstCharacter]);
printCharuint8_t secondCharacter = waitForKeypad();
(asciiLookup[secondCharacter]);
printChar
uint8_t month = (firstCharacter << 4) | secondCharacter;
("/");
printString
// day
= waitForKeypad();
firstCharacter (asciiLookup[firstCharacter]);
printChar= waitForKeypad();
secondCharacter (asciiLookup[secondCharacter]);
printChar
uint8_t day = (firstCharacter << 4) | secondCharacter;
("/");
printString
// year
= waitForKeypad();
firstCharacter (asciiLookup[firstCharacter]);
printChar= waitForKeypad();
secondCharacter (asciiLookup[secondCharacter]);
printChar
uint8_t year = (firstCharacter << 4) | secondCharacter;
(" ");
printString
// hours
= waitForKeypad();
firstCharacter (asciiLookup[firstCharacter]);
printChar= waitForKeypad();
secondCharacter (asciiLookup[secondCharacter]);
printChar
uint8_t hours = (firstCharacter << 4) | secondCharacter;
(":");
printString
// minutes
= waitForKeypad();
firstCharacter (asciiLookup[firstCharacter]);
printChar= waitForKeypad();
secondCharacter (asciiLookup[secondCharacter]);
printChar
uint8_t minutes = (firstCharacter << 4) | secondCharacter;
(":");
printString
// seconds
= waitForKeypad();
firstCharacter (asciiLookup[firstCharacter]);
printChar= waitForKeypad();
secondCharacter (asciiLookup[secondCharacter]);
printChar
uint8_t seconds = (firstCharacter << 4) | secondCharacter;
uint8_t mon_ctrl = __MON_E32K_SET__ | month; // Set month to May (05)
uint8_t ctrl_a = __CTRLA_PAB_SET__; // Control A settings (no changes needed here)
uint8_t ctrl_b = (__CTRLB_TE_SET__ | __CTRLB_BME_SET__); // Control B settings (no changes needed here)
((uint8_t __xdata *)(__RTC_CTRL_A_REG__), ctrl_a); // Set Control A register
iowrite8((uint8_t __xdata *)(__RTC_CTRL_B_REG__), ctrl_b); // Set Control B register
iowrite8((uint8_t __xdata *)(__RTC_MONTH_REG__), mon_ctrl); // Set month to May
iowrite8((uint8_t __xdata *)(__RTC_YEAR_REG__), year); // Set year to 24 (2024 in BCD)
iowrite8((uint8_t __xdata *)(__RTC_DATE_REG__), day); // Set date to 08 (for May 8th)
iowrite8((uint8_t __xdata *)(__RTC_HOURS_REG__), hours); // Hours in 24-hour format, 14 for 2 PM
iowrite8((uint8_t __xdata *)(__RTC_MINUTES_REG__), minutes); // Set minutes to 30
iowrite8((uint8_t __xdata *)(__RTC_SECONDS_REG__), seconds); // Set seconds to 00
iowrite8
}
}
// associated header file
#include "RamCheck.h"
// including standard headers and portable datatypes
#include "8051.h"
#include <stdint.h>
#include "Bool.h"
#include "LCD.h"
#include "Utils.h"
#include "Keypad.h"
void writeAllRam(uint8_t value) {
// the assembly code will fetch the value to be written from the bccumulator
= value;
B
__asm.EQU 1
RAMCHECK_WRITE_LOOP , #0
MOV DPH, #0
MOV DPL:
RAMCHECK_WRITE_LOOP$, B
MOV A, A
MOVX @DPTR
INC DPTR, DPL
MOV A, DPH
ORL A
JNZ RAMCHECK_WRITE_LOOP$;
__endasm}
bool readAllRam(uint8_t value) {
// the assembly code will fetch the value to be compared against from the bccumulator
= value;
B
__asm.EQU 1
RAMCHECK_READ_LOOP .EQU 2
RAMCHECK_READ_FAIL .EQU 3
RAMCHECK_READ_DONE , #0
MOV DPH, #0
MOV DPL:
RAMCHECK_READ_LOOP$, @DPTR
MOVX A, B
SUBB A
JNZ RAMCHECK_READ_FAIL$
INC DPTR, DPL
MOV A, DPH
ORL A
JNZ RAMCHECK_READ_LOOP$, #1
MOV B
SJMP RAMCHECK_READ_DONE$:
RAMCHECK_READ_FAIL$, #0
MOV B:
RAMCHECK_READ_DONE$;
__endasm// returns the value our assembly put in regB as a true/false
return B;
}
// takes a byte value, writes it to the entire XRAM, then inverts and repeats
// returns FALSE on success, TRUE on error
bool ramCheckCycle(uint8_t value) {
// Writing RAM w/ value: 0x__
("Writing 0x");
printString(value);
printHexByteToASCIIArray("... ");
printString
// perform the write
(value);
writeAllRam
("done");
printString
// Checking RAM w/
// leaving "value: 0x__" on screen
(10, getCursorY() + 25);
setCursor("Checking for 0x");
printString(value);
printHexByteToASCIIArray("... ");
printString
// perform the read
bool readSuccess = readAllRam(value);
// if we failed the read, tell the user and duck out immediately
if (!readSuccess) {
("RAM Fail!");
errorBackToMenu// TODO: return address of failure?
return true;
}
// we succeeded!
("done");
printString(10, getCursorY() + 25);
setCursorreturn false;
}
void ramCheck(void) {
uint8_t value = promptForByte("RAM Check Value?");
();
clearLCD(10, 10);
setCursor
if (ramCheckCycle(value) != 0 || ramCheckCycle(~value) != 0)
// error, return immediately to menu
return;
("RAM Success!");
errorBackToMenureturn;
}
#include "Segment.h"
#include "8051.h"
#include "LCD.h"
#include "Constants.h"
#include <stdint.h>
#include "Utils.h"
void hexToSegment(uint8_t byte) {
uint8_t segment = 0;
= segconvert[byte];
segment ((char __xdata*)(0x8000), segment);
iowrite8}
void loadingLoop(uint8_t count) {
for (uint8_t j = 0; j < count; j++) {
((char __xdata*)(0x8000), 0x01);
iowrite8(100);
delay((char __xdata*)(0x8000), 0x02);
iowrite8(100);
delay((char __xdata*)(0x8000), 0x04);
iowrite8(100);
delay((char __xdata*)(0x8000), 0x08);
iowrite8(100);
delay((char __xdata*)(0x8000), 0x10);
iowrite8(100);
delay((char __xdata*)(0x8000), 0x20);
iowrite8(100);
delay}
((char __xdata*)(0x8000), 0x00);
iowrite8}
#include "Serial.h"
#include "8051.h"
void serialInit(void) {
|= (1<<0) | (1<<1);
P3 = 0xF3;
TL1 = 0xF3;
TH1 = 0x20;
TMOD |= (1<<7);
PCON |= (1<<6) | (1<<4);
SCON |= (1<<7) | (1<<4);
IE
= 0x40;
TCON }
// associated header file
#include "Utils.h"
// including standard headers and portable datatypes
#include "8051.h"
#include <stdint.h>
#include "Constants.h"
#include "LCD.h"
void printHexByteToASCIIArray(uint8_t byte) {
(asciiLookup[((byte >> 4) & 0x0F)]);
printChar(asciiLookup[(byte & 0x0F)]);
printChar}
void printHexWordToASCIIArray(uint16_t word) {
(asciiLookup[((word >> 12) & 0x0F)]);
printChar(asciiLookup[((word >> 8) & 0x0F)]);
printChar(asciiLookup[((word >> 4) & 0x0F)]);
printChar(asciiLookup[(word & 0x0F)]);
printChar}
inline void iowrite8(uint8_t __xdata* map_address, uint8_t d) {
= 1;
IOM *map_address = d;
= 0;
IOM }
inline uint8_t ioread8(uint8_t __xdata* map_address)
{
uint8_t d;
= 1;
IOM = *map_address;
d = 0;
IOM return d;
}
#ifndef ADC_H
#define ADC_H
void adcMenu(void);
void adcPrint(void);
#endif
#ifndef CONSTANTS_H
#define CONSTANTS_H
#include <stdint.h>
extern __code char asciiLookup[17];
extern __code char menuCount;
extern __code char* menuOptions[8];
extern __code char blockSizeMenuCount;
extern __code char* blockSizeMenuOptions[4];
extern __code char blockSizeMenuButtons[4];
extern __code char segconvert[16];
#endif
#ifndef COUNT_H
#define COUNT_H
void count(void);
#endif
#ifndef DUMP_H
#define DUMP_H
#include "8051.h"
#include <stdint.h>
#include "Bool.h"
uint8_t dumpPage(uint16_t address, uint8_t byteCount, bool pagesBefore, bool pagesAfter);
void dump(void);
#endif
#ifndef EDIT_H
#define EDIT_H
#include <stdint.h>
uint8_t editPage(uint16_t address);
void edit(void);
#endif
#ifndef FIND_H
#define FIND_H
#include <stdint.h>
#include "Bool.h"
uint8_t findPage(uint16_t address, bool pagesBefore, bool pagesAfter);
void findArgs(uint16_t startAddress, uint16_t blockQuantity, uint8_t searchValue);
void find(void);
#endif
#ifndef KEYPAD_H
#define KEYPAD_H
#include "8051.h"
#include <stdint.h>
uint8_t checkRows(void);
uint8_t checkColumns(void);
uint8_t readKeypad(void);
uint8_t decodeKeypadToHex(uint8_t keypadIndex);
uint8_t waitForKeypad(void);
void waitForKey(uint8_t key);
uint8_t promptForByte(char* prompt);
uint16_t promptForWord(char* prompt);
void setSerialData(uint8_t data);
uint8_t getSerialData(void);
#endif
/* all the required header for project here*/
#ifndef LCD_H
#define LCD_H
#include <8051.h>
#include <stdint.h>
/* define any address for lcd for address decoding */
#define LCD_ADDRESS 0x4000
/* LCD specific variables */
#define TFTWIDTH 240
#define TFTHEIGHT 320
/* A good way to stay consistent with writing signals */
#define ACTIVE 0
#define IDLE 1
#define CMD 0
#define DATA 1
#define IO 1
#define MEM 0
/* LCD control pin interfacing. */
#define IOM P3_4
#define CD P3_5
/* definition of colors in 2-bytes*/
#define BLACK 0x0000
#define GRAY 0xD6BA
#define BLUE 0x001F
#define RED 0xF800
#define LIME 0x07E0
#define GREEN 0x0401
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
/*ILI9341 Registers*/
#define ILI9341_SOFTRESET 0x01
#define ILI9341_SLEEPIN 0x10
#define ILI9341_SLEEPOUT 0x11
#define ILI9341_NORMALDISP 0x13
#define ILI9341_INVERTOFF 0x20
#define ILI9341_INVERTON 0x21
#define ILI9341_GAMMASET 0x26
#define ILI9341_DISPLAYOFF 0x28
#define ILI9341_DISPLAYON 0x29
#define ILI9341_COLADDRSET 0x2A
#define ILI9341_PAGEADDRSET 0x2B
#define ILI9341_MEMORYWRITE 0x2C
#define ILI9341_PIXELFORMAT 0x3A
#define ILI9341_FRAMECONTROL 0xB1
#define ILI9341_DISPLAYFUNC 0xB6
#define ILI9341_ENTRYMODE 0xB7
#define ILI9341_POWERCONTROL1 0xC0
#define ILI9341_POWERCONTROL2 0xC1
#define ILI9341_VCOMCONTROL1 0xC5
#define ILI9341_VCOMCONTROL2 0xC7
#define ILI9341_MEMCONTROL 0x36
#define ILI9341_MADCTL 0x36
#define ILI9341_MADCTL_MY 0x80
#define ILI9341_MADCTL_MX 0x40
#define ILI9341_MADCTL_MV 0x20
#define ILI9341_MADCTL_ML 0x10
#define ILI9341_MADCTL_RGB 0x00
#define ILI9341_MADCTL_BGR 0x08
#define ILI9341_MADCTL_MH 0x04
//Prototypes!
void delay (int16_t d);
inline void lcdWrite8Reg(uint8_t d);
inline void lcdWrite8Data(uint8_t d);
inline void lcdWrite8DataBlocking(uint8_t d);
inline void lcdWriteRegData8(uint8_t a, uint8_t d);
void setCursorx(uint16_t x);
void setCursory(uint16_t y);
void lcdWriteRegData16(uint16_t a, uint16_t d);
void setCursor(uint16_t x, uint16_t y);
void setTextColor(uint16_t x, uint16_t y);
void setTextSize(uint8_t s);
void setRotation(uint8_t flag);
void setAddress(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2);
void initLCD(void);
void drawPixel(uint16_t x3,uint16_t y3,uint16_t color1);
void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
void fillRect(uint16_t x,uint16_t y,uint16_t w,uint16_t h,uint16_t color);
void fillScreen(void);
void drawChar(uint8_t c);
void printChar(uint8_t c);
void printString(char *str);
uint16_t reverse(uint8_t d);
void asciiToDec(uint8_t d);
void asciiToHex(uint8_t d);
uint16_t getCursorX(void);
uint16_t getCursorY(void);
uint8_t getTextSize(void);
void clearLCD(void);
void errorBackToMenu(char* message);
#endif
#ifndef MEMORY_H
#define MEMORY_H
#include "8051.h"
#include <stdint.h>
#include "Bool.h"
uint8_t readFromExternalAddress(uint16_t address);
void writeToExternalAddress(uint16_t address, uint8_t value);
uint16_t searchForwardForExternalValue(uint16_t address, uint8_t value, bool* success);
uint16_t searchBackwardForExternalValue(uint16_t address, uint8_t value, bool* success);
uint16_t countValueInRange(uint16_t startAddress, uint16_t endAddress, uint8_t value);
#endif
#ifndef MENU_H
#define MENU_H
#include <stdint.h>
void titleScreen(void);
void fryScreen(void);
uint8_t menu(void);
uint8_t blockSizeMenu(void);
#endif
#ifndef MOVE_H
#define MOVE_H
void move(void);
#endif
#ifndef RTC_H
#define RTC_H
#include <stdint.h>
#define RTC_ADDRESS 0x0000
#define __RTC_SECONDS_REG__ RTC_ADDRESS + (0x00 << 9)
#define __RTC_MINUTES_REG__ RTC_ADDRESS + (0x01 << 9)
#define __RTC_HOURS_REG__ RTC_ADDRESS + (0x02 << 9)
#define __RTC_DAYS_REG__ RTC_ADDRESS + (0x03 << 9)
#define __RTC_DATE_REG__ RTC_ADDRESS + (0x04 << 9)
#define __RTC_MONTH_REG__ RTC_ADDRESS + (0x05 << 9)
#define __RTC_YEAR_REG__ RTC_ADDRESS + (0x06 << 9)
#define __RTC_CENTURY_REG__ RTC_ADDRESS + (0x07 << 9)
#define __RTC_ALARM_SEC_REG__ RTC_ADDRESS + (0x08 << 9)
#define __RTC_ALARM_MIN_REG__ RTC_ADDRESS + (0x09 << 9)
#define __RTC_ALARM_HOUR_REG__ RTC_ADDRESS + (0x0A << 9)
#define __RTC_ALARM_DAY_REG__ RTC_ADDRESS + (0x0B << 9)
#define __RTC_WATCHDOG1_REG__ RTC_ADDRESS + (0x0C << 9)
#define __RTC_WATCHDOG2_REG__ RTC_ADDRESS + (0x0D << 9)
#define __RTC_CTRL_A_REG__ RTC_ADDRESS + (0x0E << 9)
#define __RTC_CTRL_B_REG__ RTC_ADDRESS + (0x0F << 9)
#define __RTC_RAM_ADDR_REG__ RTC_ADDRESS + (0x10 << 9)
#define __RTC_EXT_RAM_ADDR_REG__ RTC_ADDRESS + (0x13 << 9)
// Control A Register Values
#define __CTRLA_WDF_SET__ 0x02
#define __CTRLA_KSF_SET__ 0x04
#define __CTRLA_TDF_SET__ 0x08
#define __CTRLA_PAB_SET__ 0x10
#define __CTRLA_PRS_SET__ 0x20
// Control B Register Values
#define __CTRLB_WDS_SET__ 0x01
#define __CTRLB_WDE_SET__ 0x02
#define __CTRLB_KIE_SET__ 0x04
#define __CTRLB_TIE_SET__ 0x08
#define __CTRLB_TPE_SET__ 0x10
#define __CTRLB_BME_SET__ 0x20
#define __CTRLB_CS_SET__ 0x40
#define __CTRLB_TE_SET__ 0x80
//Month Control Bits
#define __MON_EOSC_SET__ 0x80
#define __MON_E32K_SET__ 0x40
#define __MON_BB32_SET__ 0x20
//Masks
#define __RTC_MONTH_MASK__ 0x1F
#define __RTC_DATE_MASK__ 0x3F
#define __RTC_SECONDS_MASK__ 0x7F
#define __RTC_MINUTES_MASK__ 0x7F
#define __RTC_HOURS_MASK__ 0x3F
#define __RTC_DAYS_MASK__ 0x07
#define __RTC_YEAR_MASK__ 0xFF
#define __RTC_CENTURY_MASK__ 0xFF
// void rtcInit(void);
uint8_t rtcBcdToAscii(uint8_t bcd);
uint8_t rtcAsciiToBcd(uint8_t ascii);
void rtcRegToLCD(uint8_t __xdata * reg, uint8_t mask);
void rtcPrint(void);
void rtcMenu(void);
#endif
#ifndef RAMCHECK_H
#define RAMCHECK_H
#include <stdint.h>
#include "Bool.h"
void writeAllRam(uint8_t value);
bool readAllRam(uint8_t value);
bool ramCheckCycle(uint8_t value);
void ramCheck(void);
#endif
#ifndef SEG_H
#define SEG_H
#define SEG_7_ADDRESS 0x8000
#include <stdint.h>
#include <8051.h>
void hexToSegment(uint8_t byte);
void loadingLoop(uint8_t count);
#endif
#ifndef SERIAL_H
#define SERIAL_H
#include <stdint.h>
#include "8051.h"
void serialInit(void);
#endif
#ifndef UTILS_H
#define UTILS_H
#include <stdint.h>
void printHexByteToASCIIArray(uint8_t byte);
void printHexWordToASCIIArray(uint16_t word);
char * hexByteToASCIIArray(uint8_t byte);
char* hexWordToASCIIArray(uint16_t word);
inline void iowrite8(uint8_t __xdata* map_address, uint8_t d);
inline uint8_t ioread8(uint8_t __xdata* map_address);
#endif
/****** INPUT PINS ******/
2 = iom;
PIN 3 = psen;
PIN 4 = wr;
PIN 5 = a15;
PIN 6 = a14;
PIN
/****** OUTPUT PINS ******/
19 = cs_rom1;
PIN 18 = cs_rom2;
PIN 17 = cs_ram1;
PIN 16 = cs_ram2;
PIN 15 = cs_adc;
PIN 14 = cs_lcd;
PIN 13 = cd_rtc;
PIN 12 = cs_seg;
PIN
= !(!psen & !iom & !a15);
cs_rom1 = !(!psen & !iom & a15);
cs_rom2 = !(psen & !iom & !a15);
cs_ram1 = !(psen & !iom & a15);
cs_ram2 = !(psen & iom & a15 & a14);
cs_adc = !(psen & iom & !a15 & a14);
cs_lcd = !(psen & iom & !a15 & !a14);
cd_rtc = (psen & iom & a15 & !a14 & !wr); cs_seg