Lukas Reichwein
5 years ago
20 changed files with 1546 additions and 0 deletions
-
21Code/libraries/MX1508/LICENSE
-
100Code/libraries/MX1508/MX1508.cpp
-
39Code/libraries/MX1508/MX1508.h
-
4Code/libraries/MX1508/README.md
-
68Code/libraries/MX1508/examples/16bitResolutionPWM/16bitResolutionPWM.ino
-
44Code/libraries/MX1508/examples/exampleMX1508/exampleMX1508.ino
-
26Code/libraries/MX1508/keywords.txt
-
10Code/libraries/MX1508/library.properties
-
112Code/libraries/PCD8544_SPI/Examples/PCD8544SPIbenchmark/PCD8544SPIbenchmark.ino
-
152Code/libraries/PCD8544_SPI/PCD8544_SPI.cpp
-
242Code/libraries/PCD8544_SPI/PCD8544_SPI.h
-
284Code/libraries/PCD8544_SPI/PCD8544_SPI_FB.cpp
-
45Code/libraries/PCD8544_SPI/keywords.txt
-
25Code/libraries/PCD8544_SPI/license.txt
-
32Code/libraries/myInterrupts/keywords.txt
-
97Code/libraries/myInterrupts/myInterrupts.cpp
-
22Code/libraries/myInterrupts/myInterrupts.h
-
50Code/libraries/shiftRegButtonLib/keywords.txt
-
87Code/libraries/shiftRegButtonLib/shiftRegButtonLib.cpp
-
86Code/libraries/shiftRegButtonLib/shiftRegButtonLib.h
@ -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. |
@ -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); |
|||
} |
|||
} |
|||
} |
|||
} |
@ -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 |
@ -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). |
@ -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.
|
|||
} |
|||
|
|||
} |
@ -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.
|
|||
} |
|||
|
|||
} |
@ -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) |
|||
####################################### |
@ -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 |
@ -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
|
|||
} |
@ -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)
|
|||
} |
@ -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 |
|||
}; |
@ -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); |
|||
} |
|||
} |
@ -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 |
@ -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. |
@ -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 |
|||
|
@ -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
|
|||
} |
@ -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 |
@ -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 |
@ -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; |
|||
} |
@ -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 |
Write
Preview
Loading…
Cancel
Save
Reference in new issue