mirror of
https://github.com/smartykit/apple1.git
synced 2025-01-15 02:29:59 +00:00
Merge branch 'master' of https://github.com/sparky62/apple1
This commit is contained in:
commit
813aa91de1
@ -4,10 +4,10 @@ SmartyKit Apple I replica drivers and software (http://www.smartykit.io/).
|
|||||||
All needed libraries included in repository in /Arduino/libraries
|
All needed libraries included in repository in /Arduino/libraries
|
||||||
|
|
||||||
## Keyboard Driver
|
## Keyboard Driver
|
||||||
Keyboard driver uses Arduino PS2Keyboard library.
|
Keyboard driver uses Arduino PS2KeyAdvanced library.
|
||||||
|
|
||||||
## Video Driver
|
## Video Driver
|
||||||
Video driver uses Arduino TVout library.
|
Video driver uses Arduino custom 2.8" TFT screen driver (based on Adafruit driver) and TV Terminal library.
|
||||||
|
|
||||||
## Software Emulator - POM 1
|
## Software Emulator - POM 1
|
||||||
POM 1 cross-platform emulator by Verhille Arnaud to test SmartyKit 1 ROM with software.
|
POM 1 cross-platform emulator by Verhille Arnaud to test SmartyKit 1 ROM with software.
|
||||||
|
@ -0,0 +1,183 @@
|
|||||||
|
/* SmartyKit 1 - 40 keys Keyboard driver v.1.0
|
||||||
|
* http://www.smartykit.io/
|
||||||
|
* Copyright (C) 2021, Sergey Panarin <sergey@smartykit.io>
|
||||||
|
*
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#undef DEBUG
|
||||||
|
|
||||||
|
const int KEYBOARD_ROWS = 4;
|
||||||
|
const int KEYBOARD_COLS = 10;
|
||||||
|
|
||||||
|
const int keyboardRowsPins[KEYBOARD_ROWS] = {A2, A3, A4, A5};
|
||||||
|
const int keyboardColsPins[KEYBOARD_COLS] = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
|
||||||
|
|
||||||
|
const int latchPin = 2;
|
||||||
|
const int clockPin = A1;
|
||||||
|
const int dataPin = A0;
|
||||||
|
|
||||||
|
const int keyReadyPin = 3;
|
||||||
|
static boolean BIT7flag = false;
|
||||||
|
|
||||||
|
const char cShift = char(0x80);
|
||||||
|
const char cEnter = char(0x0D);
|
||||||
|
const char cSpace = char(0x20);
|
||||||
|
const char cDelete = char(0x7F);
|
||||||
|
|
||||||
|
const unsigned char keyboard[KEYBOARD_ROWS][KEYBOARD_COLS] =
|
||||||
|
{
|
||||||
|
{'1','2','3','4','5','6','7','8','9','0',},
|
||||||
|
{'Q','W','E','R','T','Y','U','I','O','P',},
|
||||||
|
{'A','S','D','F','G','H','J','K','L', cEnter,},
|
||||||
|
{cShift,'Z','X','C','V','B','N', 'M',cSpace,cDelete,},
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char keyboardShift[KEYBOARD_ROWS][KEYBOARD_COLS] =
|
||||||
|
{
|
||||||
|
{'!','@','#','$','%','^','&','*','(',')',},
|
||||||
|
{'Q','{','}','[',']','\\','_','-','+','=',},
|
||||||
|
{'A','S','D','F','G',':',';','"','\'', cEnter,},
|
||||||
|
{cShift,'Z','<','>',',','.','?', '/',cSpace,cDelete,},
|
||||||
|
};
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// put your setup code here, to run once:
|
||||||
|
for (int i=0; i < KEYBOARD_ROWS; i++)
|
||||||
|
pinMode(keyboardRowsPins[i], INPUT_PULLUP);
|
||||||
|
for (int i=0; i < KEYBOARD_COLS; i++)
|
||||||
|
pinMode(keyboardColsPins[i], OUTPUT);
|
||||||
|
|
||||||
|
|
||||||
|
pinMode(keyReadyPin, OUTPUT);
|
||||||
|
digitalWrite(keyReadyPin, HIGH);
|
||||||
|
|
||||||
|
pinMode(latchPin, OUTPUT);
|
||||||
|
pinMode(clockPin, OUTPUT);
|
||||||
|
pinMode(dataPin, OUTPUT);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
digitalWrite(latchPin, LOW);
|
||||||
|
shiftOut(dataPin, clockPin, MSBFIRST, '1'); # hex code 0x31 = 0011.0001b
|
||||||
|
digitalWrite(latchPin, HIGH);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
// Read user input if available.
|
||||||
|
if (Serial.available()){
|
||||||
|
char c = Serial.read();
|
||||||
|
sendCharToKeyboardPort(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// put your main code here, to run repeatedly:
|
||||||
|
char c = getKey();
|
||||||
|
if(c)
|
||||||
|
{
|
||||||
|
if (c == cEnter)
|
||||||
|
Serial.println();
|
||||||
|
else
|
||||||
|
Serial.print(c);
|
||||||
|
|
||||||
|
sendCharToKeyboardPort(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char getKey()
|
||||||
|
{
|
||||||
|
char c = NULL;
|
||||||
|
bool bShift = getShift();
|
||||||
|
for (int j=0; j < KEYBOARD_COLS; j++)
|
||||||
|
{
|
||||||
|
scanCol(j, bShift);
|
||||||
|
for (int i=KEYBOARD_ROWS-1; i >= 0; i--) //start from bottom-left corner with SHIFT button
|
||||||
|
{
|
||||||
|
int val = digitalRead(keyboardRowsPins[i]);
|
||||||
|
if (val == 0)
|
||||||
|
{
|
||||||
|
c = keyboard[i][j];
|
||||||
|
if (c == cShift)
|
||||||
|
c = NULL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (bShift)
|
||||||
|
c = keyboardShift[i][j];
|
||||||
|
}
|
||||||
|
delay(150);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getShift()
|
||||||
|
{
|
||||||
|
bool bShift = false;
|
||||||
|
int shiftCol = 0; // first column
|
||||||
|
int shiftRow = KEYBOARD_ROWS-1; // A row
|
||||||
|
|
||||||
|
scanCol(shiftCol, false);
|
||||||
|
int val = digitalRead(keyboardRowsPins[shiftRow]);
|
||||||
|
if (val == 0)
|
||||||
|
bShift = true;
|
||||||
|
|
||||||
|
return bShift;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scanCol(int col, bool bShift)
|
||||||
|
{
|
||||||
|
if(bShift)
|
||||||
|
digitalWrite(keyboardColsPins[0], LOW);
|
||||||
|
|
||||||
|
for (int i=0; i < KEYBOARD_COLS; i++)
|
||||||
|
{
|
||||||
|
if (i == col)
|
||||||
|
digitalWrite(keyboardColsPins[i], LOW);
|
||||||
|
else
|
||||||
|
digitalWrite(keyboardColsPins[i], HIGH);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cpuReadsKeyboard(void)
|
||||||
|
{
|
||||||
|
KeyboardBIT7_Disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardBIT7_Enable()
|
||||||
|
{
|
||||||
|
digitalWrite(keyReadyPin, HIGH);
|
||||||
|
BIT7flag = true;
|
||||||
|
}
|
||||||
|
void KeyboardBIT7_Disable()
|
||||||
|
{
|
||||||
|
digitalWrite(keyReadyPin, LOW);
|
||||||
|
BIT7flag = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendCharToKeyboardPort(char c)
|
||||||
|
{
|
||||||
|
// while(BIT7flag == true) //wait untill the previous char is read by CPU
|
||||||
|
// delay(5);
|
||||||
|
|
||||||
|
digitalWrite(keyReadyPin, LOW);
|
||||||
|
digitalWrite(latchPin, LOW);
|
||||||
|
shiftOut(dataPin, clockPin, MSBFIRST, c);
|
||||||
|
digitalWrite(latchPin, HIGH);
|
||||||
|
delay(30);
|
||||||
|
digitalWrite(keyReadyPin, HIGH);
|
||||||
|
KeyboardBIT7_Enable();
|
||||||
|
}
|
@ -0,0 +1,517 @@
|
|||||||
|
/*
|
||||||
|
* multi-mode tv out terminal library for Arduino
|
||||||
|
*
|
||||||
|
* Dave Curran 2013-09-06
|
||||||
|
*
|
||||||
|
* Arduino Terminal Library - Dave Curran (www.tynemouthsoftware.co.uk)
|
||||||
|
* Concept and Microcontroller Firmware - Daryl Rictor, Grant Searle
|
||||||
|
*
|
||||||
|
* 2013-09-06 - V0.1 - Initial Release
|
||||||
|
* 2013-09-13 - V0.2 - Added 4 bit mode plus minor tidy up
|
||||||
|
* 2013-09-16 - V0.3 - Added I2C mode
|
||||||
|
* 2013-09-23 - V0.4 - I2C mode writing direct and bypassing Wire
|
||||||
|
* 2013-09-28 - V0.5 - Added font and graphics options
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Terminal.h"
|
||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
// ***************************************
|
||||||
|
// * CONSTRUCTORS
|
||||||
|
// ***************************************
|
||||||
|
|
||||||
|
// Initialise the display for 8 bit mode
|
||||||
|
// The pins can be any that are convenient.
|
||||||
|
Terminal::Terminal(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7, uint8_t avail, uint8_t ack)
|
||||||
|
{
|
||||||
|
// store pin numbers
|
||||||
|
_avail_pin = avail;
|
||||||
|
_ack_pin = ack;
|
||||||
|
|
||||||
|
_data_pins[0] = d0;
|
||||||
|
_data_pins[1] = d1;
|
||||||
|
_data_pins[2] = d2;
|
||||||
|
_data_pins[3] = d3;
|
||||||
|
_data_pins[4] = d4;
|
||||||
|
_data_pins[5] = d5;
|
||||||
|
_data_pins[6] = d6;
|
||||||
|
_data_pins[7] = d7;
|
||||||
|
|
||||||
|
// set pin modes
|
||||||
|
pinMode(_ack_pin, INPUT);
|
||||||
|
pinMode(_avail_pin, OUTPUT);
|
||||||
|
|
||||||
|
for(uint8_t i=0; i<8; i++)
|
||||||
|
{
|
||||||
|
pinMode(_data_pins[i], OUTPUT);
|
||||||
|
digitalWrite(_data_pins[i], LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
_4bit_mode = false;
|
||||||
|
_i2c_mode = false;
|
||||||
|
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise the display for 4 bit mode
|
||||||
|
// The pins can be any that are convenient. If using an Arduino, using pin 13 for ack will show activity
|
||||||
|
Terminal::Terminal(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t avail, uint8_t ack)
|
||||||
|
{
|
||||||
|
// store pin numbers
|
||||||
|
_avail_pin = avail;
|
||||||
|
_ack_pin = ack;
|
||||||
|
|
||||||
|
_data_pins[0] = d0;
|
||||||
|
_data_pins[1] = d1;
|
||||||
|
_data_pins[2] = d2;
|
||||||
|
_data_pins[3] = d3;
|
||||||
|
_data_pins[4] = 0;
|
||||||
|
_data_pins[5] = 0;
|
||||||
|
_data_pins[6] = 0;
|
||||||
|
_data_pins[7] = 0;
|
||||||
|
|
||||||
|
// set pin modes
|
||||||
|
pinMode(_ack_pin, INPUT);
|
||||||
|
pinMode(_avail_pin, OUTPUT);
|
||||||
|
|
||||||
|
for(uint8_t i=0; i<4; i++)
|
||||||
|
{
|
||||||
|
pinMode(_data_pins[i], OUTPUT);
|
||||||
|
digitalWrite(_data_pins[i], LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
_4bit_mode = true;
|
||||||
|
_i2c_mode = false;
|
||||||
|
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialise for I2C mode
|
||||||
|
Terminal::Terminal()
|
||||||
|
{
|
||||||
|
_4bit_mode = false;
|
||||||
|
_i2c_mode = true;
|
||||||
|
_transmitting = false;
|
||||||
|
|
||||||
|
DDRC |= 0x30; // set the two I2C pins as outputs
|
||||||
|
|
||||||
|
// Two wire speed initialisation
|
||||||
|
// SCL freq = CPU freq / (16+2*TWBR*Prescaler)
|
||||||
|
TWSR = 0; // Prescaler = 1
|
||||||
|
TWBR = 12; // Bit rate 12 = 400KHz for 16MHz clk
|
||||||
|
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ***************************************
|
||||||
|
// * Display control functions
|
||||||
|
// ***************************************
|
||||||
|
|
||||||
|
// Clear the screen
|
||||||
|
void Terminal::clear()
|
||||||
|
{
|
||||||
|
send(TERMINAL_CLEAR_SCREEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blink the cursor
|
||||||
|
void Terminal::cursorBlink()
|
||||||
|
{
|
||||||
|
send(TERMINAL_CURSOR_BLINKING);
|
||||||
|
}
|
||||||
|
|
||||||
|
// use a solid cursor
|
||||||
|
void Terminal::cursorBlinkOff()
|
||||||
|
{
|
||||||
|
send(TERMINAL_CURSOR_SOLID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change the cursor to a block
|
||||||
|
void Terminal::cursorBlock()
|
||||||
|
{
|
||||||
|
cursorCustom(0xDB);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change the cursor to an underscore (default)
|
||||||
|
void Terminal::cursorUnderscore()
|
||||||
|
{
|
||||||
|
cursorCustom('_');
|
||||||
|
}
|
||||||
|
|
||||||
|
// no cursor
|
||||||
|
void Terminal::cursorOff()
|
||||||
|
{
|
||||||
|
send(TERMINAL_CURSOR_SOLID);
|
||||||
|
cursorCustom(0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set any character as the cursor character, 0x00 for off
|
||||||
|
void Terminal::cursorCustom(uint8_t c)
|
||||||
|
{
|
||||||
|
send(TERMINAL_CURSOR_SET);
|
||||||
|
send(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the font (use combinations of TERMAIN_FONT_x
|
||||||
|
void Terminal::setFont(uint8_t c)
|
||||||
|
{
|
||||||
|
send(TERMINAL_SET_FONT);
|
||||||
|
send(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the cursor location
|
||||||
|
void Terminal::setCursor(uint8_t column, uint8_t row)
|
||||||
|
{
|
||||||
|
setColumn(column);
|
||||||
|
setRow(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set location to a given column
|
||||||
|
void Terminal::setColumn(uint8_t column)
|
||||||
|
{
|
||||||
|
send(TERMINAL_SET_COLUMN);
|
||||||
|
send(column);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set location to a given row
|
||||||
|
void Terminal::setRow(uint8_t row)
|
||||||
|
{
|
||||||
|
send(TERMINAL_SET_ROW);
|
||||||
|
send(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the CTRL+LF pair
|
||||||
|
void Terminal::sendCRLF()
|
||||||
|
{
|
||||||
|
send(TERMINAL_CARRIAGE_RETURN);
|
||||||
|
send(TERMINAL_LINE_FEED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ***************************************
|
||||||
|
// * Graphics functions
|
||||||
|
// ***************************************
|
||||||
|
|
||||||
|
// Set a pixel in 160x100 graphics - note any text on this line will be cleared
|
||||||
|
void Terminal::setPixel(uint8_t x, uint8_t y)
|
||||||
|
{
|
||||||
|
if (x<160 && y<100)
|
||||||
|
{
|
||||||
|
send(TERMINAL_SET_PIXEL);
|
||||||
|
send(x);
|
||||||
|
send(y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear a pixel in 160x100 graphics - note any text on this line will be cleared
|
||||||
|
void Terminal::clearPixel(uint8_t x, uint8_t y)
|
||||||
|
{
|
||||||
|
if (x<160 && y<100)
|
||||||
|
{
|
||||||
|
send(TERMINAL_CLEAR_PIXEL);
|
||||||
|
send(x);
|
||||||
|
send(y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw a line from x1,y1 to x2,y2
|
||||||
|
void Terminal::drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
|
||||||
|
{
|
||||||
|
int xdiff = x2 - x1;
|
||||||
|
int ydiff = y2 - y1;
|
||||||
|
int maxdiff = max(abs(xdiff),abs(ydiff));
|
||||||
|
for(int n=0; n<maxdiff; n++)
|
||||||
|
{
|
||||||
|
setPixel(x1 + xdiff*n/maxdiff, y1 + ydiff*n/maxdiff);
|
||||||
|
}
|
||||||
|
// set the final pixel in case of rounding errors
|
||||||
|
setPixel(x2, y2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear a line from x1,y1 to x2,y2
|
||||||
|
void Terminal::clearLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
|
||||||
|
{
|
||||||
|
int xdiff = x2 - x1;
|
||||||
|
int ydiff = y2 - y1;
|
||||||
|
int maxdiff = max(abs(xdiff),abs(ydiff));
|
||||||
|
for(int n=0; n<maxdiff; n++)
|
||||||
|
{
|
||||||
|
clearPixel(x1 + xdiff*n/maxdiff, y1 + ydiff*n/maxdiff);
|
||||||
|
}
|
||||||
|
// clear the final pixel in case of rounding errors
|
||||||
|
clearPixel(x2, y2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw the outline of a box with opposite corners at x1,y1 and x2,y2
|
||||||
|
void Terminal::drawBox(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
|
||||||
|
{
|
||||||
|
drawLine(x1,y1, x2,y1);
|
||||||
|
drawLine(x2,y1, x2,y2);
|
||||||
|
drawLine(x2,y2, x1,y2);
|
||||||
|
drawLine(x1,y2, x1,y1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw the filled box with opposite corners at x1,y1 and x2,y2
|
||||||
|
void Terminal::fillBox(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
|
||||||
|
{
|
||||||
|
uint8_t ymin = min(y1,y2);
|
||||||
|
uint8_t ymax = max(y1,y2);
|
||||||
|
for(int y=ymin; y<=ymax; y++)
|
||||||
|
{
|
||||||
|
drawLine(x1,y, x2,y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear the area of a box with opposite corners at x1,y1 and x2,y2
|
||||||
|
void Terminal::clearBox(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
|
||||||
|
{
|
||||||
|
uint8_t ymin = min(y1,y2);
|
||||||
|
uint8_t ymax = max(y1,y2);
|
||||||
|
for(int y=ymin; y<=ymax; y++)
|
||||||
|
{
|
||||||
|
clearLine(x1,y, x2,y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw the outline of a circle centred on x0,y0 with a radius of radius
|
||||||
|
void Terminal::drawCircle(uint8_t x0, uint8_t y0, uint8_t radius)
|
||||||
|
{
|
||||||
|
int8_t x = radius;
|
||||||
|
int8_t y = 0;
|
||||||
|
int8_t radiusError = 1-x;
|
||||||
|
|
||||||
|
while(x >= y)
|
||||||
|
{
|
||||||
|
setPixel(x + x0, y + y0);
|
||||||
|
setPixel(y + x0, x + y0);
|
||||||
|
setPixel(-x + x0, y + y0);
|
||||||
|
setPixel(-y + x0, x + y0);
|
||||||
|
setPixel(-x + x0, -y + y0);
|
||||||
|
setPixel(-y + x0, -x + y0);
|
||||||
|
setPixel(x + x0, -y + y0);
|
||||||
|
setPixel(y + x0, -x + y0);
|
||||||
|
|
||||||
|
y++;
|
||||||
|
if(radiusError<0)
|
||||||
|
radiusError+=2*y+1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x--;
|
||||||
|
radiusError+=2*(y-x+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill a circle centred on x0,y0 with a radius of radius
|
||||||
|
void Terminal::fillCircle(uint8_t x0, uint8_t y0, uint8_t radius)
|
||||||
|
{
|
||||||
|
for(int y=-radius; y<=radius; y++)
|
||||||
|
{
|
||||||
|
for(int x=-radius; x<=radius; x++)
|
||||||
|
{
|
||||||
|
if(x*x+y*y <= radius*radius)
|
||||||
|
{
|
||||||
|
setPixel(x0+x, y0+y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear a circle centred on x0,y0 with a radius of radius
|
||||||
|
void Terminal::clearCircle(uint8_t x0, uint8_t y0, uint8_t radius)
|
||||||
|
{
|
||||||
|
for(int y=-radius; y<=radius; y++)
|
||||||
|
{
|
||||||
|
for(int x=-radius; x<=radius; x++)
|
||||||
|
{
|
||||||
|
if(x*x+y*y <= radius*radius)
|
||||||
|
{
|
||||||
|
clearPixel(x0+x, y0+y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ***************************************
|
||||||
|
// * Send functions
|
||||||
|
// ***************************************
|
||||||
|
|
||||||
|
// Print a string with a linefeed at the end
|
||||||
|
void Terminal::printLine(String s)
|
||||||
|
{
|
||||||
|
print(s);
|
||||||
|
sendCRLF();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print a string
|
||||||
|
void Terminal::print(String s)
|
||||||
|
{
|
||||||
|
// send character by character
|
||||||
|
for(unsigned int n=0; n<s.length(); n++)
|
||||||
|
{
|
||||||
|
send(s[n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// send a single byte
|
||||||
|
uint8_t Terminal::send(uint8_t c)
|
||||||
|
{
|
||||||
|
if (_i2c_mode)
|
||||||
|
{
|
||||||
|
return sendI2C(c);
|
||||||
|
}
|
||||||
|
else if (_4bit_mode)
|
||||||
|
{
|
||||||
|
return send4Bit(c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return send8Bit(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ***************************************
|
||||||
|
// * 4 and 8 bit parallel send functions
|
||||||
|
// ***************************************
|
||||||
|
|
||||||
|
// Internal 4 bit send
|
||||||
|
uint8_t Terminal::send4Bit(uint8_t c)
|
||||||
|
{
|
||||||
|
uint8_t i=0;
|
||||||
|
|
||||||
|
// Should already be low, set just in case
|
||||||
|
digitalWrite(_avail_pin, LOW);
|
||||||
|
|
||||||
|
// Check to see if the acknowledge pin is low
|
||||||
|
// If not then wait until it is (the display processor will change to low when ready)
|
||||||
|
while (digitalRead(_ack_pin) == HIGH);
|
||||||
|
|
||||||
|
// Move the data into the appropriate output pins
|
||||||
|
// Start with the upper nibble
|
||||||
|
for(i=0; i<4; i++)
|
||||||
|
{
|
||||||
|
digitalWrite(_data_pins[i], bitRead(c, i + 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for a bit
|
||||||
|
asm volatile ("nop");
|
||||||
|
asm volatile ("nop");
|
||||||
|
asm volatile ("nop");
|
||||||
|
asm volatile ("nop");
|
||||||
|
|
||||||
|
// Flip the data avail bit to tell the display that high 4 bits are ready for display
|
||||||
|
digitalWrite(_avail_pin, HIGH);
|
||||||
|
|
||||||
|
// Check to see if the acknowledge pin is high
|
||||||
|
// If not then wait until it is (the display processor will change to high when ready)
|
||||||
|
while (digitalRead(_ack_pin) == LOW);
|
||||||
|
|
||||||
|
// Move the data into the appropriate output pins
|
||||||
|
// Now the lower nibble
|
||||||
|
for(i=0; i<4; i++)
|
||||||
|
{
|
||||||
|
digitalWrite(_data_pins[i], bitRead(c, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait a bit
|
||||||
|
asm volatile ("nop");
|
||||||
|
asm volatile ("nop");
|
||||||
|
asm volatile ("nop");
|
||||||
|
asm volatile ("nop");
|
||||||
|
|
||||||
|
// Flip the data avail bit to tell the display that low 4 bits are ready for display
|
||||||
|
digitalWrite(_avail_pin, LOW);
|
||||||
|
|
||||||
|
// success
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal 8 bit send
|
||||||
|
uint8_t Terminal::send8Bit(uint8_t c)
|
||||||
|
{
|
||||||
|
// Check to see if the acknowledge pin is the same as the data available pin
|
||||||
|
// If not then wait until it is (the display processor will change it to be the same when ready)
|
||||||
|
while (digitalRead(_avail_pin) != digitalRead(_ack_pin));
|
||||||
|
|
||||||
|
// Move the data into the appropriate output pins
|
||||||
|
for(uint8_t i=0; i<8; i++)
|
||||||
|
{
|
||||||
|
digitalWrite(_data_pins[i], bitRead(c, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flip the data avail bit to tell the display that there is a character/command ready for display
|
||||||
|
digitalWrite(_avail_pin, !digitalRead(_avail_pin));
|
||||||
|
|
||||||
|
// success
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ***************************************
|
||||||
|
// * I2C Functions
|
||||||
|
// ***************************************
|
||||||
|
|
||||||
|
// Two-wire interface definitions
|
||||||
|
#define TW_START 0x08
|
||||||
|
#define TW_MT_SLA_ACK 0x18
|
||||||
|
#define TW_MT_DATA_ACK 0x28
|
||||||
|
#define TW_WRITE 0
|
||||||
|
// this can be changed in the firmware
|
||||||
|
#define TWI_ADDRESS 0x01
|
||||||
|
|
||||||
|
uint8_t Terminal::sendI2C(uint8_t c)
|
||||||
|
{
|
||||||
|
uint8_t retCode = 0;
|
||||||
|
|
||||||
|
if (!_transmitting)
|
||||||
|
{
|
||||||
|
// send start
|
||||||
|
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
|
||||||
|
|
||||||
|
// wait for response (blocking)
|
||||||
|
while ((TWCR & (1<<TWINT))==0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
retCode = TWSR & 0xF8;
|
||||||
|
if (retCode != TW_START)
|
||||||
|
{
|
||||||
|
// ERROR
|
||||||
|
return retCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load SLA_W (address of display and low-write bit) into TWDR
|
||||||
|
TWDR = TW_WRITE | (TWI_ADDRESS << 1);
|
||||||
|
// Clear TWINT bit in TWCR to start transmission of address
|
||||||
|
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||||
|
|
||||||
|
// Wait for confirmation
|
||||||
|
while ((TWCR & (1<<TWINT))==0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
retCode=TWSR & 0xF8;
|
||||||
|
if (retCode != TW_MT_SLA_ACK)
|
||||||
|
{
|
||||||
|
// ERROR
|
||||||
|
return retCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
_transmitting = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the data
|
||||||
|
TWDR = c;
|
||||||
|
// Clear TWINT bit in TWCR to start transmission of data
|
||||||
|
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||||
|
|
||||||
|
// Wait
|
||||||
|
while ((TWCR & (1<<TWINT))==0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
retCode = TWSR & 0xF8;
|
||||||
|
if (retCode != TW_MT_DATA_ACK)
|
||||||
|
{
|
||||||
|
// ERROR
|
||||||
|
return retCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// success
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* multi-mode tv out terminal library for Arduino
|
||||||
|
*
|
||||||
|
* Dave Curran 2013-09-28
|
||||||
|
*
|
||||||
|
* Arduino Terminal Library - Dave Curran (www.tynemouthsoftware.co.uk)
|
||||||
|
* Concept and Microcontroller Firmware - Daryl Rictor, Grant Searle
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef Terminal_h
|
||||||
|
#define Terminal_h
|
||||||
|
|
||||||
|
#include <arduino.h>
|
||||||
|
|
||||||
|
// Control Codes
|
||||||
|
#define TERMINAL_CURSOR_HOME 0x01
|
||||||
|
#define TERMINAL_CURSOR_SET 0x02
|
||||||
|
#define TERMINAL_CURSOR_BLINKING 0x03
|
||||||
|
#define TERMINAL_CURSOR_SOLID 0x04
|
||||||
|
#define TERMINAL_SET_PIXEL 0x05
|
||||||
|
#define TERMINAL_CLEAR_PIXEL 0x06
|
||||||
|
#define TERMINAL_BACKSPACE 0x08
|
||||||
|
#define TERMINAL_TAB 0x09
|
||||||
|
#define TERMINAL_LINE_FEED 0x0A
|
||||||
|
#define TERMINAL_CLEAR_SCREEN 0x0C
|
||||||
|
#define TERMINAL_CARRIAGE_RETURN 0x0D
|
||||||
|
// Set column 0 to 79 (2nd uint8_t is the column number)
|
||||||
|
#define TERMINAL_SET_COLUMN 0x0E
|
||||||
|
// Set row 0 to 24 (2nd uint8_t is the row number)
|
||||||
|
#define TERMINAL_SET_ROW 0x0F
|
||||||
|
// Delete to the start of the line
|
||||||
|
#define TERMINAL_DELETE_BEFORE_LINE 0x10
|
||||||
|
// Delete to the end of the line
|
||||||
|
#define TERMINAL_DELETE_AFTER_LINE 0x11
|
||||||
|
// Delete to start of screen
|
||||||
|
#define TERMINAL_DELETE_BEFORE_PAGE 0x12
|
||||||
|
// Delete to end of screen
|
||||||
|
#define TERMINAL_DELETE_AFTER_PAGE 0x13
|
||||||
|
#define TERMINAL_SCROLL_UP 0x14
|
||||||
|
#define TERMINAL_SCROLL_DOWN 0x15
|
||||||
|
#define TERMINAL_SCROLL_LEFT 0x16
|
||||||
|
#define TERMINAL_SCROLL_RIGHT 0x17
|
||||||
|
#define TERMINAL_SET_FONT 0x18
|
||||||
|
|
||||||
|
// Treat next uint8_t as a character (to allow PC DOS char codes 1 to 31 to be displayed on screen)
|
||||||
|
#define TERMINAL_NEXT_IS_CHAR 0x1A
|
||||||
|
// ESC - reserved for ANSI sequences
|
||||||
|
#define TERMINAL_ESCAPE 0x1B
|
||||||
|
#define TERMINAL_CURSOR_RIGHT 0x1C
|
||||||
|
#define TERMINAL_CURSOR_LEFT 0x1D
|
||||||
|
#define TERMINAL_CURSOR_UP 0x1E
|
||||||
|
#define TERMINAL_CURSOR_DOWN 0x1F
|
||||||
|
|
||||||
|
#define TERMINAL_DELETE 0x7F
|
||||||
|
|
||||||
|
// font options
|
||||||
|
#define TERMINAL_FONT_40_CHAR 0x00
|
||||||
|
#define TERMINAL_FONT_80_CHAR 0x01
|
||||||
|
#define TERMINAL_FONT_NORMAL 0x00
|
||||||
|
#define TERMINAL_FONT_BOLD 0x02
|
||||||
|
#define TERMINAL_FONT_SINGLE_HEIGHT 0x00
|
||||||
|
#define TERMINAL_FONT_DOUBLE_HEIGHT 0x04
|
||||||
|
#define TERMINAL_FONT_GRAPHICS 0x80
|
||||||
|
|
||||||
|
#define TERMINAL_FONT_40_NORMAL_SINGLE 0x00
|
||||||
|
#define TERMINAL_FONT_80_NORMAL_SINGLE 0x01
|
||||||
|
#define TERMINAL_FONT_40_BOLD_SINGLE 0x02
|
||||||
|
#define TERMINAL_FONT_80_BOLD_SINGLE 0x03
|
||||||
|
#define TERMINAL_FONT_40_NORMAL_DOUBLE 0x04
|
||||||
|
#define TERMINAL_FONT_80_NORMAL_DOUBLE 0x05
|
||||||
|
#define TERMINAL_FONT_40_BOLD_DOUBLE 0x06
|
||||||
|
#define TERMINAL_FONT_80_BOLD_DOUBLE 0x07
|
||||||
|
|
||||||
|
class Terminal
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Terminal(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7, uint8_t avail, uint8_t ack);
|
||||||
|
Terminal(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t avail, uint8_t ack);
|
||||||
|
Terminal();
|
||||||
|
|
||||||
|
void begin();
|
||||||
|
void clear();
|
||||||
|
void cursorBlink();
|
||||||
|
void cursorBlinkOff();
|
||||||
|
void cursorUnderscore();
|
||||||
|
void cursorBlock();
|
||||||
|
void cursorOff();
|
||||||
|
void cursorCustom(uint8_t c);
|
||||||
|
void setFont(uint8_t c);
|
||||||
|
void setCursor(uint8_t column, uint8_t row);
|
||||||
|
void setColumn(uint8_t column);
|
||||||
|
void setRow(uint8_t row);
|
||||||
|
void setPixel(uint8_t x, uint8_t y);
|
||||||
|
void clearPixel(uint8_t x, uint8_t y);
|
||||||
|
void drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);
|
||||||
|
void clearLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);
|
||||||
|
void drawBox(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);
|
||||||
|
void fillBox(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);
|
||||||
|
void clearBox(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);
|
||||||
|
void drawCircle(uint8_t x0, uint8_t y0, uint8_t radius);
|
||||||
|
void fillCircle(uint8_t x0, uint8_t y0, uint8_t radius);
|
||||||
|
void clearCircle(uint8_t x0, uint8_t y0, uint8_t radius);
|
||||||
|
void sendCRLF();
|
||||||
|
void printLine(String s);
|
||||||
|
void print(String s);
|
||||||
|
uint8_t send(uint8_t c);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t send4Bit(uint8_t c);
|
||||||
|
uint8_t send8Bit(uint8_t c);
|
||||||
|
uint8_t sendI2C(uint8_t c);
|
||||||
|
|
||||||
|
uint8_t _data_pins[8]; // data outputs
|
||||||
|
uint8_t _avail_pin; // output, tell the display that new data is available
|
||||||
|
uint8_t _ack_pin; // input, the display acknowledges the input
|
||||||
|
bool _4bit_mode; // is the interface in 4 bit mode
|
||||||
|
bool _i2c_mode; // is this in I2C mode
|
||||||
|
bool _transmitting; // in the middle of an I2C packet
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user