Yves Ehrlich
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