From 329532273820f1574d859c6bae714ff0610ada13 Mon Sep 17 00:00:00 2001 From: Yves Ehrlich Date: Tue, 28 Jan 2020 12:00:43 +0100 Subject: [PATCH] alle relevanten Libs added --- Code/libraries/MX1508/LICENSE | 21 ++ Code/libraries/MX1508/MX1508.cpp | 100 ++++++ Code/libraries/MX1508/MX1508.h | 39 +++ Code/libraries/MX1508/README.md | 4 + .../16bitResolutionPWM/16bitResolutionPWM.ino | 68 +++++ .../examples/exampleMX1508/exampleMX1508.ino | 44 +++ Code/libraries/MX1508/keywords.txt | 26 ++ Code/libraries/MX1508/library.properties | 10 + .../PCD8544SPIbenchmark.ino | 112 +++++++ Code/libraries/PCD8544_SPI/PCD8544_SPI.cpp | 152 ++++++++++ Code/libraries/PCD8544_SPI/PCD8544_SPI.h | 242 +++++++++++++++ Code/libraries/PCD8544_SPI/PCD8544_SPI_FB.cpp | 284 ++++++++++++++++++ Code/libraries/PCD8544_SPI/keywords.txt | 45 +++ Code/libraries/PCD8544_SPI/license.txt | 25 ++ Code/libraries/myInterrupts/keywords.txt | 32 ++ Code/libraries/myInterrupts/myInterrupts.cpp | 97 ++++++ Code/libraries/myInterrupts/myInterrupts.h | 22 ++ Code/libraries/shiftRegButtonLib/keywords.txt | 50 +++ .../shiftRegButtonLib/shiftRegButtonLib.cpp | 87 ++++++ .../shiftRegButtonLib/shiftRegButtonLib.h | 86 ++++++ 20 files changed, 1546 insertions(+) create mode 100644 Code/libraries/MX1508/LICENSE create mode 100644 Code/libraries/MX1508/MX1508.cpp create mode 100644 Code/libraries/MX1508/MX1508.h create mode 100644 Code/libraries/MX1508/README.md create mode 100644 Code/libraries/MX1508/examples/16bitResolutionPWM/16bitResolutionPWM.ino create mode 100644 Code/libraries/MX1508/examples/exampleMX1508/exampleMX1508.ino create mode 100644 Code/libraries/MX1508/keywords.txt create mode 100644 Code/libraries/MX1508/library.properties create mode 100644 Code/libraries/PCD8544_SPI/Examples/PCD8544SPIbenchmark/PCD8544SPIbenchmark.ino create mode 100644 Code/libraries/PCD8544_SPI/PCD8544_SPI.cpp create mode 100644 Code/libraries/PCD8544_SPI/PCD8544_SPI.h create mode 100644 Code/libraries/PCD8544_SPI/PCD8544_SPI_FB.cpp create mode 100644 Code/libraries/PCD8544_SPI/keywords.txt create mode 100644 Code/libraries/PCD8544_SPI/license.txt create mode 100644 Code/libraries/myInterrupts/keywords.txt create mode 100644 Code/libraries/myInterrupts/myInterrupts.cpp create mode 100644 Code/libraries/myInterrupts/myInterrupts.h create mode 100644 Code/libraries/shiftRegButtonLib/keywords.txt create mode 100644 Code/libraries/shiftRegButtonLib/shiftRegButtonLib.cpp create mode 100644 Code/libraries/shiftRegButtonLib/shiftRegButtonLib.h diff --git a/Code/libraries/MX1508/LICENSE b/Code/libraries/MX1508/LICENSE new file mode 100644 index 0000000..cb93db3 --- /dev/null +++ b/Code/libraries/MX1508/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Cheng Saetern + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Code/libraries/MX1508/MX1508.cpp b/Code/libraries/MX1508/MX1508.cpp new file mode 100644 index 0000000..5572386 --- /dev/null +++ b/Code/libraries/MX1508/MX1508.cpp @@ -0,0 +1,100 @@ +#include "MX1508.h" + +MX1508::MX1508( uint8_t pinIN1, uint8_t pinIN2) { + _pinIN1 = pinIN1; // always a PWM pin + _pinIN2 = pinIN2; // can be a non-Pwm pin. + _whichMode = FAST_DECAY; + _numPwmPins = PWM_2PIN; + pinMode(_pinIN1, OUTPUT); + pinMode(_pinIN2, OUTPUT); +} + +MX1508::MX1508( uint8_t pinIN1, uint8_t pinIN2, DecayMode decayMode, NumOfPwmPins numPins) { + _pinIN1 = pinIN1; // always a PWM pin + _pinIN2 = pinIN2; // can be a non-Pwm pin. + _whichMode = decayMode; + _numPwmPins = numPins; + pinMode(_pinIN1, OUTPUT); + pinMode(_pinIN2, OUTPUT); +} + +int MX1508::getPWM() { + return _pwmVal; +} + +void MX1508::stopMotor() { + digitalWrite(_pinIN1, LOW); + digitalWrite(_pinIN2, LOW); +} + +void MX1508::setResolution(unsigned int pwmResolution) { + _pwmResolution = pwmResolution; + if(_useAnalogWrite16) ICR1 = pwmResolution; +} + +void MX1508::setPWM16(uint8_t prescaler, unsigned int resolution){ + if(prescaler > 5 || prescaler == 0) prescaler = 3; // default to 64 if not in range. + DDRB |= _BV(PB1) | _BV(PB2); /* set pin 9and 10 as outputs */ + TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM11); // non-inverting PWM, mode 14 fastPWM, TOP =ICR1 + TCCR1B = _BV(WGM13) | _BV(WGM12) | prescaler ; // rescaler must be 1->5, 1,8,64,256,1028 respectively + ICR1 = resolution; + _pwmResolution = resolution; + _useAnalogWrite16 = true; +} + +void MX1508::analogWrite16(uint8_t pin, uint16_t val) +{ + if(_useAnalogWrite16){ + if(val < 5) val =5; + switch (pin) { + case 9: OCR1A = val; break; + case 10: OCR1B = val; break; + default: analogWrite(pin,val); + } + }else{ + analogWrite(pin, val); + } +} + +void MX1508::motorGo(long pwmSpeed) { + _pwmVal = pwmSpeed; + if(pwmSpeed == 0) { + this->stopMotor(); + } else { + // if set decay mode is set as fast decay mode + if (this->_whichMode == FAST_DECAY) { + if (pwmSpeed >= 0) { //forward fast decay + if(_numPwmPins == PWM_1PIN)digitalWrite(_pinIN2, LOW); + else analogWrite16(_pinIN2, 1); + analogWrite16(_pinIN1, pwmSpeed); + } else if (this->_numPwmPins == PWM_2PIN) { // reverse fast decay + pwmSpeed *= -1; + analogWrite16(_pinIN1, 1); + analogWrite16(_pinIN2, pwmSpeed); + } else if (this->_numPwmPins == PWM_1PIN) { // reverse slow decay + pwmSpeed *= -1; + pwmSpeed = map(pwmSpeed, 0, _pwmResolution, _pwmResolution, 0); + digitalWrite(_pinIN2, HIGH); + analogWrite16(_pinIN1, pwmSpeed); + } + } + // if decay mode is set as slow decay mode + else { + if (pwmSpeed >= 0) { // forward slow decay + pwmSpeed = map(pwmSpeed, 0, _pwmResolution, _pwmResolution, 0); + if(_numPwmPins == PWM_1PIN)digitalWrite(_pinIN1, HIGH); + else analogWrite16(_pinIN1, _pwmResolution); + analogWrite16(_pinIN2, pwmSpeed); + } else if (this->_numPwmPins == PWM_2PIN) { // reverse slow decay + pwmSpeed *= -1; + pwmSpeed = map(pwmSpeed, 0, _pwmResolution, _pwmResolution, 0); + analogWrite16(_pinIN2, _pwmResolution); + analogWrite16(_pinIN1, pwmSpeed); + } else if (this->_numPwmPins == PWM_1PIN) { // reverse fast decay + pwmSpeed *= -1; + digitalWrite(_pinIN1, LOW); + analogWrite16(_pinIN2, pwmSpeed); + } + } +} +} diff --git a/Code/libraries/MX1508/MX1508.h b/Code/libraries/MX1508/MX1508.h new file mode 100644 index 0000000..02aaa18 --- /dev/null +++ b/Code/libraries/MX1508/MX1508.h @@ -0,0 +1,39 @@ +#ifndef MX1508_h +#define MX1508_h + +#include "Arduino.h" + +typedef enum +{ + FAST_DECAY = 0, // set non-PWM pin low + SLOW_DECAY = 1 // set non-PWM pin high +} DecayMode; + +typedef enum +{ + PWM_1PIN = 1, + PWM_2PIN = 2 +} NumOfPwmPins; + +class MX1508 { + public: + MX1508(uint8_t pinIN1, uint8_t pinIN2); // default fast decay, 2 pwm pins + MX1508(uint8_t pinIN1, uint8_t pinIN2, DecayMode decayMode, NumOfPwmPins numPWM); + void motorGo(long pwmVal); // + void setResolution(unsigned int resolution); + int getPWM(); + void stopMotor(); + void analogWrite16(uint8_t pin, uint16_t val); + void setPWM16(uint8_t prescaler, unsigned int resolution); + private: + + uint8_t _pinIN1; + uint8_t _pinIN2; + bool _useAnalogWrite16 = false; + int _pwmVal; + int _pwmResolution = 255; //max resolution of pwm, default is 255. + DecayMode _whichMode; + NumOfPwmPins _numPwmPins; +}; + +#endif diff --git a/Code/libraries/MX1508/README.md b/Code/libraries/MX1508/README.md new file mode 100644 index 0000000..3b1e0ad --- /dev/null +++ b/Code/libraries/MX1508/README.md @@ -0,0 +1,4 @@ +# MX1508 +Arduino library for MX1508 dual DC motor driver + +This motor driver is only ideal for low power applications(Motors that draws less that 1.5A). diff --git a/Code/libraries/MX1508/examples/16bitResolutionPWM/16bitResolutionPWM.ino b/Code/libraries/MX1508/examples/16bitResolutionPWM/16bitResolutionPWM.ino new file mode 100644 index 0000000..0e026ca --- /dev/null +++ b/Code/libraries/MX1508/examples/16bitResolutionPWM/16bitResolutionPWM.ino @@ -0,0 +1,68 @@ + +/* + * Created by: Cheng Saetern + * This example is meant to demonstrate the ability to adjust pwm frequency and/or + * resolution for Arduino Nano/Uno pin 9 and 10 using function setPWM16(uint8_t prescaler, unsigned int resolution). + * Equation for fast pwm frequency = frequency of MPU(16Mhz)/prescaler/resolution + * F_PWM = 16000000/prescaler/resolution. + * prescaler argument value MUST be between 1-5, representing 1,8,64,256,1024 respectively. + * resolution MUST be a value from 0-65535. + */ + +#include + +#define PINA 9 +#define PINB 10 +#define NUMPWM 2 +// MX1508 schematics(in Chinese) can be found here at: http://sales.dzsc.com/486222.html +/* + * MX1508(uint8_t pinIN1, uint8_t pinIN2, DecayMode decayMode, NumOfPwmPins numPWM); + * DecayMode must be FAST_DECAY or SLOW_DECAY, + * NumOfPwmPins, must be the value of 2 for setPWM16() function + * PINA and PINB MUST!!! be pin 9 and 10 for setPWM16() function + * Example MX1508 myMotor(10,9,FAST_DECAY, 2). + */ +MX1508 motorA(PINA,PINB, FAST_DECAY, 2); + +int resolution = 1000; +void setup() { + Serial.begin(115200); + + motorA.setPWM16(2,resolution); // prescaler at 8, resolution 1000, PWM frequency = 16Mhz/8/1000=2000Hz + // prescalar 1=1, 2=8, 3=64, 4=256, 5 =1028 + /*------------ setPWM16 Class function is defined as below----------------- + void MX1508::setPWM16(uint8_t prescaler, unsigned int resolution){ + if(prescaler > 5 || prescaler == 0) prescaler = 3; // default to 64 if not in range. + DDRB |= _BV(PB1) | _BV(PB2); // set pin 9and 10 as outputs + TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM11); // non-inverting PWM, mode 14 fastPWM, TOP =ICR1 + TCCR1B = _BV(WGM13) | _BV(WGM12) | prescaler ; + ICR1 = resolution; + _pwmResolution = resolution; + _useAnalogWrite16 = true; + } + */ +} +/* + * Ramp up to pwm = resolution/2 , by increasing pwm by 1 every 50 millisecond. + * then ramp down to pwm = -resolution/2, by decreasing pwm every 50 millisecond. + * positive value pwm results in forward direction. + * negative value pwm results in opposite direction. + */ +void loop() { + // put your main code here, to run repeatedly: + static unsigned long lastMilli = 0; + static bool cwDirection = true; // assume initial direction(positive pwm) is clockwise + static int pwm = 1; + + if(millis()-lastMilli > 50){ // every 50 millisecond + if (cwDirection && pwm++ > resolution/2 ) { + cwDirection = false; + } else if (!cwDirection && pwm-- < -(resolution/2)) { + cwDirection = true; + } + motorA.motorGo(pwm); + lastMilli = millis(); + Serial.println(motorA.getPWM()); // we can just print pwm but just showing that member function getPWM() works. + } + +} diff --git a/Code/libraries/MX1508/examples/exampleMX1508/exampleMX1508.ino b/Code/libraries/MX1508/examples/exampleMX1508/exampleMX1508.ino new file mode 100644 index 0000000..2ea9f24 --- /dev/null +++ b/Code/libraries/MX1508/examples/exampleMX1508/exampleMX1508.ino @@ -0,0 +1,44 @@ + +#include + +#define PINA 9 +#define PINB 10 +#define NUMPWM 2 +// MX1508 schematics(in Chinese) can be found here at: http://sales.dzsc.com/486222.html +/* + * MX1508(uint8_t pinIN1, uint8_t pinIN2, DecayMode decayMode, NumOfPwmPins numPWM); + * DecayMode must be FAST_DECAY or SLOW_DECAY, + * NumOfPwmPins, either use 1 or 2 pwm. + * I recommend using 2 pwm pins per motor so spinning motor forward and backward gives similar response. + * if using 1 pwm pin, make sure its pinIN1, then set pinIN2 to any digital pin. I dont recommend this setting because + * we need to use FAST_DECAY in one direction and SLOW_DECAY for the other direction. + */ +MX1508 motorA(PINA,PINB, FAST_DECAY, NUMPWM); + +void setup() { + Serial.begin(115200); +} +/* + * Ramp up to pwm = 100, by increasing pwm by 1 every 50 millisecond. + * then ramp down to pwm = -100, by decreasing pwm every 50 millisecond. + * positive value pwm results in forward direction. + * negative value pwm results in opposite direction. + */ +void loop() { + // put your main code here, to run repeatedly: + static unsigned long lastMilli = 0; + static bool cwDirection = true; // assume initial direction(positive pwm) is clockwise + static int pwm = 1; + + if(millis()-lastMilli > 50){ // every 50 millisecond + if (cwDirection && pwm++ > 100 ) { + cwDirection = false; + } else if (!cwDirection && pwm-- < -100) { + cwDirection = true; + } + motorA.motorGo(pwm); + lastMilli = millis(); + Serial.println(motorA.getPWM()); // we can just print pwm but just showing that member function getPWM() works. + } + +} diff --git a/Code/libraries/MX1508/keywords.txt b/Code/libraries/MX1508/keywords.txt new file mode 100644 index 0000000..dc74352 --- /dev/null +++ b/Code/libraries/MX1508/keywords.txt @@ -0,0 +1,26 @@ +####################################### +# Syntax Coloring Map For MX1508 Library +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +MX1508 KEYWORD1 +DecayMode KEYWORD1 +NumOfPWMPins KEYWORD1 + + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +motorGo KEYWORD2 +setResolution KEYWORD2 +getPWM KEYWORD2 +stopMotor KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/Code/libraries/MX1508/library.properties b/Code/libraries/MX1508/library.properties new file mode 100644 index 0000000..bfe9c23 --- /dev/null +++ b/Code/libraries/MX1508/library.properties @@ -0,0 +1,10 @@ +name=MX1508 +version=1.0.0 +author=Cheng Saetern +maintainer=Cheng Saetern +sentence=A library that makes using mx1508 dual DC motor driver easier. +paragraph=I know how very little resource there are on this motor driver. A lot of sellers assume this IC is l298N but its rather much more like pololu DDRV8833. +category=Device Control +url=https://github.com/Saeterncj/MX1508 +architectures=avr +includes=MX1508.h diff --git a/Code/libraries/PCD8544_SPI/Examples/PCD8544SPIbenchmark/PCD8544SPIbenchmark.ino b/Code/libraries/PCD8544_SPI/Examples/PCD8544SPIbenchmark/PCD8544SPIbenchmark.ino new file mode 100644 index 0000000..d89835f --- /dev/null +++ b/Code/libraries/PCD8544_SPI/Examples/PCD8544SPIbenchmark/PCD8544SPIbenchmark.ino @@ -0,0 +1,112 @@ +#include +#include "PCD8544_SPI.h" + +#define USE_FRAME_BUFFER + +#ifdef USE_FRAME_BUFFER +PCD8544_SPI_FB lcd; +#else +PCD8544_SPI lcd; +#endif + +void setup(void) +{ + Serial.begin(9600); + lcd.begin(); + lcd.print(F("Preparing benchmark")); +#ifdef USE_FRAME_BUFFER + lcd.renderAll(); +#endif + delay(1000); +} + +uint8_t bmp[] = { + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, +}; + +void loop(void) +{ + size_t len; + + lcd.clear(); + unsigned long time = micros(); + len = lcd.print(F("012345678901234567890123456789012345678901234567890123456789012345678901234567890123")); +#ifdef USE_FRAME_BUFFER + lcd.renderString(0, 0, len); +#endif + time = micros() - time; + delay(3000); + + lcd.clear(); + lcd.print(F("The time it took to print 84 chars is: ")); + lcd.print(time); +#ifdef USE_FRAME_BUFFER + lcd.renderAll(); +#endif + delay(3000); + + lcd.clear(); + lcd.gotoXY(5,3); + lcd.print(F("Test gotoXY")); +#ifdef USE_FRAME_BUFFER + lcd.renderAll(); +#endif + delay(3000); + + lcd.clear(); + time = micros(); + lcd.writeBitmap(bmp, 10, 2, 25, 3); +#ifdef USE_FRAME_BUFFER + lcd.renderAll(); +#endif + time = micros() - time; + delay(3000); + + lcd.clear(); + lcd.print(F("The time it took to draw a 25x3 (25x18) bitmap is: ")); + lcd.print(time); +#ifdef USE_FRAME_BUFFER + lcd.renderAll(); +#endif + delay(3000); + +#ifdef USE_FRAME_BUFFER + lcd.clear(); + time = micros(); + lcd.writeRect(5, 5, 50, 40); + lcd.writeLine(75, 3, 75, 35); + lcd.writeLine(60, 10, 60, 40); + lcd.writeLine(10, 47, 60, 47); + lcd.renderAll(); + time = micros() - time; + delay(3000); + + lcd.clear(); + len = lcd.print(F("The time it took draw a rect and 3 lines: ")); + len += lcd.print(time); + lcd.renderString(0, 0, len); + delay(3000); + + lcd.clear(); + time = micros(); + for (uint8_t row = 0; row < PCD8544_Y_PIXELS; row++) + { + for (uint8_t col = 0; col < PCD8544_X_PIXELS; col++) + { + uint8_t pixel = (col + row) % 2; + lcd.setPixel(col, row, pixel); + } + } + lcd.renderAll(); + time = micros() - time; + delay(5000); + + lcd.clear(); + lcd.print(F("The time it took to run setPixel on all 4032 pixels and render it: ")); + lcd.print(time); + lcd.renderAll(); + delay(5000); +#endif +} \ No newline at end of file diff --git a/Code/libraries/PCD8544_SPI/PCD8544_SPI.cpp b/Code/libraries/PCD8544_SPI/PCD8544_SPI.cpp new file mode 100644 index 0000000..126c1e5 --- /dev/null +++ b/Code/libraries/PCD8544_SPI/PCD8544_SPI.cpp @@ -0,0 +1,152 @@ +#include "PCD8544_SPI.h" +#include + +PCD8544_SPI::PCD8544_SPI() +{ +} + +void PCD8544_SPI::begin(bool invert) +{ + this->begin(invert, 0xB0, 0x04, 0x15); +} + +void PCD8544_SPI::begin(bool invert, uint8_t vop, uint8_t tempCoef, uint8_t bias) +{ + PCD8544_PORT |= (PIN_DC | PIN_RESET | PIN_CE); + PCD8544_DDR |= (PIN_DC | PIN_RESET | PIN_CE); + SPI.begin(); + + // LCD init section: + + uint8_t invertSetting = invert ? 0x0D : 0x0C; + // Must reset LCD first! + PCD8544_PORT &= ~PIN_RESET; + PCD8544_PORT |= PIN_RESET; + + this->writeLcd(PCD8544_COMMAND, 0x21); //Tell LCD that extended commands follow + this->writeLcd(PCD8544_COMMAND, vop); //Set LCD Vop (Contrast): Try 0xB1(good @ 3.3V) or 0xBF if your display is too dark + this->writeLcd(PCD8544_COMMAND, tempCoef); //Set Temp coefficent + this->writeLcd(PCD8544_COMMAND, bias); //LCD bias mode 1:48: Try 0x13 or 0x14. Mine works best with 1:65/1:65 + + this->writeLcd(PCD8544_COMMAND, 0x20); //We must send 0x20 before modifying the display control mode + this->writeLcd(PCD8544_COMMAND, invertSetting); //Set display control, normal mode. 0x0D for inverse + + this->clear(); +} + +size_t PCD8544_SPI::write(uint8_t data) +{ + // Non-ASCII characters are not supported. + if (data < 0x20 || data > 0x7F) return 0; + + uint8_t buf[6]; + memcpy_P(buf, ASCII[data - 0x20], 5); + buf[5] = 0x00; + this->writeLcd(PCD8544_DATA, buf, 6); + this->advanceXY(6); + return 1; +} + +void PCD8544_SPI::clear() +{ + for (uint16_t i = 0; i < BUF_LEN; i++) + this->writeLcd(PCD8544_DATA, 0x00); + //PCD8544_PORT = (PCD8544_PORT & ~PINS_CE_DC) | PCD8544_DATA; + //for (uint16_t i = BUF_LEN; i > 0; i--) SPI.transfer(0x00); + //PCD8544_PORT |= PIN_CE; + this->gotoXY(0, 0); +} + +uint8_t PCD8544_SPI::gotoXY(uint8_t x, uint8_t y) +{ + if (x >= PCD8544_X_PIXELS || y >= PCD8544_ROWS) return PCD8544_ERROR; + //PCD8544_PORT = (PCD8544_PORT & ~PINS_CE_DC) | PCD8544_COMMAND; + //SPI.transfer(0x80 | x); + //SPI.transfer(0x40 | y); + //PCD8544_PORT |= PIN_CE; + this->writeLcd(PCD8544_COMMAND, 0x80 | x); // Column. + this->writeLcd(PCD8544_COMMAND, 0x40 | y); // Row. + this->m_Column = x; + this->m_Line = y; + return PCD8544_SUCCESS; +} + +uint8_t PCD8544_SPI::writeBitmap(const uint8_t *bitmap, uint8_t x, uint8_t y, uint8_t width, uint8_t height) +{ + //if (x >= PCD8544_X_PIXELS || y >= PCD8544_ROWS) return; + ////height = (this->m_Line + height > PCD8544_Y_PIXELS / 8) ? ((PCD8544_Y_PIXELS / 8) - this->m_Line) : height; + ////width = (this->m_Column + width > PCD8544_X_PIXELS) ? (PCD8544_X_PIXELS - this->m_Column) : width; + //this->gotoXY(x, y); + //for (uint8_t y = 0; y < height; y++) + //{ + // for (uint8_t x = 0; x < width; x++) + // this->writeLcd(PCD8544_DATA, bitmap[x + (y * width)]); + // this->gotoXY(this->m_Column, this->m_Line + 1); + //} + + //this->advanceXY(width); + + if (this->gotoXY(x, y) == PCD8544_ERROR) return PCD8544_ERROR; + const uint8_t *maxY = bitmap + height * width; + + for (const uint8_t *y = bitmap; y < maxY; y += width) + { + //for (uint8_t x = 0; x < width; x++, y++) + // this->writeLcd(PCD8544_DATA, *y); + + this->writeLcd(PCD8544_DATA, y , width); + this->gotoXY(this->m_Column, this->m_Line + 1); + } + + this->advanceXY(width); +} + +//void PCD8544_SPI::init(void) +//{ +// // Must reset LCD first! +// PCD8544_PORT &= ~PIN_RESET; +// PCD8544_PORT |= PIN_RESET; +// +// this->writeLcd(PCD8544_COMMAND, 0x21); //Tell LCD that extended commands follow +// this->writeLcd(PCD8544_COMMAND, 0xB0); //Set LCD Vop (Contrast): Try 0xB1(good @ 3.3V) or 0xBF if your display is too dark +// this->writeLcd(PCD8544_COMMAND, 0x04); //Set Temp coefficent +// this->writeLcd(PCD8544_COMMAND, 0x12); //LCD bias mode 1:48: Try 0x13 or 0x14. Mine works best with 1:65/1:65 +// +// this->writeLcd(PCD8544_COMMAND, 0x20); //We must send 0x20 before modifying the display control mode +// this->writeLcd(PCD8544_COMMAND, 0x0C); //Set display control, normal mode. 0x0D for inverse +//} + +void PCD8544_SPI::advanceXY(uint8_t columns) +{ + this->m_Column += columns; + if (this->m_Column >= PCD8544_X_PIXELS) + { + this->m_Column %= PCD8544_X_PIXELS; + this->m_Line++; + this->m_Line %= PCD8544_ROWS; + } +} + +void PCD8544_SPI::writeLcd(uint8_t dataOrCommand, const uint8_t *data, uint16_t count) +{ + PCD8544_PORT = (PCD8544_PORT & ~PINS_CE_DC) | dataOrCommand; + //for (uint16_t i = 0; i < count; i++) + // SPI.transfer(data[i]); + for (uint16_t i = count; i > 0; i--) + SPI.transfer(data[count-i]); + PCD8544_PORT |= PIN_CE; +} + +void PCD8544_SPI::writeLcd(uint8_t dataOrCommand, uint8_t data) +{ + PCD8544_PORT = (PCD8544_PORT & ~PINS_CE_DC) | dataOrCommand; + SPI.transfer(data); + PCD8544_PORT |= PIN_CE; +} + +// Valid values are 0x00 - 0x7F. +void PCD8544_SPI::contrast(uint8_t cnt) +{ + this->writeLcd(PCD8544_COMMAND, 0x21); //Tell LCD that extended commands follow + this->writeLcd(PCD8544_COMMAND, 0X80 | cnt); //Set LCD Vop (Contrast) +} diff --git a/Code/libraries/PCD8544_SPI/PCD8544_SPI.h b/Code/libraries/PCD8544_SPI/PCD8544_SPI.h new file mode 100644 index 0000000..7b0e4a1 --- /dev/null +++ b/Code/libraries/PCD8544_SPI/PCD8544_SPI.h @@ -0,0 +1,242 @@ +/******************************************************************** + This is a "Fast PCD8544 Library". It is designed to be used with + Nokia 5110 type of display, driven by the PCD8544 controller. + This library uses hardware SPI of your Arduino microcontroller, + and does not supprt 'software SPI' mode. + + Written by Arthur Liberman (aka 'The Coolest'). http://www.alcpu.com + Special thanks goes out to 'robtillaart' for his help with debugging + and optimization. + + BSD license, check license.txt for more information. + All text above must be included in any redistribution. +********************************************************************/ + +// Version 1.2 -- Sept. 15, 2013 + +#pragma once +#include "Arduino.h" + +// It is very important to wire the LCD correctly. +// The following is the default wiring configuration for an Atmega168/328 based Arduino: +// PIN_DC D8 +// PIN_RESET D9 +// PIN_SCE D10 +// PIN_SDIN D11 +// PIN_SCLK D13 + +// You may change pins DC, Reset and SCE to map them to different pins on your Arduino board. +// Please keep SDIN and SCLK connected to your Arduino's MOSI and SCK (hardware SPI) pins. +// You can remap the LCD control pins by changing the following '#define' values: +// Please refer to the pin/port mapping for your Arduino device: +// http://arduino.cc/en/Hacking/PinMapping168 +// http://arduino.cc/en/Hacking/PinMapping2560 +// Pins labeled Px (PB, PC, etc.) stand for PORTx. +// The current version of this library only allows the use of one port for the control pins. +// Pins are mapped in binary order. Valid values are 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80. +// Px0 is the LSB pin of the port, which in turn is represented by the hexadecimal number 0x01. +// Px7 is the MSB pin of the port, which in turn is represented by the hexadecimal number 0x80. + +// This is the port where the LCD is connected. +#define PCD8544_PORT PORTD +#define PCD8544_DDR DDRD // Should be DDRx, x = port name (B, C, D, etc.) + +#define PIN_DC 0x20 // D5 +#define PIN_RESET 0x08 // D3 +#define PIN_CE 0x10 // D4 +#define PINS_CE_DC (PIN_DC | PIN_CE) + +// When DC is '1' the LCD expects data, when it is '0' it expects a command. +#define PCD8544_COMMAND 0 +#define PCD8544_DATA PIN_DC + +// You may find a different size screen, but this one is 84 by 48 pixels +#define PCD8544_X_PIXELS 84 +#define PCD8544_Y_PIXELS 48 +#define PCD8544_ROWS 6 + +#define BUF_LEN 504 // 84 * 6 (6 rows of 8 bits) + +// Functions gotoXY, writeBitmap, renderString, writeLine and writeRect +// will return PCD8544_SUCCESS if they succeed and PCD8544_ERROR if they fail. +#define PCD8544_SUCCESS 1 +#define PCD8544_ERROR 0 + +//Umlaute +#define Ae 0x80 +#define ae 0x81 +#define Oe 0x82 +#define oe 0x83 +#define Ue 0x84 +#define ue 0x85 + + +class PCD8544_SPI : public Print +{ +public: + PCD8544_SPI(); + + void begin(bool invert = false); + void begin(bool invert, uint8_t vop, uint8_t tempCoef, uint8_t bias); + void clear(); + uint8_t gotoXY(uint8_t x, uint8_t y); + virtual size_t write(uint8_t uint8_t); + uint8_t writeBitmap(const uint8_t *bitmap, uint8_t x, uint8_t y, uint8_t width, uint8_t height); + void contrast(uint8_t cnt); + +private: + + //void init(void); + void writeLcd(uint8_t dataOrCommand, uint8_t data); + void writeLcd(uint8_t dataOrCommand, const uint8_t *data, uint16_t count); + + uint8_t m_Column; + uint8_t m_Line; + void advanceXY(uint8_t columns); +}; + +class PCD8544_SPI_FB : public Print +{ +public: + PCD8544_SPI_FB(); + + // Call a render method after any print/write methods are called. + // For best perofrmance aggragate all writes before calling a render method. + void renderLine(); + void renderAll(); + uint8_t renderString(uint8_t x, uint8_t y, uint16_t length); + + void setPixel(uint8_t x, uint8_t y, uint8_t value); + bool PCD8544_SPI_FB::getPixel(uint8_t x, uint8_t y); + + // WriteLine currently only supports horizontal and vertical lines. + uint8_t writeLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2); + uint8_t writeRect(uint8_t x, uint8_t y, uint8_t width, uint8_t height, bool fill = false); + + void begin(bool invert = false); + void begin(bool invert, uint8_t vop, uint8_t tempCoef, uint8_t bias); + void clear(bool render = true); + uint8_t gotoXY(uint8_t x, uint8_t y); + virtual size_t write(uint8_t uint8_t); + uint8_t writeBitmap(const uint8_t *bitmap, uint8_t x, uint8_t y, uint8_t width, uint8_t height); + void contrast(uint8_t cnt); + void printOut(String string, uint8_t line, uint8_t start); + +private: + + //void init(void); + void writeLcd(uint8_t dataOrCommand, uint8_t data); + void writeLcd(uint8_t dataOrCommand, const uint8_t *data, uint16_t count); + + inline void swap(uint8_t &a, uint8_t &b); + uint16_t m_Position; + uint8_t m_Buffer[BUF_LEN]; +}; + +//This table contains the hex values that represent pixels +//for a font that is 5 pixels wide and 8 pixels high +static const PROGMEM uint8_t ASCII[][5] = { + { 0x00, 0x00, 0x00, 0x00, 0x00 } // 20 (space) + ,{ 0x00, 0x00, 0x5f, 0x00, 0x00 } // 21 ! + ,{ 0x00, 0x07, 0x00, 0x07, 0x00 } // 22 " + ,{ 0x14, 0x7f, 0x14, 0x7f, 0x14 } // 23 # + ,{ 0x24, 0x2a, 0x7f, 0x2a, 0x12 } // 24 $ + ,{ 0x23, 0x13, 0x08, 0x64, 0x62 } // 25 % + ,{ 0x36, 0x49, 0x55, 0x22, 0x50 } // 26 & + ,{ 0x00, 0x05, 0x03, 0x00, 0x00 } // 27 ' + ,{ 0x00, 0x1c, 0x22, 0x41, 0x00 } // 28 ( + ,{ 0x00, 0x41, 0x22, 0x1c, 0x00 } // 29 ) + ,{ 0x14, 0x08, 0x3e, 0x08, 0x14 } // 2a * + ,{ 0x08, 0x08, 0x3e, 0x08, 0x08 } // 2b + + ,{ 0x00, 0x50, 0x30, 0x00, 0x00 } // 2c , + ,{ 0x08, 0x08, 0x08, 0x08, 0x08 } // 2d - + ,{ 0x00, 0x60, 0x60, 0x00, 0x00 } // 2e . + ,{ 0x20, 0x10, 0x08, 0x04, 0x02 } // 2f / + ,{ 0x3e, 0x51, 0x49, 0x45, 0x3e } // 30 0 + ,{ 0x00, 0x42, 0x7f, 0x40, 0x00 } // 31 1 + ,{ 0x42, 0x61, 0x51, 0x49, 0x46 } // 32 2 + ,{ 0x21, 0x41, 0x45, 0x4b, 0x31 } // 33 3 + ,{ 0x18, 0x14, 0x12, 0x7f, 0x10 } // 34 4 + ,{ 0x27, 0x45, 0x45, 0x45, 0x39 } // 35 5 + ,{ 0x3c, 0x4a, 0x49, 0x49, 0x30 } // 36 6 + ,{ 0x01, 0x71, 0x09, 0x05, 0x03 } // 37 7 + ,{ 0x36, 0x49, 0x49, 0x49, 0x36 } // 38 8 + ,{ 0x06, 0x49, 0x49, 0x29, 0x1e } // 39 9 + ,{ 0x00, 0x36, 0x36, 0x00, 0x00 } // 3a : + ,{ 0x00, 0x56, 0x36, 0x00, 0x00 } // 3b ; + ,{ 0x08, 0x14, 0x22, 0x41, 0x00 } // 3c < + ,{ 0x14, 0x14, 0x14, 0x14, 0x14 } // 3d = + ,{ 0x00, 0x41, 0x22, 0x14, 0x08 } // 3e > + ,{ 0x02, 0x01, 0x51, 0x09, 0x06 } // 3f ? + ,{ 0x32, 0x49, 0x79, 0x41, 0x3e } // 40 @ + ,{ 0x7e, 0x11, 0x11, 0x11, 0x7e } // 41 A + ,{ 0x7f, 0x49, 0x49, 0x49, 0x36 } // 42 B + ,{ 0x3e, 0x41, 0x41, 0x41, 0x22 } // 43 C + ,{ 0x7f, 0x41, 0x41, 0x22, 0x1c } // 44 D + ,{ 0x7f, 0x49, 0x49, 0x49, 0x41 } // 45 E + ,{ 0x7f, 0x09, 0x09, 0x09, 0x01 } // 46 F + ,{ 0x3e, 0x41, 0x49, 0x49, 0x7a } // 47 G + ,{ 0x7f, 0x08, 0x08, 0x08, 0x7f } // 48 H + ,{ 0x00, 0x41, 0x7f, 0x41, 0x00 } // 49 I + ,{ 0x20, 0x40, 0x41, 0x3f, 0x01 } // 4a J + ,{ 0x7f, 0x08, 0x14, 0x22, 0x41 } // 4b K + ,{ 0x7f, 0x40, 0x40, 0x40, 0x40 } // 4c L + ,{ 0x7f, 0x02, 0x0c, 0x02, 0x7f } // 4d M + ,{ 0x7f, 0x04, 0x08, 0x10, 0x7f } // 4e N + ,{ 0x3e, 0x41, 0x41, 0x41, 0x3e } // 4f O + ,{ 0x7f, 0x09, 0x09, 0x09, 0x06 } // 50 P + ,{ 0x3e, 0x41, 0x51, 0x21, 0x5e } // 51 Q + ,{ 0x7f, 0x09, 0x19, 0x29, 0x46 } // 52 R + ,{ 0x46, 0x49, 0x49, 0x49, 0x31 } // 53 S + ,{ 0x01, 0x01, 0x7f, 0x01, 0x01 } // 54 T + ,{ 0x3f, 0x40, 0x40, 0x40, 0x3f } // 55 U + ,{ 0x1f, 0x20, 0x40, 0x20, 0x1f } // 56 V + ,{ 0x3f, 0x40, 0x38, 0x40, 0x3f } // 57 W + ,{ 0x63, 0x14, 0x08, 0x14, 0x63 } // 58 X + ,{ 0x07, 0x08, 0x70, 0x08, 0x07 } // 59 Y + ,{ 0x61, 0x51, 0x49, 0x45, 0x43 } // 5a Z + ,{ 0x00, 0x7f, 0x41, 0x41, 0x00 } // 5b [ + ,{ 0x02, 0x04, 0x08, 0x10, 0x20 } // 5c backslash + ,{ 0x00, 0x41, 0x41, 0x7f, 0x00 } // 5d ] + ,{ 0x04, 0x02, 0x01, 0x02, 0x04 } // 5e ^ + ,{ 0x40, 0x40, 0x40, 0x40, 0x40 } // 5f _ + ,{ 0x00, 0x01, 0x02, 0x04, 0x00 } // 60 ` + ,{ 0x20, 0x54, 0x54, 0x54, 0x78 } // 61 a + ,{ 0x7f, 0x48, 0x44, 0x44, 0x38 } // 62 b + ,{ 0x38, 0x44, 0x44, 0x44, 0x20 } // 63 c + ,{ 0x38, 0x44, 0x44, 0x48, 0x7f } // 64 d + ,{ 0x38, 0x54, 0x54, 0x54, 0x18 } // 65 e + ,{ 0x08, 0x7e, 0x09, 0x01, 0x02 } // 66 f + ,{ 0x0c, 0x52, 0x52, 0x52, 0x3e } // 67 g + ,{ 0x7f, 0x08, 0x04, 0x04, 0x78 } // 68 h + ,{ 0x00, 0x44, 0x7d, 0x40, 0x00 } // 69 i + ,{ 0x20, 0x40, 0x44, 0x3d, 0x00 } // 6a j + ,{ 0x7f, 0x10, 0x28, 0x44, 0x00 } // 6b k + ,{ 0x00, 0x41, 0x7f, 0x40, 0x00 } // 6c l + ,{ 0x7c, 0x04, 0x18, 0x04, 0x78 } // 6d m + ,{ 0x7c, 0x08, 0x04, 0x04, 0x78 } // 6e n + ,{ 0x38, 0x44, 0x44, 0x44, 0x38 } // 6f o + ,{ 0x7c, 0x14, 0x14, 0x14, 0x08 } // 70 p + ,{ 0x08, 0x14, 0x14, 0x18, 0x7c } // 71 q + ,{ 0x7c, 0x08, 0x04, 0x04, 0x08 } // 72 r + ,{ 0x48, 0x54, 0x54, 0x54, 0x20 } // 73 s + ,{ 0x04, 0x3f, 0x44, 0x40, 0x20 } // 74 t + ,{ 0x3c, 0x40, 0x40, 0x20, 0x7c } // 75 u + ,{ 0x1c, 0x20, 0x40, 0x20, 0x1c } // 76 v + ,{ 0x3c, 0x40, 0x30, 0x40, 0x3c } // 77 w + ,{ 0x44, 0x28, 0x10, 0x28, 0x44 } // 78 x + ,{ 0x0c, 0x50, 0x50, 0x50, 0x3c } // 79 y + ,{ 0x44, 0x64, 0x54, 0x4c, 0x44 } // 7a z + ,{ 0x00, 0x08, 0x36, 0x41, 0x00 } // 7b { + ,{ 0x00, 0x00, 0x7f, 0x00, 0x00 } // 7c | + ,{ 0x00, 0x41, 0x36, 0x08, 0x00 } // 7d } + ,{ 0x10, 0x08, 0x08, 0x10, 0x08 } // 7e ~ + ,{ 0x78, 0x46, 0x41, 0x46, 0x78 } // 7f DEL +//Umlaute + ,{ 0xfd, 0x22, 0x22, 0x22, 0xfd } // 80 Ae + ,{ 0x21, 0x54, 0x54, 0x54, 0x79 } // 81 ae + ,{ 0x7d, 0x41, 0x41, 0x41, 0x7d } // 82 Oe + ,{ 0x38, 0x88, 0x88, 0x88, 0x38 } // 83 oe + ,{ 0x7e, 0x41, 0x40, 0x41, 0x7e } // 84 Ue + ,{ 0x3c, 0x41, 0x40, 0x21, 0x7c } // 85 ue +}; diff --git a/Code/libraries/PCD8544_SPI/PCD8544_SPI_FB.cpp b/Code/libraries/PCD8544_SPI/PCD8544_SPI_FB.cpp new file mode 100644 index 0000000..c453cf2 --- /dev/null +++ b/Code/libraries/PCD8544_SPI/PCD8544_SPI_FB.cpp @@ -0,0 +1,284 @@ +#include "PCD8544_SPI.h" +#include + +PCD8544_SPI_FB::PCD8544_SPI_FB() +{ +} + +void PCD8544_SPI_FB::begin(bool invert) +{ + this->begin(invert, 0xB0, 0x04, 0x12); +} + +void PCD8544_SPI_FB::begin(bool invert, uint8_t vop, uint8_t tempCoef, uint8_t bias) +{ + PCD8544_PORT |= (PIN_DC | PIN_RESET | PIN_CE); + PCD8544_DDR |= (PIN_DC | PIN_RESET | PIN_CE); + SPI.begin(); + + // LCD init section: + + uint8_t invertSetting = invert ? 0x0D : 0x0C; + // Must reset LCD first! + PCD8544_PORT &= ~PIN_RESET; + PCD8544_PORT |= PIN_RESET; + + this->writeLcd(PCD8544_COMMAND, 0x21); //Tell LCD that extended commands follow + this->writeLcd(PCD8544_COMMAND, vop); //Set LCD Vop (Contrast): Try 0xB1(good @ 3.3V) or 0xBF if your display is too dark + this->writeLcd(PCD8544_COMMAND, tempCoef); //Set Temp coefficent + this->writeLcd(PCD8544_COMMAND, bias); //LCD bias mode 1:48: Try 0x13 or 0x14. Mine works best with 1:65/1:65 + + this->writeLcd(PCD8544_COMMAND, 0x20); //We must send 0x20 before modifying the display control mode + this->writeLcd(PCD8544_COMMAND, invertSetting); //Set display control, normal mode. 0x0D for inverse + + this->clear(); +} + +size_t PCD8544_SPI_FB::write(uint8_t data) +{ + // Non-ASCII characters are not supported. + if (data < 0x20 || data > 0x7F) return 0; + + if (this->m_Position + 5 >= BUF_LEN) this->m_Position -= (BUF_LEN - 6); + memcpy_P(this->m_Buffer + this->m_Position, ASCII[data - 0x20], 5); + this->m_Buffer[this->m_Position+5] = 0x00; + this->m_Position += 6; + if (this->m_Position >= BUF_LEN) this->m_Position -= BUF_LEN; + //this->m_Position %= BUF_LEN; + return 1; +} + +void PCD8544_SPI_FB::clear(bool render) +{ + memset(this->m_Buffer, 0x00, sizeof(this->m_Buffer)); + if (render) + this->renderAll(); + this->gotoXY(0, 0); +} + +uint8_t PCD8544_SPI_FB::gotoXY(uint8_t x, uint8_t y) +{ + if (x >= PCD8544_X_PIXELS || y >= PCD8544_ROWS) return PCD8544_ERROR; + this->writeLcd(PCD8544_COMMAND, 0x80 | x); // Column. + this->writeLcd(PCD8544_COMMAND, 0x40 | y); // Row. + this->m_Position = (PCD8544_X_PIXELS * y) + x; + return PCD8544_SUCCESS; +} + +uint8_t PCD8544_SPI_FB::writeBitmap(const uint8_t *bitmap, uint8_t x, uint8_t y, uint8_t width, uint8_t height) +{ + //if (x >= PCD8544_X_PIXELS || y >= PCD8544_Y_PIXELS) return; + //this->gotoXY(x, y); + //uint16_t pos = this->m_Position; + //for (uint8_t y = 0; y < height; y++) + //{ + // memcpy(this->m_Buffer + pos, bitmap + (y*width), width); + // pos += PCD8544_X_PIXELS; + //} + + if (this->gotoXY(x, y) == PCD8544_ERROR) return PCD8544_ERROR; + + uint8_t *pos = this->m_Buffer + this->m_Position; + const uint8_t *maxY = bitmap + height * width; + + for (const uint8_t *y = (uint8_t*) bitmap; y < maxY; y += width) + { + memcpy(pos, y, width); + pos += PCD8544_X_PIXELS; + } + return PCD8544_SUCCESS; +} + +//void PCD8544_SPI_FB::init(void) +//{ +// // Must reset LCD first! +// PCD8544_PORT &= ~PIN_RESET; +// PCD8544_PORT |= PIN_RESET; +// +// this->writeLcd(PCD8544_COMMAND, 0x21); //Tell LCD that extended commands follow +// this->writeLcd(PCD8544_COMMAND, 0xB0); //Set LCD Vop (Contrast): Try 0xB1(good @ 3.3V) or 0xBF if your display is too dark +// this->writeLcd(PCD8544_COMMAND, 0x04); //Set Temp coefficent +// this->writeLcd(PCD8544_COMMAND, 0x12); //LCD bias mode 1:48: Try 0x13 or 0x14. Mine works best with 1:65/1:65 +// +// this->writeLcd(PCD8544_COMMAND, 0x20); //We must send 0x20 before modifying the display control mode +// this->writeLcd(PCD8544_COMMAND, 0x0C); //Set display control, normal mode. 0x0D for inverse +//} + +void PCD8544_SPI_FB::renderLine() +{ + this->writeLcd(PCD8544_DATA, this->m_Buffer, BUF_LEN); +} + +void PCD8544_SPI_FB::renderAll() +{ + this->gotoXY(0, 0); + this->writeLcd(PCD8544_DATA, this->m_Buffer, BUF_LEN); +} + +uint8_t PCD8544_SPI_FB::renderString(uint8_t x, uint8_t y, uint16_t length) +{ + if (this->gotoXY(x, y) == PCD8544_ERROR) return PCD8544_ERROR; + length *= 6; + this->writeLcd(PCD8544_DATA, this->m_Buffer + this->m_Position, length); + this->m_Position += length; + return PCD8544_SUCCESS; +} + +void PCD8544_SPI_FB::setPixel(uint8_t x, uint8_t y, uint8_t value) +{ + if (x >= PCD8544_X_PIXELS || y >= PCD8544_Y_PIXELS) return; + uint8_t bank = y / 8; + uint8_t bitMask = 1 << (y % 8); + uint8_t &byte = this->m_Buffer[(PCD8544_X_PIXELS * bank) + x]; + if (value) + byte |= bitMask; + else + byte &= ~bitMask; +} + +bool PCD8544_SPI_FB::getPixel(uint8_t x, uint8_t y) +{ + if (x >= PCD8544_X_PIXELS || y >= PCD8544_Y_PIXELS) return false; + uint8_t bank = y / 8; + uint8_t bitMask = 1 << (y % 8); + uint8_t &byte = this->m_Buffer[(PCD8544_X_PIXELS * bank) + x]; + if((byte &= bitMask) > 0){ + return true; + } else{ + return false; + } +} + +uint8_t PCD8544_SPI_FB::writeLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) +{ + if (x1 == x2 || y1 == y2) + { + if (y1 > y2) + swap(y1, y2); + if (x1 > x2) + swap(x1, x2); + return this->writeRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1); + } + else + return PCD8544_ERROR; +} + +void PCD8544_SPI_FB::swap(uint8_t &a, uint8_t &b) +{ + uint8_t temp = a; + a = b; + b = temp; +} +//from top left to bottom right corner +uint8_t PCD8544_SPI_FB::writeRect(uint8_t x, uint8_t y, uint8_t width, uint8_t height, bool fill) +{ + if (x >= PCD8544_X_PIXELS || y >= PCD8544_Y_PIXELS || width == 0 || height == 0) return PCD8544_ERROR; + + // Calculate the bitmasks for the pixels. + uint8_t bottom = y + height - 1; + uint8_t bankTop = y / 8; + uint8_t bankBottom = bottom / 8; + uint8_t bitMaskTop = 0x01; + uint8_t bitMaskBottom = 0x80; + uint8_t bitMaskTopFill = 0xFF; + uint8_t bitMaskBottomFill = 0xFF; + bitMaskTop <<= (y % 8); + bitMaskBottom >>= 7 - (bottom % 8); + bitMaskTopFill <<= (y % 8); + bitMaskBottomFill >>= 7 - (bottom % 8); + + // When fill is selected, we'll use the FillMask. + if (fill) + { + bitMaskTop = bitMaskTopFill; + bitMaskBottom = bitMaskBottomFill; + } + + // When the rectangle fits in a single bank, we AND the top and bottom masks + // So that we only fill the required area on the LCD. + if (bankTop == bankBottom) + { + bitMaskTop = fill ? bitMaskTop & bitMaskBottom : bitMaskTop | bitMaskBottom; + bitMaskTopFill &= bitMaskBottomFill; + } + this->gotoXY(x, bankTop); + + // Write the left 'side' of the rectangle on the top bank. + this->m_Buffer[this->m_Position++] |= bitMaskTopFill; + // Write a line or a fill. + for (uint8_t i = 1; i < width-1; i++) + this->m_Buffer[this->m_Position++] |= bitMaskTop; + // Write the right 'side' of the rectangle on the top bank. + if (width > 1) + this->m_Buffer[this->m_Position++] |= bitMaskTopFill; + + this->m_Position += (PCD8544_X_PIXELS - width); + + // Write a fill across the middle banks or two sides of the rectangle. + if (bankBottom - bankTop > 1) + { + for (uint8_t i = bankTop + 1; i < bankBottom; i++) + { + if (fill) + memset(this->m_Buffer + this->m_Position, 0xFF, width); + else + { + this->m_Buffer[this->m_Position] = 0xFF; + this->m_Buffer[this->m_Position+width-1] = 0xFF; + } + this->m_Position += PCD8544_X_PIXELS; + } + } + // If the rectangle spans across more than one bank, + // apply the same logic for the bottom as the top. + if (bankBottom > bankTop) + { + this->m_Buffer[this->m_Position++] |= bitMaskBottomFill; + for (uint8_t i = 1; i < width-1; i++) + this->m_Buffer[this->m_Position++] |= bitMaskBottom; + if (width > 1) + this->m_Buffer[this->m_Position++] |= bitMaskBottomFill; + } + return PCD8544_SUCCESS; +} + +void PCD8544_SPI_FB::writeLcd(uint8_t dataOrCommand, const uint8_t *data, uint16_t count) +{ + PCD8544_PORT = (PCD8544_PORT & ~PINS_CE_DC) | dataOrCommand; + //for (uint16_t i = 0; i < count; i++) + // SPI.transfer(data[i]); + for (uint16_t i = count; i > 0; i--) + SPI.transfer(data[count-i]); + PCD8544_PORT |= PIN_CE; +} + +void PCD8544_SPI_FB::writeLcd(uint8_t dataOrCommand, uint8_t data) +{ + PCD8544_PORT = (PCD8544_PORT & ~PINS_CE_DC) | dataOrCommand; + SPI.transfer(data); + PCD8544_PORT |= PIN_CE; +} + +// Valid values are 0x00 - 0x7F. +void PCD8544_SPI_FB::contrast(uint8_t cnt) +{ + this->writeLcd(PCD8544_COMMAND, 0x21); //Tell LCD that extended commands follow + this->writeLcd(PCD8544_COMMAND, 0X80 | cnt); //Set LCD Vop (Contrast) +} +// printing just one line and cut the overhang +void PCD8544_SPI_FB::printOut(String string, uint8_t line, uint8_t start) +{ + line--; + if(line > 5) { + this->gotoXY(start,5); + } else { + this->gotoXY(start,line); + } + String subString; + if(string.length() > 14) { + subString += string.substring(0, 14); + this->print(subString); + } else { + this->print(string); + } +} diff --git a/Code/libraries/PCD8544_SPI/keywords.txt b/Code/libraries/PCD8544_SPI/keywords.txt new file mode 100644 index 0000000..78866cc --- /dev/null +++ b/Code/libraries/PCD8544_SPI/keywords.txt @@ -0,0 +1,45 @@ +####################################### +# Syntax Coloring Map For PCD8544_SPI +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +PCD8544_SPI KEYWORD1 +PCD8544_SPI_FB KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +clear KEYWORD2 +gotoXY KEYWORD2 +writeBitmap KEYWORD2 +renderLine KEYWORD2 +renderAll KEYWORD2 +renderString KEYWORD2 +setPixel KEYWORD2 +getPixel KEYWORD2 +writeLine KEYWORD2 +writeRect KEYWORD2 +contrast KEYWORD2 +printOut KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +PIN_DC LITERAL1 +PIN_RESET LITERAL1 +PIN_CE LITERAL1 +PINS_CE_DC LITERAL1 +PCD8544_COMMAND LITERAL1 +PCD8544_DATA LITERAL1 +PCD8544_X_PIXELS LITERAL1 +PCD8544_Y_PIXELS LITERAL1 +PCD8544_ROWS LITERAL1 +PCD8544_SUCCESS LITERAL1 +PCD8544_ERROR LITERAL1 +BUF_LEN LITERAL1 diff --git a/Code/libraries/PCD8544_SPI/license.txt b/Code/libraries/PCD8544_SPI/license.txt new file mode 100644 index 0000000..d82aa8c --- /dev/null +++ b/Code/libraries/PCD8544_SPI/license.txt @@ -0,0 +1,25 @@ +Software License Agreement (BSD License) + +Copyright (c) 2013, ALCPU (Arthur Liberman). All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holders nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Code/libraries/myInterrupts/keywords.txt b/Code/libraries/myInterrupts/keywords.txt new file mode 100644 index 0000000..9df6ebd --- /dev/null +++ b/Code/libraries/myInterrupts/keywords.txt @@ -0,0 +1,32 @@ +####################################### +# Syntax Coloring Map For NanoGame +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +myInterrupts KEYWORD1 + + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +myInterrupts KEYWORD2 +initTimer1 KEYWORD2 +disableTimer1Interrupt KEYWORD2 +enableTimer1Interrupt KEYWORD2 + +initTimer2 KEYWORD2 +disableTimer2Interrupt KEYWORD2 +enableTimer2Interrupt KEYWORD2 +initOCR1B KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### + +#shiftDatPin LITERAL1 + diff --git a/Code/libraries/myInterrupts/myInterrupts.cpp b/Code/libraries/myInterrupts/myInterrupts.cpp new file mode 100644 index 0000000..d6ddea9 --- /dev/null +++ b/Code/libraries/myInterrupts/myInterrupts.cpp @@ -0,0 +1,97 @@ +#include "myInterrupts.h" + + myInterrupts::myInterrupts(){} + + myInterrupts::initTimer1(){ + // reset a timer unit (replace X by timer number) + TCCR1A = 0; // set TCCRXA register to 0 + TCCR1B = 0; // set TCCRXB register to 0 + TCNT1 = 0; // reset counter value + + // 1:1 + TCCR1B |= (1 << CS10); + + OCR1A = 15999; // set compare match register of timer 1 (max. value: 65536 = 2^16 - 1), 16000 ~ 1 millisecond + + //enable timer + TCCR1B |= (1 << WGM12); // enable timer1 CTC mode + TIMSK1 |= (1 << OCIE2A); // enable timer1 compare interrupt + } + + myInterrupts::disableTimer1Interrupt(){ + TIMSK1 &= ~(1 << OCIE2A); // disable timer1 compare interrupt + } + + myInterrupts::enableTimer1Interrupt(){ + TIMSK1 |= (1 << OCIE2A); // enable timer1 compare interrupt + } +//Timer2 + myInterrupts::initTimer2(){ + // reset a timer unit (replace X by timer number) + TCCR2A = 0; // set TCCRXA register to 0 + TCCR2B = 0; // set TCCRXB register to 0 + TCNT2 = 0; // reset counter value + + TCCR2A |= (1 << WGM21); // enable timer1 CTC mode + TCCR2A |= (1 << WGM20); + // 1:64 + TCCR2B |= (1 << CS22); + + OCR2A = 249; // set compare match register of timer 1 (max. value: 65536 = 2^16 - 1), 16000 ~ 1 millisecond + + //enable timer + TIMSK2 |= (1 << OCIE2A); // enable timer1 compare interrupt + } + + myInterrupts::initTimer2SoftPWM(){ + // reset a timer unit (replace X by timer number) + TCCR2A = 0; // set TCCRXA register to 0 + TCCR2B = 0; // set TCCRXB register to 0 + TCNT2 = 0; // reset counter value + + TCCR2A |= (1 << WGM21); // enable timer1 CTC mode + //TCCR2A |= (1 << WGM20); + // 1:8 + // TCCR2B |= (1 << CS20); + TCCR2B |= (1 << CS21); + //TCCR2B |= (1 << CS20); + + OCR2A = 100; // set compare match register of timer 2 (max. value: 255 = 2^8 - 1) (100µs) ca. 78Hz + + //enable timer + TIMSK2 |= (1 << OCIE2A); // enable timer1 compare interrupt + + } + + myInterrupts::disableTimer2Interrupt(){ + TIMSK2 &= ~(1 << OCIE2A); // disable timer1 compare interrupt + } + + myInterrupts::enableTimer2Interrupt(){ + TIMSK2 |= (1 << OCIE2A); // enable timer1 compare interrupt + } +//OCR1B + + myInterrupts::initOCR1B(){ + // reset a timer unit (replace X by timer number) + TCCR1A = 0; // set TCCRXA register to 0 + TCCR1B = 0; // set TCCRXB register to 0 + TCNT1 = 0; // reset counter value + + //OC1B behaviour + TCCR1A |= (1 << COM1B1); + // TCCR1A |= (1 << COM1B0); + TCCR1A |= (1 << WGM10); + // TCCR1A |= (1 << WGM11); + + // 1:1, 62.5kHz + TCCR1B |= (1 << CS10); + + TCCR1B |= (1 << WGM12); + // TCCR1B |= (1 << WGM13); + + OCR1B = 127; // set compare match register of timer 1 (max. value: 65536 = 2^16 - 1), 16000 ~ 1 millisecond + + //enable timer + TIMSK1 = 0; //no Interrupts + } diff --git a/Code/libraries/myInterrupts/myInterrupts.h b/Code/libraries/myInterrupts/myInterrupts.h new file mode 100644 index 0000000..73b5148 --- /dev/null +++ b/Code/libraries/myInterrupts/myInterrupts.h @@ -0,0 +1,22 @@ +#pragma once + +#ifndef myInterrupts_h +#define myInterrupts_h +#include + +class myInterrupts { + public: + myInterrupts(); + initTimer1(); + disableTimer1Interrupt(); + enableTimer1Interrupt(); + + initTimer2(); + initTimer2SoftPWM(); //55µs + disableTimer2Interrupt(); + enableTimer2Interrupt(); + + initOCR1B(); +}; + +#endif diff --git a/Code/libraries/shiftRegButtonLib/keywords.txt b/Code/libraries/shiftRegButtonLib/keywords.txt new file mode 100644 index 0000000..1e43eb8 --- /dev/null +++ b/Code/libraries/shiftRegButtonLib/keywords.txt @@ -0,0 +1,50 @@ +####################################### +# Syntax Coloring Map For shiftRegButtonLib +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +shiftRegButton KEYWORD1 +shiftRegButtonLib KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +#shiftRegButton KEYWORD2 +checkButtons KEYWORD2 +checkButton KEYWORD2 +checkButtonCycle KEYWORD2 +clearButton KEYWORD2 +clearAllButtons KEYWORD2 +getButtonCycle KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +shiftDatPin LITERAL1 +shiftClkPin LITERAL1 +shiftInPin LITERAL1 +shiftDatPORT LITERAL1 +shiftDatDDR LITERAL1 +shiftClkPORT LITERAL1 +shiftClkDDR LITERAL1 +shiftInPORT LITERAL1 +shiftInDDR LITERAL1 + +buttonUp LITERAL1 +buttonLeft LITERAL1 +buttonRight LITERAL1 +buttonDown LITERAL1 + +buttonL1 LITERAL1 +buttonStart LITERAL1 +buttonSelect LITERAL1 +buttonR1 LITERAL1 + +buttonA LITERAL1 +buttonB LITERAL1 +buttonC LITERAL1 diff --git a/Code/libraries/shiftRegButtonLib/shiftRegButtonLib.cpp b/Code/libraries/shiftRegButtonLib/shiftRegButtonLib.cpp new file mode 100644 index 0000000..eaff5ff --- /dev/null +++ b/Code/libraries/shiftRegButtonLib/shiftRegButtonLib.cpp @@ -0,0 +1,87 @@ +#include "shiftRegButtonLib.h" + + shiftRegButton::shiftRegButton() { + + //init Pins + shiftDatPORT &= ~shiftDatPin; + shiftClkPORT &= ~shiftClkPin; + + //shiftInDDR &= ~shiftInPin; + shiftDatDDR |= shiftDatPin; + shiftClkDDR |= shiftClkPin; + + shiftInPORT |= shiftInPin; + + //init all flags + shiftDatHi; + for(uint8_t i = 0; i < numberOfButtons; i++, shiftClk()) { + // buttonsPressed[i] = false; + // buttonsCycle[i] = false; + + buttonsTime[i] = 0; +// cycleFlag[i] = false; + //init shiftreg outputs to all 1's + } + buttonsPressed = 0; + buttonsCycle = 0; + cycleFlag = 0; + } + + shiftRegButton::checkButtons(void) { + //this procedure is needed by the 74HC595, other shift registers' behaviour may differ. See the datasheet of your part for more informations. + shiftDatLo; // + shiftClk(); //zero to shift stage 0 + shiftDatHi; // + shiftClk(); //zero to parallel output 0 + for(uint8_t i = 0; i < numberOfButtons; i++, shiftClk()) { + //is button i actually pressed? + if(buttonsInput()) { + buttonsPressed |= 1 << i; + // buttonsPressed[i] = true; + // cycleFlag[i] = true; + cycleFlag |= 1 << i; + buttonsTime[i]++; + } else { + // buttonsPressed[i] = false; + buttonsPressed &= ~(1 << i); + buttonsTime[i] = 0; + } + checkButtonCycle(i); + //increase the time button i is pressed, or clear if it is not pressed anymore + } + } + + bool shiftRegButton::checkButton(uint8_t n) { +// return buttonsPressed[n]; + return buttonsPressed & (1 << n); + } + + shiftRegButton::checkButtonCycle(uint8_t n) { +// if(!buttonsPressed[n] && cycleFlag[n]) { + if(!(buttonsPressed & (1 << n)) && (cycleFlag & (1 << n)) ) { +// buttonsCycle[n] = true; + buttonsCycle |= 1 << n; +// cycleFlag[n] = false; + cycleFlag &= ~(1 << n); + } + } + + shiftRegButton::clearButton(uint8_t buttonToBeCleared) { +// buttonsCycle[buttonToBeCleared] = false; + buttonsCycle &= ~(1 << buttonToBeCleared); + } + + shiftRegButton::clearAllButtons() { + for(uint8_t i = 0; i < numberOfButtons; i++) { +// buttonsCycle[i] = false; + buttonsCycle &= ~(1 << i); + } + } + + bool shiftRegButton::getButtonCycle(uint8_t n) { +// return buttonsCycle[n]; + return buttonsCycle & (1 << n); + } + uint16_t shiftRegButton::getAnyPressed() { + return buttonsPressed; + } diff --git a/Code/libraries/shiftRegButtonLib/shiftRegButtonLib.h b/Code/libraries/shiftRegButtonLib/shiftRegButtonLib.h new file mode 100644 index 0000000..9ec2e05 --- /dev/null +++ b/Code/libraries/shiftRegButtonLib/shiftRegButtonLib.h @@ -0,0 +1,86 @@ +#pragma once + +#ifndef shiftRegButtonLib_h +#define shiftRegButtonLib_h + +#include + +#define numberOfButtons 11 +//definitions for buttons +#define buttonUp 0 +#define buttonLeft 2 +#define buttonRight 1 +#define buttonDown 3 + +#define buttonL1 4 +#define buttonStart 5 +#define buttonSelect 6 +#define buttonR1 7 + +#define buttonA 9 +#define buttonB 10 +#define buttonC 8 +//Pin and PORT assignments for shiftRegister(s) +#define shiftDatPin 0x01 //D8 +#define shiftClkPin 0x40 //D6 +#define shiftInPin 0x02 //D9 + +#define shiftDatPORT PORTB +#define shiftDatDDR DDRB // Should be DDRx, x = port name (B, C, D, etc.) + +#define shiftClkPORT PORTD +#define shiftClkDDR DDRD + +#define shiftInPIN PINB +#define shiftInPORT PORTB +#define shiftInDDR DDRB +//Macros +#define shiftDatLo (shiftDatPORT &= ~shiftDatPin) +#define shiftDatHi (shiftDatPORT |= shiftDatPin) +//74HC595 needs rising edge for sampling data +inline void shiftClk(void) +{ + shiftClkPORT |= shiftClkPin; + shiftClkPORT &= ~shiftClkPin; +} + +inline bool buttonsInput(void) +{ + if((shiftInPIN &= shiftInPin) == 0) { + return true; + } else { + return false; + } +} + +class shiftRegButton { + public: + + shiftRegButton(); + checkButtons(void); +//returns the state of a certain button + bool checkButton(uint8_t n); + checkButtonCycle(uint8_t n); +//clears the cycle flag of a certain button + clearButton(uint8_t buttonToBeCleared); +//clears all cycle flags + clearAllButtons(); +//return, if a certain button has been pressed (complete cycle, Hi-Lo-Hi) + bool getButtonCycle(uint8_t n); +//was any button pressed? + uint16_t getAnyPressed(); + + + private: + +// volatile bool buttonsPressed[numberOfButtons]; //flags to represent the actual (debounced) state of a button, no clearing needed + volatile uint16_t buttonsPressed; //flags to represent the actual (debounced) state of a button, no clearing needed + +// volatile bool buttonsCycle[numberOfButtons]; //flags to represent if a button did a whole hi-lo-hi cycle, clearing needed + volatile uint16_t buttonsCycle; //flags to represent if a button did a whole hi-lo-hi cycle, clearing needed + uint8_t buttonsTime[numberOfButtons]; //the time in milliseconds a button was actually pressed, no clearing needed, no overflow detection (max = 255ms) +// volatile bool cycleFlag[numberOfButtons]; + volatile uint16_t cycleFlag; +}; + +#endif