Lukas Reichwein 5 years ago
parent
commit
2e9dc216d4
  1. 21
      Code/libraries/MX1508/LICENSE
  2. 100
      Code/libraries/MX1508/MX1508.cpp
  3. 39
      Code/libraries/MX1508/MX1508.h
  4. 4
      Code/libraries/MX1508/README.md
  5. 68
      Code/libraries/MX1508/examples/16bitResolutionPWM/16bitResolutionPWM.ino
  6. 44
      Code/libraries/MX1508/examples/exampleMX1508/exampleMX1508.ino
  7. 26
      Code/libraries/MX1508/keywords.txt
  8. 10
      Code/libraries/MX1508/library.properties
  9. 112
      Code/libraries/PCD8544_SPI/Examples/PCD8544SPIbenchmark/PCD8544SPIbenchmark.ino
  10. 152
      Code/libraries/PCD8544_SPI/PCD8544_SPI.cpp
  11. 242
      Code/libraries/PCD8544_SPI/PCD8544_SPI.h
  12. 284
      Code/libraries/PCD8544_SPI/PCD8544_SPI_FB.cpp
  13. 45
      Code/libraries/PCD8544_SPI/keywords.txt
  14. 25
      Code/libraries/PCD8544_SPI/license.txt
  15. 32
      Code/libraries/myInterrupts/keywords.txt
  16. 97
      Code/libraries/myInterrupts/myInterrupts.cpp
  17. 22
      Code/libraries/myInterrupts/myInterrupts.h
  18. 50
      Code/libraries/shiftRegButtonLib/keywords.txt
  19. 87
      Code/libraries/shiftRegButtonLib/shiftRegButtonLib.cpp
  20. 86
      Code/libraries/shiftRegButtonLib/shiftRegButtonLib.h

21
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.

100
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);
}
}
}
}

39
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

4
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).

68
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 <MX1508.h>
#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.
}
}

44
Code/libraries/MX1508/examples/exampleMX1508/exampleMX1508.ino

@ -0,0 +1,44 @@
#include <MX1508.h>
#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.
}
}

26
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)
#######################################

10
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

112
Code/libraries/PCD8544_SPI/Examples/PCD8544SPIbenchmark/PCD8544SPIbenchmark.ino

@ -0,0 +1,112 @@
#include <SPI.h>
#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
}

152
Code/libraries/PCD8544_SPI/PCD8544_SPI.cpp

@ -0,0 +1,152 @@
#include "PCD8544_SPI.h"
#include <SPI.h>
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)
}

242
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
};

284
Code/libraries/PCD8544_SPI/PCD8544_SPI_FB.cpp

@ -0,0 +1,284 @@
#include "PCD8544_SPI.h"
#include <SPI.h>
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);
}
}

45
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

25
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.

32
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

97
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
}

22
Code/libraries/myInterrupts/myInterrupts.h

@ -0,0 +1,22 @@
#pragma once
#ifndef myInterrupts_h
#define myInterrupts_h
#include <Arduino.h>
class myInterrupts {
public:
myInterrupts();
initTimer1();
disableTimer1Interrupt();
enableTimer1Interrupt();
initTimer2();
initTimer2SoftPWM(); //55µs
disableTimer2Interrupt();
enableTimer2Interrupt();
initOCR1B();
};
#endif

50
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

87
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;
}

86
Code/libraries/shiftRegButtonLib/shiftRegButtonLib.h

@ -0,0 +1,86 @@
#pragma once
#ifndef shiftRegButtonLib_h
#define shiftRegButtonLib_h
#include <Arduino.h>
#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
Loading…
Cancel
Save