mbedica Graphing Calculator
Purpose & Description
The purpose of this project is to create a Mathematica-type calculator on the mbed.
This project is meant to take keyboard input for mathematical functions, display the input on a VGA screen, parse the input, evaluate the answer, and graph and print the result. Presently, this program does not parse inputs and thus does not return the output. The LEDs on the mbed will light up as follows:
- LED1: blinks on and off when the program is running.
- LED2: is on when the keyboard is connected (if it is off, disconnect and reconnect the keyboard).
- LED3: is on when processing keyboard input. I will also rapidly blink during bitmap processing.
- LED4: cycles when drawing on the VGA.
Function Parser
This originally used Bison and Flex(both tools to make compilers). Flex lexes (tags) tokens such as +,-,digits, and letters. Bison uses rules to write a tree which sits on a doubly linked list. It uses reverse post-order traversal: right sibling, left sibling, parent. Upon reaching a parent node, a function is evaluated and the parent node is replaced with that value. Bison needs Unix structures and would not fully run on the MBED, so the lexer and parser had to be re-written by hand.
VGA
On the left side of the screen, it will display the user input and result of the input. The screen is then divided by a red line, then the right side will display a graph on the function. Since VGA is slow, this graph will take time to complete. Also due to the speed of the display, the input characters are not displayed as they are typed, but rather once the user hits the enter key.
Thermal Printer
The printer prints every line that is input by keyboard, and can also print graphs that are displayed on the VGA display or the uLCD. Reading from the uLCD is much faster than the VGA, so we print each graph on both the VGA display and the uLCD, and read from the uLCD to print. To print, we read each pixel from the uLCD and store the result (0 for background, 1 for anything else) in bitmap format that the printer is able to read.
Parts List
- mbed LPC1768
- uLCD
- uVGA III
- Thermal Printer
- USB female connector
- USB keyboard
- 2 x 15k resistors (10k will work)
Pinout
mbed | uVGA | Thermal Printer | USB Keyboard | uLCD | External 5V |
---|---|---|---|---|---|
GND | GND | GND | GND | GND | GND |
- | - | VH | 5V | 5V | 5V |
Vu | 5V | - | - | - | - |
p9 | RX | - | - | - | - |
p10 | TX | - | - | - | - |
p11 | Reset | - | - | - | - |
p12 | - | - | - | Reset | - |
p13 | - | - | - | RX | - |
p14 | - | - | - | TX | - |
D+ | - | - | D+ | - | - |
D- | - | - | D- | - | - |
p27 | - | TX | - | - | - |
p28 | - | RX | - | - | - |
Hardware Diagram
USB Female Pinout
uVGA Pinout
Thermal Printer Pinout
Results
Future Work
- Implement function parsing
- Balance thread times for increased performance
- Optimize bitmap processing time
- Update libraries for compatibility with newer RTOS
Program
Information
These are not the most up to date libraries; they are from 2013. They do not use modern rtos, and the libraries had to be modified for compatibility.
Information
The uLCD library may not correctly import with the rest of the code, so that maybe need to be imported manually:
Import programmbedica
Mathematica-like environment on the mbed using USB keyboard input, VGA output, and a thermal printer.
main.cpp
#include "mbed.h" #include "Thermal.h" #include "uLCD_4DGL.h" #include "USBHostKeyboard.h" #include "uVGAIII.h" extern "C" struct node* scanner(const char* es); extern "C" float eval_expr(struct node* node, float x_value); #include <math.h> #define SIZE_X 480 #define SIZE_Y 800 // Debugging LEDs DigitalOut led(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); DigitalOut led4(LED4); uVGAIII ecran(p9,p10,p11); // serial tx, serial rx, reset pin; uLCD_4DGL uLCD(p13,p14,p12); // serial tx, serial rx, reset pin; Thermal printer(p28, p27, 19200); // Variables to track cursor location on VGA int verticalCursor = 2; int horizontalCursor = 0; // Variables to hold user input & index char currentLine[48]; int currentLineIndex = 0; // Variables to track graph bitmaps unsigned char bitmap[5000]; char temp[8]; // Mutexes for displays Mutex VGA_Lock; Mutex LCD_Lock; char getPixel(int x, int y, int bk) { LCD_Lock.lock(); int r = uLCD.read_pixel(x, y); LCD_Lock.unlock(); if (r == bk) //same as background return '0'; else return '1'; } void makeBitmap() { LCD_Lock.lock(); int bk = uLCD.read_pixel(127,127); LCD_Lock.unlock(); for (int i = 0; i < 128*128/8; ++i) { for (int j = 0; j < 8; ++j) { //get next 8 bits and put them in temp array //temp[2*j] = getPixel((i%32)*4+j,i/32,bk); //temp[2*j+1] = temp[2*j]; temp[j] = getPixel((i%16)*8+j,i/16,bk); } //need to convert to 0b format char * end; long int value = strtol(temp, &end, 2); //bitmap[64*(i/32)+(i%32)] = value; //bitmap[64*(i/32)+(i%32)+32] = value; bitmap[i] = value; led3 = !led3; } //printer.printf(bitmap); //printer.justify('C'); printer.printBitmap(128,128,bitmap); printer.feed(2); } // hardcode plot x^2 void plotx2() { LCD_Lock.lock(); uLCD.cls(); int xOffset = 0; int yOffset = 127; int pastX = 0; int pastY = 127; int currentX = 0; int currentY = 0; for(double i = 0; i < 11; i++) { //evaluate(); currentX = i*10 + xOffset; currentY = yOffset-(i*i); if(pastX == 0){ pastX = currentX; pastY = currentY; continue; } uLCD.line(pastX, pastY, currentX, currentY, RED); uLCD.line(pastX, pastY+1, currentX, currentY+1, RED); uLCD.line(pastX, pastY-1, currentX, currentY-1, RED); pastX = currentX; pastY = currentY; } LCD_Lock.unlock(); } void plotsin() { LCD_Lock.lock(); uLCD.cls(); int xOffset = 0; int yOffset = 64; int pastX = 0; int pastY = 64; int currentX = 0; int currentY = 0; for(double i = 0; i < 7; i+=.01) { //evaluate(); currentX = i*16 + xOffset; currentY = yOffset-40*sin(i); if(pastX == 0){ pastX = currentX; pastY = currentY; continue; } uLCD.line(pastX, pastY, currentX, currentY, RED); uLCD.line(pastX, pastY+1, currentX, currentY+1, RED); uLCD.line(pastX, pastY-1, currentX, currentY-1, RED); pastX = currentX; pastY = currentY; } LCD_Lock.unlock(); } void plotx2vga(void const *) { int xOffset = 600; int yOffset = 401; int pastX = 0; int pastY = 0; int currentX = 0; int currentY = 0; VGA_Lock.lock(); for(double i = -20; i < 21; i++) { led4 = !led4; //evaluate(); // Where evaluate would go...if we could parse input currentX = i*9 + xOffset; currentY = yOffset-(i*i); if(pastX == 0){ pastX = currentX; pastY = currentY; continue; } ecran.line(pastX, pastY, currentX, currentY, RED); pastX = currentX; pastY = currentY; } VGA_Lock.unlock(); while(1) { Thread::wait(500); } } void onKeyCode(uint8_t key, uint8_t modifier) { led3 = 1; // Skip spaces, empty spaces if(key == 0 || key == 0x20) { led3 = 0; return; } VGA_Lock.lock(); // Handle newline if(key == 0x0A) { // Check if going off end of screen if(verticalCursor > 37) { ecran.filled_rectangle(0, 0 , 399, 480, DGREY); verticalCursor = 0; } else { // Move cursor to newline verticalCursor+=2; } horizontalCursor = 0; ecran.move_cursor(verticalCursor, horizontalCursor); ecran.puts(currentLine); printer.printf(currentLine); printer.feed(2); struct node* expr = scanner(currentLine); float val = eval_expr(expr, 3.0); uLCD.printf("Evaluate: %f \n",val); for(size_t i = 0; i < 48; i++) { currentLine[i] = NULL; } currentLineIndex = 0; VGA_Lock.unlock(); led3 = 0; return; } if(key == 0x08) { if(currentLineIndex != 0) { currentLineIndex--; currentLine[currentLineIndex] = NULL; } led3 = 0; VGA_Lock.unlock(); return; } // Append character to curret line string currentLine[currentLineIndex] = (char)key; if(currentLineIndex < 47) { currentLineIndex++; } VGA_Lock.unlock(); led3 = 0; } void keyboard_task(void const *) { USBHostKeyboard keyboard; while(1) { // try to connect a USB keyboard while(!keyboard.connect()) { Thread::wait(200); } if(keyboard.connected()) led2 = 1; // When connected, attach handler called on keyboard event keyboard.attach(onKeyCode); // Wait until the keyboard is disconnected while(keyboard.connected()) Thread::wait(500); led2 = 0; } } int main() { led = 1; // Set up uLCD uLCD.baudrate(300000); uLCD.background_color(BLACK); // Set up VGA display ecran.baudrate(300000); ecran.screen_mode(LANDSCAPE); ecran.graphics_parameters(RESOLUTION, 2); ecran.touch_status(); ecran.background_color(DGREY); ecran.cls(); ecran.move_cursor(0, 0); ecran.char_width('d'); ecran.char_height('d'); ecran.text_fgd_color(WHITE); ecran.text_bgd_color(DGREY); ecran.puts("Booting up..."); ecran.filled_rectangle(398,0,402,480,RED); // Use old style threading Thread keyboardTask(keyboard_task, NULL, osPriorityNormal, 256 * 4); // Launch VGA plot through thread Thread vgaPlot(plotx2vga, NULL, osPriorityNormal, 256 * 4); plotx2(); makeBitmap(); led3 = 1; plotsin(); makeBitmap(); led3 = 1; // Clear currentLine array before using for(size_t i = 0; i < 48; i++) { currentLine[i] = NULL; } VGA_Lock.lock(); ecran.move_cursor(2, 0); ecran.puts("Ready!"); VGA_Lock.unlock(); static const char es[] = "1 + 2 ^ 3 * 4 + 5 * x"; struct node* expr = scanner(es); float val = eval_expr(expr, 3.0); while(1) { led=!led; Thread::wait(600); // Wait .6s in main thread } }
Team Members
Spencer Bongiovi, Zachary Russell, Rodrigo Alarcon, Yehowshua Immanuel
Please log in to post comments.