feat: 全量同步 254 个常用的 Arduino 扩展库文件
This commit is contained in:
480
arduino-libs/arduino-cli/libraries/yfrobot/Adafruit_GFX.cpp
Normal file
480
arduino-libs/arduino-cli/libraries/yfrobot/Adafruit_GFX.cpp
Normal file
@@ -0,0 +1,480 @@
|
||||
/*
|
||||
This is the core graphics library for all our displays, providing a common
|
||||
set of graphics primitives (points, lines, circles, etc.). It needs to be
|
||||
paired with a hardware-specific library for each display device we carry
|
||||
(to handle the lower-level functions).
|
||||
|
||||
Adafruit invests time and resources providing this open source code, please
|
||||
support Adafruit & open-source hardware by purchasing products from Adafruit!
|
||||
|
||||
Copyright (c) 2013 Adafruit Industries. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
- 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.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
#include "Adafruit_GFX.h"
|
||||
#include "glcdfont.c"
|
||||
#ifdef __AVR__
|
||||
#include <avr/pgmspace.h>
|
||||
#else
|
||||
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
|
||||
#endif
|
||||
|
||||
Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h):
|
||||
WIDTH(w), HEIGHT(h)
|
||||
{
|
||||
_width = WIDTH;
|
||||
_height = HEIGHT;
|
||||
rotation = 0;
|
||||
cursor_y = cursor_x = 0;
|
||||
textsize = 1;
|
||||
textcolor = textbgcolor = 0xFFFF;
|
||||
wrap = true;
|
||||
}
|
||||
|
||||
// Draw a circle outline
|
||||
void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r,
|
||||
uint16_t color) {
|
||||
int16_t f = 1 - r;
|
||||
int16_t ddF_x = 1;
|
||||
int16_t ddF_y = -2 * r;
|
||||
int16_t x = 0;
|
||||
int16_t y = r;
|
||||
|
||||
drawPixel(x0 , y0+r, color);
|
||||
drawPixel(x0 , y0-r, color);
|
||||
drawPixel(x0+r, y0 , color);
|
||||
drawPixel(x0-r, y0 , color);
|
||||
|
||||
while (x<y) {
|
||||
if (f >= 0) {
|
||||
y--;
|
||||
ddF_y += 2;
|
||||
f += ddF_y;
|
||||
}
|
||||
x++;
|
||||
ddF_x += 2;
|
||||
f += ddF_x;
|
||||
|
||||
drawPixel(x0 + x, y0 + y, color);
|
||||
drawPixel(x0 - x, y0 + y, color);
|
||||
drawPixel(x0 + x, y0 - y, color);
|
||||
drawPixel(x0 - x, y0 - y, color);
|
||||
drawPixel(x0 + y, y0 + x, color);
|
||||
drawPixel(x0 - y, y0 + x, color);
|
||||
drawPixel(x0 + y, y0 - x, color);
|
||||
drawPixel(x0 - y, y0 - x, color);
|
||||
}
|
||||
}
|
||||
|
||||
void Adafruit_GFX::drawCircleHelper( int16_t x0, int16_t y0,
|
||||
int16_t r, uint8_t cornername, uint16_t color) {
|
||||
int16_t f = 1 - r;
|
||||
int16_t ddF_x = 1;
|
||||
int16_t ddF_y = -2 * r;
|
||||
int16_t x = 0;
|
||||
int16_t y = r;
|
||||
|
||||
while (x<y) {
|
||||
if (f >= 0) {
|
||||
y--;
|
||||
ddF_y += 2;
|
||||
f += ddF_y;
|
||||
}
|
||||
x++;
|
||||
ddF_x += 2;
|
||||
f += ddF_x;
|
||||
if (cornername & 0x4) {
|
||||
drawPixel(x0 + x, y0 + y, color);
|
||||
drawPixel(x0 + y, y0 + x, color);
|
||||
}
|
||||
if (cornername & 0x2) {
|
||||
drawPixel(x0 + x, y0 - y, color);
|
||||
drawPixel(x0 + y, y0 - x, color);
|
||||
}
|
||||
if (cornername & 0x8) {
|
||||
drawPixel(x0 - y, y0 + x, color);
|
||||
drawPixel(x0 - x, y0 + y, color);
|
||||
}
|
||||
if (cornername & 0x1) {
|
||||
drawPixel(x0 - y, y0 - x, color);
|
||||
drawPixel(x0 - x, y0 - y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r,
|
||||
uint16_t color) {
|
||||
drawFastVLine(x0, y0-r, 2*r+1, color);
|
||||
fillCircleHelper(x0, y0, r, 3, 0, color);
|
||||
}
|
||||
|
||||
// Used to do circles and roundrects
|
||||
void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
|
||||
uint8_t cornername, int16_t delta, uint16_t color) {
|
||||
|
||||
int16_t f = 1 - r;
|
||||
int16_t ddF_x = 1;
|
||||
int16_t ddF_y = -2 * r;
|
||||
int16_t x = 0;
|
||||
int16_t y = r;
|
||||
|
||||
while (x<y) {
|
||||
if (f >= 0) {
|
||||
y--;
|
||||
ddF_y += 2;
|
||||
f += ddF_y;
|
||||
}
|
||||
x++;
|
||||
ddF_x += 2;
|
||||
f += ddF_x;
|
||||
|
||||
if (cornername & 0x1) {
|
||||
drawFastVLine(x0+x, y0-y, 2*y+1+delta, color);
|
||||
drawFastVLine(x0+y, y0-x, 2*x+1+delta, color);
|
||||
}
|
||||
if (cornername & 0x2) {
|
||||
drawFastVLine(x0-x, y0-y, 2*y+1+delta, color);
|
||||
drawFastVLine(x0-y, y0-x, 2*x+1+delta, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bresenham's algorithm - thx wikpedia
|
||||
void Adafruit_GFX::drawLine(int16_t x0, int16_t y0,
|
||||
int16_t x1, int16_t y1,
|
||||
uint16_t color) {
|
||||
int16_t steep = abs(y1 - y0) > abs(x1 - x0);
|
||||
if (steep) {
|
||||
swap(x0, y0);
|
||||
swap(x1, y1);
|
||||
}
|
||||
|
||||
if (x0 > x1) {
|
||||
swap(x0, x1);
|
||||
swap(y0, y1);
|
||||
}
|
||||
|
||||
int16_t dx, dy;
|
||||
dx = x1 - x0;
|
||||
dy = abs(y1 - y0);
|
||||
|
||||
int16_t err = dx / 2;
|
||||
int16_t ystep;
|
||||
|
||||
if (y0 < y1) {
|
||||
ystep = 1;
|
||||
} else {
|
||||
ystep = -1;
|
||||
}
|
||||
|
||||
for (; x0<=x1; x0++) {
|
||||
if (steep) {
|
||||
drawPixel(y0, x0, color);
|
||||
} else {
|
||||
drawPixel(x0, y0, color);
|
||||
}
|
||||
err -= dy;
|
||||
if (err < 0) {
|
||||
y0 += ystep;
|
||||
err += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw a rectangle
|
||||
void Adafruit_GFX::drawRect(int16_t x, int16_t y,
|
||||
int16_t w, int16_t h,
|
||||
uint16_t color) {
|
||||
drawFastHLine(x, y, w, color);
|
||||
drawFastHLine(x, y+h-1, w, color);
|
||||
drawFastVLine(x, y, h, color);
|
||||
drawFastVLine(x+w-1, y, h, color);
|
||||
}
|
||||
|
||||
void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y,
|
||||
int16_t h, uint16_t color) {
|
||||
// Update in subclasses if desired!
|
||||
drawLine(x, y, x, y+h-1, color);
|
||||
}
|
||||
|
||||
void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y,
|
||||
int16_t w, uint16_t color) {
|
||||
// Update in subclasses if desired!
|
||||
drawLine(x, y, x+w-1, y, color);
|
||||
}
|
||||
|
||||
void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
|
||||
uint16_t color) {
|
||||
// Update in subclasses if desired!
|
||||
for (int16_t i=x; i<x+w; i++) {
|
||||
drawFastVLine(i, y, h, color);
|
||||
}
|
||||
}
|
||||
|
||||
void Adafruit_GFX::fillScreen(uint16_t color) {
|
||||
fillRect(0, 0, _width, _height, color);
|
||||
}
|
||||
|
||||
// Draw a rounded rectangle
|
||||
void Adafruit_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w,
|
||||
int16_t h, int16_t r, uint16_t color) {
|
||||
// smarter version
|
||||
drawFastHLine(x+r , y , w-2*r, color); // Top
|
||||
drawFastHLine(x+r , y+h-1, w-2*r, color); // Bottom
|
||||
drawFastVLine(x , y+r , h-2*r, color); // Left
|
||||
drawFastVLine(x+w-1, y+r , h-2*r, color); // Right
|
||||
// draw four corners
|
||||
drawCircleHelper(x+r , y+r , r, 1, color);
|
||||
drawCircleHelper(x+w-r-1, y+r , r, 2, color);
|
||||
drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
|
||||
drawCircleHelper(x+r , y+h-r-1, r, 8, color);
|
||||
}
|
||||
|
||||
// Fill a rounded rectangle
|
||||
void Adafruit_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w,
|
||||
int16_t h, int16_t r, uint16_t color) {
|
||||
// smarter version
|
||||
fillRect(x+r, y, w-2*r, h, color);
|
||||
|
||||
// draw four corners
|
||||
fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color);
|
||||
fillCircleHelper(x+r , y+r, r, 2, h-2*r-1, color);
|
||||
}
|
||||
|
||||
// Draw a triangle
|
||||
void Adafruit_GFX::drawTriangle(int16_t x0, int16_t y0,
|
||||
int16_t x1, int16_t y1,
|
||||
int16_t x2, int16_t y2, uint16_t color) {
|
||||
drawLine(x0, y0, x1, y1, color);
|
||||
drawLine(x1, y1, x2, y2, color);
|
||||
drawLine(x2, y2, x0, y0, color);
|
||||
}
|
||||
|
||||
// Fill a triangle
|
||||
void Adafruit_GFX::fillTriangle ( int16_t x0, int16_t y0,
|
||||
int16_t x1, int16_t y1,
|
||||
int16_t x2, int16_t y2, uint16_t color) {
|
||||
|
||||
int16_t a, b, y, last;
|
||||
|
||||
// Sort coordinates by Y order (y2 >= y1 >= y0)
|
||||
if (y0 > y1) {
|
||||
swap(y0, y1); swap(x0, x1);
|
||||
}
|
||||
if (y1 > y2) {
|
||||
swap(y2, y1); swap(x2, x1);
|
||||
}
|
||||
if (y0 > y1) {
|
||||
swap(y0, y1); swap(x0, x1);
|
||||
}
|
||||
|
||||
if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing
|
||||
a = b = x0;
|
||||
if(x1 < a) a = x1;
|
||||
else if(x1 > b) b = x1;
|
||||
if(x2 < a) a = x2;
|
||||
else if(x2 > b) b = x2;
|
||||
drawFastHLine(a, y0, b-a+1, color);
|
||||
return;
|
||||
}
|
||||
|
||||
int16_t
|
||||
dx01 = x1 - x0,
|
||||
dy01 = y1 - y0,
|
||||
dx02 = x2 - x0,
|
||||
dy02 = y2 - y0,
|
||||
dx12 = x2 - x1,
|
||||
dy12 = y2 - y1,
|
||||
sa = 0,
|
||||
sb = 0;
|
||||
|
||||
// For upper part of triangle, find scanline crossings for segments
|
||||
// 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
|
||||
// is included here (and second loop will be skipped, avoiding a /0
|
||||
// error there), otherwise scanline y1 is skipped here and handled
|
||||
// in the second loop...which also avoids a /0 error here if y0=y1
|
||||
// (flat-topped triangle).
|
||||
if(y1 == y2) last = y1; // Include y1 scanline
|
||||
else last = y1-1; // Skip it
|
||||
|
||||
for(y=y0; y<=last; y++) {
|
||||
a = x0 + sa / dy01;
|
||||
b = x0 + sb / dy02;
|
||||
sa += dx01;
|
||||
sb += dx02;
|
||||
/* longhand:
|
||||
a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
|
||||
b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
|
||||
*/
|
||||
if(a > b) swap(a,b);
|
||||
drawFastHLine(a, y, b-a+1, color);
|
||||
}
|
||||
|
||||
// For lower part of triangle, find scanline crossings for segments
|
||||
// 0-2 and 1-2. This loop is skipped if y1=y2.
|
||||
sa = dx12 * (y - y1);
|
||||
sb = dx02 * (y - y0);
|
||||
for(; y<=y2; y++) {
|
||||
a = x1 + sa / dy12;
|
||||
b = x0 + sb / dy02;
|
||||
sa += dx12;
|
||||
sb += dx02;
|
||||
/* longhand:
|
||||
a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
|
||||
b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
|
||||
*/
|
||||
if(a > b) swap(a,b);
|
||||
drawFastHLine(a, y, b-a+1, color);
|
||||
}
|
||||
}
|
||||
|
||||
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
|
||||
const uint8_t *bitmap, int16_t w, int16_t h,
|
||||
uint16_t color) {
|
||||
|
||||
int16_t i, j, byteWidth = (w + 7) / 8;
|
||||
|
||||
for(j=0; j<h; j++) {
|
||||
for(i=0; i<w; i++ ) {
|
||||
if(pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
|
||||
drawPixel(x+i, y+j, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if ARDUINO >= 100
|
||||
size_t Adafruit_GFX::write(uint8_t c) {
|
||||
#else
|
||||
void Adafruit_GFX::write(uint8_t c) {
|
||||
#endif
|
||||
if (c == '\n') {
|
||||
cursor_y += textsize*8;
|
||||
cursor_x = 0;
|
||||
} else if (c == '\r') {
|
||||
// skip em
|
||||
} else {
|
||||
drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize);
|
||||
cursor_x += textsize*6;
|
||||
if (wrap && (cursor_x > (_width - textsize*6))) {
|
||||
cursor_y += textsize*8;
|
||||
cursor_x = 0;
|
||||
}
|
||||
}
|
||||
#if ARDUINO >= 100
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Draw a character
|
||||
void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
|
||||
uint16_t color, uint16_t bg, uint8_t size) {
|
||||
|
||||
if((x >= _width) || // Clip right
|
||||
(y >= _height) || // Clip bottom
|
||||
((x + 6 * size - 1) < 0) || // Clip left
|
||||
((y + 8 * size - 1) < 0)) // Clip top
|
||||
return;
|
||||
|
||||
for (int8_t i=0; i<6; i++ ) {
|
||||
uint8_t line;
|
||||
if (i == 5)
|
||||
line = 0x0;
|
||||
else
|
||||
line = pgm_read_byte(font+(c*5)+i);
|
||||
for (int8_t j = 0; j<8; j++) {
|
||||
if (line & 0x1) {
|
||||
if (size == 1) // default size
|
||||
drawPixel(x+i, y+j, color);
|
||||
else { // big size
|
||||
fillRect(x+(i*size), y+(j*size), size, size, color);
|
||||
}
|
||||
} else if (bg != color) {
|
||||
if (size == 1) // default size
|
||||
drawPixel(x+i, y+j, bg);
|
||||
else { // big size
|
||||
fillRect(x+i*size, y+j*size, size, size, bg);
|
||||
}
|
||||
}
|
||||
line >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Adafruit_GFX::setCursor(int16_t x, int16_t y) {
|
||||
cursor_x = x;
|
||||
cursor_y = y;
|
||||
}
|
||||
|
||||
void Adafruit_GFX::setTextSize(uint8_t s) {
|
||||
textsize = (s > 0) ? s : 1;
|
||||
}
|
||||
|
||||
void Adafruit_GFX::setTextColor(uint16_t c) {
|
||||
// For 'transparent' background, we'll set the bg
|
||||
// to the same as fg instead of using a flag
|
||||
textcolor = textbgcolor = c;
|
||||
}
|
||||
|
||||
void Adafruit_GFX::setTextColor(uint16_t c, uint16_t b) {
|
||||
textcolor = c;
|
||||
textbgcolor = b;
|
||||
}
|
||||
|
||||
void Adafruit_GFX::setTextWrap(boolean w) {
|
||||
wrap = w;
|
||||
}
|
||||
|
||||
uint8_t Adafruit_GFX::getRotation(void) {
|
||||
return rotation;
|
||||
}
|
||||
|
||||
void Adafruit_GFX::setRotation(uint8_t x) {
|
||||
rotation = (x & 3);
|
||||
switch(rotation) {
|
||||
case 0:
|
||||
case 2:
|
||||
_width = WIDTH;
|
||||
_height = HEIGHT;
|
||||
break;
|
||||
case 1:
|
||||
case 3:
|
||||
_width = HEIGHT;
|
||||
_height = WIDTH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the size of the display (per current rotation)
|
||||
int16_t Adafruit_GFX::width(void) {
|
||||
return _width;
|
||||
}
|
||||
|
||||
int16_t Adafruit_GFX::height(void) {
|
||||
return _height;
|
||||
}
|
||||
|
||||
void Adafruit_GFX::invertDisplay(boolean i) {
|
||||
// Do nothing, must be subclassed if supported
|
||||
}
|
||||
|
||||
87
arduino-libs/arduino-cli/libraries/yfrobot/Adafruit_GFX.h
Normal file
87
arduino-libs/arduino-cli/libraries/yfrobot/Adafruit_GFX.h
Normal file
@@ -0,0 +1,87 @@
|
||||
#ifndef _ADAFRUIT_GFX_H
|
||||
#define _ADAFRUIT_GFX_H
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#include "Print.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#define swap(a, b) { int16_t t = a; a = b; b = t; }
|
||||
|
||||
class Adafruit_GFX : public Print {
|
||||
|
||||
public:
|
||||
|
||||
Adafruit_GFX(int16_t w, int16_t h); // Constructor
|
||||
|
||||
// This MUST be defined by the subclass:
|
||||
virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0;
|
||||
|
||||
// These MAY be overridden by the subclass to provide device-specific
|
||||
// optimized code. Otherwise 'generic' versions are used.
|
||||
virtual void
|
||||
drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color),
|
||||
drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color),
|
||||
drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color),
|
||||
drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color),
|
||||
fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color),
|
||||
fillScreen(uint16_t color),
|
||||
invertDisplay(boolean i);
|
||||
|
||||
// These exist only with Adafruit_GFX (no subclass overrides)
|
||||
void
|
||||
drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color),
|
||||
drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
|
||||
uint16_t color),
|
||||
fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color),
|
||||
fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
|
||||
int16_t delta, uint16_t color),
|
||||
drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
|
||||
int16_t x2, int16_t y2, uint16_t color),
|
||||
fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
|
||||
int16_t x2, int16_t y2, uint16_t color),
|
||||
drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h,
|
||||
int16_t radius, uint16_t color),
|
||||
fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h,
|
||||
int16_t radius, uint16_t color),
|
||||
drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap,
|
||||
int16_t w, int16_t h, uint16_t color),
|
||||
drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color,
|
||||
uint16_t bg, uint8_t size),
|
||||
setCursor(int16_t x, int16_t y),
|
||||
setTextColor(uint16_t c),
|
||||
setTextColor(uint16_t c, uint16_t bg),
|
||||
setTextSize(uint8_t s),
|
||||
setTextWrap(boolean w),
|
||||
setRotation(uint8_t r);
|
||||
|
||||
#if ARDUINO >= 100
|
||||
virtual size_t write(uint8_t);
|
||||
#else
|
||||
virtual void write(uint8_t);
|
||||
#endif
|
||||
|
||||
int16_t
|
||||
height(void),
|
||||
width(void);
|
||||
|
||||
uint8_t getRotation(void);
|
||||
|
||||
protected:
|
||||
const int16_t
|
||||
WIDTH, HEIGHT; // This is the 'raw' display w/h - never changes
|
||||
int16_t
|
||||
_width, _height, // Display w/h as modified by current rotation
|
||||
cursor_x, cursor_y;
|
||||
uint16_t
|
||||
textcolor, textbgcolor;
|
||||
uint8_t
|
||||
textsize,
|
||||
rotation;
|
||||
boolean
|
||||
wrap; // If set, 'wrap' text at right edge of display
|
||||
};
|
||||
|
||||
#endif // _ADAFRUIT_GFX_H
|
||||
1730
arduino-libs/arduino-cli/libraries/yfrobot/Adafruit_NeoPixel.cpp
Normal file
1730
arduino-libs/arduino-cli/libraries/yfrobot/Adafruit_NeoPixel.cpp
Normal file
File diff suppressed because it is too large
Load Diff
181
arduino-libs/arduino-cli/libraries/yfrobot/Adafruit_NeoPixel.h
Normal file
181
arduino-libs/arduino-cli/libraries/yfrobot/Adafruit_NeoPixel.h
Normal file
@@ -0,0 +1,181 @@
|
||||
/*--------------------------------------------------------------------
|
||||
This file is part of the Adafruit NeoPixel library.
|
||||
|
||||
NeoPixel is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
--------------------------------------------------------------------*/
|
||||
|
||||
#ifndef ADAFRUIT_NEOPIXEL_H
|
||||
#define ADAFRUIT_NEOPIXEL_H
|
||||
|
||||
#if (ARDUINO >= 100)
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#include <pins_arduino.h>
|
||||
#endif
|
||||
|
||||
// The order of primary colors in the NeoPixel data stream can vary
|
||||
// among device types, manufacturers and even different revisions of
|
||||
// the same item. The third parameter to the Adafruit_NeoPixel
|
||||
// constructor encodes the per-pixel byte offsets of the red, green
|
||||
// and blue primaries (plus white, if present) in the data stream --
|
||||
// the following #defines provide an easier-to-use named version for
|
||||
// each permutation. e.g. NEO_GRB indicates a NeoPixel-compatible
|
||||
// device expecting three bytes per pixel, with the first byte
|
||||
// containing the green value, second containing red and third
|
||||
// containing blue. The in-memory representation of a chain of
|
||||
// NeoPixels is the same as the data-stream order; no re-ordering of
|
||||
// bytes is required when issuing data to the chain.
|
||||
|
||||
// Bits 5,4 of this value are the offset (0-3) from the first byte of
|
||||
// a pixel to the location of the red color byte. Bits 3,2 are the
|
||||
// green offset and 1,0 are the blue offset. If it is an RGBW-type
|
||||
// device (supporting a white primary in addition to R,G,B), bits 7,6
|
||||
// are the offset to the white byte...otherwise, bits 7,6 are set to
|
||||
// the same value as 5,4 (red) to indicate an RGB (not RGBW) device.
|
||||
// i.e. binary representation:
|
||||
// 0bWWRRGGBB for RGBW devices
|
||||
// 0bRRRRGGBB for RGB
|
||||
|
||||
// RGB NeoPixel permutations; white and red offsets are always same
|
||||
// Offset: W R G B
|
||||
#define NEO_RGB ((0 << 6) | (0 << 4) | (1 << 2) | (2))
|
||||
#define NEO_RBG ((0 << 6) | (0 << 4) | (2 << 2) | (1))
|
||||
#define NEO_GRB ((1 << 6) | (1 << 4) | (0 << 2) | (2))
|
||||
#define NEO_GBR ((2 << 6) | (2 << 4) | (0 << 2) | (1))
|
||||
#define NEO_BRG ((1 << 6) | (1 << 4) | (2 << 2) | (0))
|
||||
#define NEO_BGR ((2 << 6) | (2 << 4) | (1 << 2) | (0))
|
||||
|
||||
// RGBW NeoPixel permutations; all 4 offsets are distinct
|
||||
// Offset: W R G B
|
||||
#define NEO_WRGB ((0 << 6) | (1 << 4) | (2 << 2) | (3))
|
||||
#define NEO_WRBG ((0 << 6) | (1 << 4) | (3 << 2) | (2))
|
||||
#define NEO_WGRB ((0 << 6) | (2 << 4) | (1 << 2) | (3))
|
||||
#define NEO_WGBR ((0 << 6) | (3 << 4) | (1 << 2) | (2))
|
||||
#define NEO_WBRG ((0 << 6) | (2 << 4) | (3 << 2) | (1))
|
||||
#define NEO_WBGR ((0 << 6) | (3 << 4) | (2 << 2) | (1))
|
||||
|
||||
#define NEO_RWGB ((1 << 6) | (0 << 4) | (2 << 2) | (3))
|
||||
#define NEO_RWBG ((1 << 6) | (0 << 4) | (3 << 2) | (2))
|
||||
#define NEO_RGWB ((2 << 6) | (0 << 4) | (1 << 2) | (3))
|
||||
#define NEO_RGBW ((3 << 6) | (0 << 4) | (1 << 2) | (2))
|
||||
#define NEO_RBWG ((2 << 6) | (0 << 4) | (3 << 2) | (1))
|
||||
#define NEO_RBGW ((3 << 6) | (0 << 4) | (2 << 2) | (1))
|
||||
|
||||
#define NEO_GWRB ((1 << 6) | (2 << 4) | (0 << 2) | (3))
|
||||
#define NEO_GWBR ((1 << 6) | (3 << 4) | (0 << 2) | (2))
|
||||
#define NEO_GRWB ((2 << 6) | (1 << 4) | (0 << 2) | (3))
|
||||
#define NEO_GRBW ((3 << 6) | (1 << 4) | (0 << 2) | (2))
|
||||
#define NEO_GBWR ((2 << 6) | (3 << 4) | (0 << 2) | (1))
|
||||
#define NEO_GBRW ((3 << 6) | (2 << 4) | (0 << 2) | (1))
|
||||
|
||||
#define NEO_BWRG ((1 << 6) | (2 << 4) | (3 << 2) | (0))
|
||||
#define NEO_BWGR ((1 << 6) | (3 << 4) | (2 << 2) | (0))
|
||||
#define NEO_BRWG ((2 << 6) | (1 << 4) | (3 << 2) | (0))
|
||||
#define NEO_BRGW ((3 << 6) | (1 << 4) | (2 << 2) | (0))
|
||||
#define NEO_BGWR ((2 << 6) | (3 << 4) | (1 << 2) | (0))
|
||||
#define NEO_BGRW ((3 << 6) | (2 << 4) | (1 << 2) | (0))
|
||||
|
||||
// Add NEO_KHZ400 to the color order value to indicate a 400 KHz
|
||||
// device. All but the earliest v1 NeoPixels expect an 800 KHz data
|
||||
// stream, this is the default if unspecified. Because flash space
|
||||
// is very limited on ATtiny devices (e.g. Trinket, Gemma), v1
|
||||
// NeoPixels aren't handled by default on those chips, though it can
|
||||
// be enabled by removing the ifndef/endif below -- but code will be
|
||||
// bigger. Conversely, can disable the NEO_KHZ400 line on other MCUs
|
||||
// to remove v1 support and save a little space.
|
||||
|
||||
#define NEO_KHZ800 0x0000 // 800 KHz datastream
|
||||
#ifndef __AVR_ATtiny85__
|
||||
#define NEO_KHZ400 0x0100 // 400 KHz datastream
|
||||
#endif
|
||||
|
||||
// If 400 KHz support is enabled, the third parameter to the constructor
|
||||
// requires a 16-bit value (in order to select 400 vs 800 KHz speed).
|
||||
// If only 800 KHz is enabled (as is default on ATtiny), an 8-bit value
|
||||
// is sufficient to encode pixel color order, saving some space.
|
||||
|
||||
#ifdef NEO_KHZ400
|
||||
typedef uint16_t neoPixelType;
|
||||
#else
|
||||
typedef uint8_t neoPixelType;
|
||||
#endif
|
||||
|
||||
class Adafruit_NeoPixel {
|
||||
|
||||
public:
|
||||
|
||||
// Constructor: number of LEDs, pin number, LED type
|
||||
Adafruit_NeoPixel(uint16_t n, uint8_t p=6, neoPixelType t=NEO_GRB + NEO_KHZ800);
|
||||
Adafruit_NeoPixel(void);
|
||||
~Adafruit_NeoPixel();
|
||||
|
||||
void
|
||||
begin(void),
|
||||
show(void),
|
||||
setPin(uint8_t p),
|
||||
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b),
|
||||
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w),
|
||||
setPixelColor(uint16_t n, uint32_t c),
|
||||
setBrightness(uint8_t),
|
||||
clear(),
|
||||
updateLength(uint16_t n),
|
||||
updateType(neoPixelType t);
|
||||
uint8_t
|
||||
*getPixels(void) const,
|
||||
getBrightness(void) const;
|
||||
int8_t
|
||||
getPin(void) { return pin; };
|
||||
uint16_t
|
||||
numPixels(void) const;
|
||||
static uint32_t
|
||||
Color(uint8_t r, uint8_t g, uint8_t b),
|
||||
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w);
|
||||
uint32_t
|
||||
getPixelColor(uint16_t n) const;
|
||||
inline bool
|
||||
canShow(void) { return (micros() - endTime) >= 50L; }
|
||||
|
||||
private:
|
||||
|
||||
boolean
|
||||
#ifdef NEO_KHZ400 // If 400 KHz NeoPixel support enabled...
|
||||
is800KHz, // ...true if 800 KHz pixels
|
||||
#endif
|
||||
begun; // true if begin() previously called
|
||||
uint16_t
|
||||
numLEDs, // Number of RGB LEDs in strip
|
||||
numBytes; // Size of 'pixels' buffer below (3 or 4 bytes/pixel)
|
||||
int8_t
|
||||
pin; // Output pin number (-1 if not yet set)
|
||||
uint8_t
|
||||
brightness,
|
||||
*pixels, // Holds LED color values (3 or 4 bytes each)
|
||||
rOffset, // Index of red byte within each 3- or 4-byte pixel
|
||||
gOffset, // Index of green byte
|
||||
bOffset, // Index of blue byte
|
||||
wOffset; // Index of white byte (same as rOffset if no white)
|
||||
uint32_t
|
||||
endTime; // Latch timing reference
|
||||
#ifdef __AVR__
|
||||
volatile uint8_t
|
||||
*port; // Output PORT register
|
||||
uint8_t
|
||||
pinMask; // Output PORT bitmask
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // ADAFRUIT_NEOPIXEL_H
|
||||
8
arduino-libs/arduino-cli/libraries/yfrobot/Mixly.h
Normal file
8
arduino-libs/arduino-cli/libraries/yfrobot/Mixly.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef _YFROBOT_H_
|
||||
#define _YFROBOT_H_
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "Adafruit_NeoPixel.h" //for RGB
|
||||
#include "Adafruit_GFX.h" //for 88点阵
|
||||
|
||||
#endif
|
||||
465
arduino-libs/arduino-cli/libraries/yfrobot/PS2X_lib.cpp
Normal file
465
arduino-libs/arduino-cli/libraries/yfrobot/PS2X_lib.cpp
Normal file
@@ -0,0 +1,465 @@
|
||||
#include "PS2X_lib.h"
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <avr/io.h>
|
||||
#if ARDUINO > 22
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#include "pins_arduino.h"
|
||||
#endif
|
||||
|
||||
static byte enter_config[]={0x01,0x43,0x00,0x01,0x00};
|
||||
static byte set_mode[]={0x01,0x44,0x00,0x01,0xEE,0x00,0x00,0x00,0x00}; // 通过MODE键,可更改模式
|
||||
// static byte set_mode[]={0x01,0x44,0x00,0x01,0x03,0x00,0x00,0x00,0x00}; // 通过MODE键,不可更改模式
|
||||
static byte set_bytes_large[]={0x01,0x4F,0x00,0xFF,0xFF,0x03,0x00,0x00,0x00};
|
||||
static byte exit_config[]={0x01,0x43,0x00,0x00,0x5A,0x5A,0x5A,0x5A,0x5A};
|
||||
static byte enable_rumble[]={0x01,0x4D,0x00,0x00,0x01};
|
||||
static byte type_read[]={0x01,0x45,0x00,0x5A,0x5A,0x5A,0x5A,0x5A,0x5A};
|
||||
|
||||
/****************************************************************************************/
|
||||
boolean PS2X::NewButtonState() {
|
||||
return ((last_buttons ^ buttons) > 0);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
boolean PS2X::NewButtonState(unsigned int button) {
|
||||
return (((last_buttons ^ buttons) & button) > 0);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
boolean PS2X::ButtonPressed(unsigned int button) {
|
||||
return(NewButtonState(button) & Button(button));
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
boolean PS2X::ButtonReleased(unsigned int button) {
|
||||
return((NewButtonState(button)) & ((~last_buttons & button) > 0));
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
boolean PS2X::Button(uint16_t button) {
|
||||
return ((~buttons & button) > 0);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
unsigned int PS2X::ButtonDataByte() {
|
||||
return (~buttons);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
byte PS2X::Analog(byte button) {
|
||||
return PS2data[button];
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
unsigned char PS2X::_gamepad_shiftinout (char byte) {
|
||||
unsigned char tmp = 0;
|
||||
for(unsigned char i=0;i<8;i++) {
|
||||
if(CHK(byte,i)) CMD_SET();
|
||||
else CMD_CLR();
|
||||
|
||||
CLK_CLR();
|
||||
delayMicroseconds(CTRL_CLK);
|
||||
|
||||
//if(DAT_CHK()) SET(tmp,i);
|
||||
if(DAT_CHK()) bitSet(tmp,i);
|
||||
|
||||
CLK_SET();
|
||||
#if CTRL_CLK_HIGH
|
||||
delayMicroseconds(CTRL_CLK_HIGH);
|
||||
#endif
|
||||
}
|
||||
CMD_SET();
|
||||
delayMicroseconds(CTRL_BYTE_DELAY);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
void PS2X::read_gamepad() {
|
||||
read_gamepad(false, 0x00);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
boolean PS2X::read_gamepad(boolean motor1, byte motor2) {
|
||||
double temp = millis() - last_read;
|
||||
|
||||
if (temp > 1500) //waited to long
|
||||
reconfig_gamepad();
|
||||
|
||||
if(temp < read_delay) //waited too short
|
||||
delay(read_delay - temp);
|
||||
|
||||
if(motor2 != 0x00)
|
||||
motor2 = map(motor2,0,255,0x40,0xFF); //noting below 40 will make it spin
|
||||
|
||||
char dword[9] = {0x01,0x42,0,motor1,motor2,0,0,0,0};
|
||||
byte dword2[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
|
||||
// Try a few times to get valid data...
|
||||
for (byte RetryCnt = 0; RetryCnt < 5; RetryCnt++) {
|
||||
CMD_SET();
|
||||
CLK_SET();
|
||||
ATT_CLR(); // low enable joystick
|
||||
|
||||
delayMicroseconds(CTRL_BYTE_DELAY);
|
||||
//Send the command to send button and joystick data;
|
||||
for (int i = 0; i<9; i++) {
|
||||
PS2data[i] = _gamepad_shiftinout(dword[i]);
|
||||
}
|
||||
|
||||
if(PS2data[1] == 0x79) { //if controller is in full data return mode, get the rest of data
|
||||
for (int i = 0; i<12; i++) {
|
||||
PS2data[i+9] = _gamepad_shiftinout(dword2[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ATT_SET(); // HI disable joystick
|
||||
// Check to see if we received valid data or not.
|
||||
// We should be in analog mode for our data to be valid (analog == 0x7_)
|
||||
if ((PS2data[1] & 0xf0) == 0x70)
|
||||
break;
|
||||
|
||||
// If we got to here, we are not in analog mode, try to recover...
|
||||
reconfig_gamepad(); // try to get back into Analog mode.
|
||||
delay(read_delay);
|
||||
}
|
||||
|
||||
// If we get here and still not in analog mode (=0x7_), try increasing the read_delay...
|
||||
if ((PS2data[1] & 0xf0) != 0x70) {
|
||||
if (read_delay < 10)
|
||||
read_delay++; // see if this helps out...
|
||||
}
|
||||
|
||||
#ifdef PS2X_COM_DEBUG
|
||||
Serial.println("OUT:IN");
|
||||
for(int i=0; i<9; i++){
|
||||
Serial.print(dword[i], HEX);
|
||||
Serial.print(":");
|
||||
Serial.print(PS2data[i], HEX);
|
||||
Serial.print(" ");
|
||||
}
|
||||
for (int i = 0; i<12; i++) {
|
||||
Serial.print(dword2[i], HEX);
|
||||
Serial.print(":");
|
||||
Serial.print(PS2data[i+9], HEX);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println("");
|
||||
#endif
|
||||
|
||||
last_buttons = buttons; //store the previous buttons states
|
||||
|
||||
#if defined(__AVR__)
|
||||
buttons = *(uint16_t*)(PS2data+3); //store as one value for multiple functions
|
||||
#else
|
||||
buttons = (uint16_t)(PS2data[4] << 8) + PS2data[3]; //store as one value for multiple functions
|
||||
#endif
|
||||
last_read = millis();
|
||||
return ((PS2data[1] & 0xf0) == 0x70); // 1 = OK = analog mode - 0 = NOK
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
byte PS2X::config_gamepad(uint8_t clk, uint8_t cmd, uint8_t att, uint8_t dat) {
|
||||
return config_gamepad(clk, cmd, att, dat, false, false);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
byte PS2X::config_gamepad(uint8_t clk, uint8_t cmd, uint8_t att, uint8_t dat, bool pressures, bool rumble) {
|
||||
|
||||
byte temp[sizeof(type_read)];
|
||||
|
||||
#ifdef __AVR__
|
||||
_clk_mask = digitalPinToBitMask(clk);
|
||||
_clk_oreg = portOutputRegister(digitalPinToPort(clk));
|
||||
_cmd_mask = digitalPinToBitMask(cmd);
|
||||
_cmd_oreg = portOutputRegister(digitalPinToPort(cmd));
|
||||
_att_mask = digitalPinToBitMask(att);
|
||||
_att_oreg = portOutputRegister(digitalPinToPort(att));
|
||||
_dat_mask = digitalPinToBitMask(dat);
|
||||
_dat_ireg = portInputRegister(digitalPinToPort(dat));
|
||||
#else
|
||||
uint32_t lport; // Port number for this pin
|
||||
_clk_mask = digitalPinToBitMask(clk);
|
||||
lport = digitalPinToPort(clk);
|
||||
_clk_lport_set = portOutputRegister(lport) + 2;
|
||||
_clk_lport_clr = portOutputRegister(lport) + 1;
|
||||
|
||||
_cmd_mask = digitalPinToBitMask(cmd);
|
||||
lport = digitalPinToPort(cmd);
|
||||
_cmd_lport_set = portOutputRegister(lport) + 2;
|
||||
_cmd_lport_clr = portOutputRegister(lport) + 1;
|
||||
|
||||
_att_mask = digitalPinToBitMask(att);
|
||||
lport = digitalPinToPort(att);
|
||||
_att_lport_set = portOutputRegister(lport) + 2;
|
||||
_att_lport_clr = portOutputRegister(lport) + 1;
|
||||
|
||||
_dat_mask = digitalPinToBitMask(dat);
|
||||
_dat_lport = portInputRegister(digitalPinToPort(dat));
|
||||
#endif
|
||||
|
||||
pinMode(clk, OUTPUT); //configure ports
|
||||
pinMode(att, OUTPUT);
|
||||
pinMode(cmd, OUTPUT);
|
||||
pinMode(dat, INPUT);
|
||||
|
||||
#if defined(__AVR__)
|
||||
digitalWrite(dat, HIGH); //enable pull-up
|
||||
#endif
|
||||
|
||||
CMD_SET(); // SET(*_cmd_oreg,_cmd_mask);
|
||||
CLK_SET();
|
||||
|
||||
//new error checking. First, read gamepad a few times to see if it's talking
|
||||
read_gamepad();
|
||||
read_gamepad();
|
||||
|
||||
//see if it talked - see if mode came back.
|
||||
//If still anything but 41, 73 or 79, then it's not talking
|
||||
if(PS2data[1] != 0x41 && PS2data[1] != 0x73 && PS2data[1] != 0x79){
|
||||
#ifdef PS2X_DEBUG
|
||||
Serial.println("Controller mode not matched or no controller found");
|
||||
Serial.print("Expected 0x41, 0x73 or 0x79, but got ");
|
||||
Serial.println(PS2data[1], HEX);
|
||||
#endif
|
||||
return 1; //return error code 1
|
||||
}
|
||||
|
||||
//try setting mode, increasing delays if need be.
|
||||
read_delay = 1;
|
||||
|
||||
for(int y = 0; y <= 10; y++) {
|
||||
sendCommandString(enter_config, sizeof(enter_config)); //start config run
|
||||
|
||||
//read type
|
||||
delayMicroseconds(CTRL_BYTE_DELAY);
|
||||
|
||||
CMD_SET();
|
||||
CLK_SET();
|
||||
ATT_CLR(); // low enable joystick
|
||||
|
||||
delayMicroseconds(CTRL_BYTE_DELAY);
|
||||
|
||||
for (int i = 0; i<9; i++) {
|
||||
temp[i] = _gamepad_shiftinout(type_read[i]);
|
||||
}
|
||||
|
||||
ATT_SET(); // HI disable joystick
|
||||
|
||||
controller_type = temp[3];
|
||||
|
||||
sendCommandString(set_mode, sizeof(set_mode));
|
||||
if(rumble){ sendCommandString(enable_rumble, sizeof(enable_rumble)); en_Rumble = true; }
|
||||
if(pressures){ sendCommandString(set_bytes_large, sizeof(set_bytes_large)); en_Pressures = true; }
|
||||
sendCommandString(exit_config, sizeof(exit_config));
|
||||
|
||||
read_gamepad();
|
||||
|
||||
if(pressures){
|
||||
if(PS2data[1] == 0x79)
|
||||
break;
|
||||
if(PS2data[1] == 0x73)
|
||||
return 3;
|
||||
}
|
||||
|
||||
if(PS2data[1] == 0x73)
|
||||
break;
|
||||
|
||||
if(y == 10){
|
||||
#ifdef PS2X_DEBUG
|
||||
Serial.println("Controller not accepting commands");
|
||||
Serial.print("mode stil set at");
|
||||
Serial.println(PS2data[1], HEX);
|
||||
#endif
|
||||
return 2; //exit function with error
|
||||
}
|
||||
read_delay += 1; //add 1ms to read_delay
|
||||
}
|
||||
return 0; //no error if here
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
void PS2X::sendCommandString(byte string[], byte len) {
|
||||
#ifdef PS2X_COM_DEBUG
|
||||
byte temp[len];
|
||||
ATT_CLR(); // low enable joystick
|
||||
delayMicroseconds(CTRL_BYTE_DELAY);
|
||||
|
||||
for (int y=0; y < len; y++)
|
||||
temp[y] = _gamepad_shiftinout(string[y]);
|
||||
|
||||
ATT_SET(); //high disable joystick
|
||||
delay(read_delay); //wait a few
|
||||
|
||||
Serial.println("OUT:IN Configure");
|
||||
for(int i=0; i<len; i++) {
|
||||
Serial.print(string[i], HEX);
|
||||
Serial.print(":");
|
||||
Serial.print(temp[i], HEX);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println("");
|
||||
#else
|
||||
ATT_CLR(); // low enable joystick
|
||||
for (int y=0; y < len; y++)
|
||||
_gamepad_shiftinout(string[y]);
|
||||
ATT_SET(); //high disable joystick
|
||||
delay(read_delay); //wait a few
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
byte PS2X::readType() {
|
||||
/*
|
||||
byte temp[sizeof(type_read)];
|
||||
|
||||
sendCommandString(enter_config, sizeof(enter_config));
|
||||
|
||||
delayMicroseconds(CTRL_BYTE_DELAY);
|
||||
|
||||
CMD_SET();
|
||||
CLK_SET();
|
||||
ATT_CLR(); // low enable joystick
|
||||
|
||||
delayMicroseconds(CTRL_BYTE_DELAY);
|
||||
|
||||
for (int i = 0; i<9; i++) {
|
||||
temp[i] = _gamepad_shiftinout(type_read[i]);
|
||||
}
|
||||
|
||||
sendCommandString(exit_config, sizeof(exit_config));
|
||||
|
||||
if(temp[3] == 0x03)
|
||||
return 1;
|
||||
else if(temp[3] == 0x01)
|
||||
return 2;
|
||||
|
||||
return 0;
|
||||
*/
|
||||
|
||||
if(controller_type == 0x03)
|
||||
return 1;
|
||||
else if(controller_type == 0x01)
|
||||
return 2;
|
||||
else if(controller_type == 0x0C)
|
||||
return 3; //2.4G Wireless Dual Shock PS2 Game Controller
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
void PS2X::enableRumble() {
|
||||
sendCommandString(enter_config, sizeof(enter_config));
|
||||
sendCommandString(enable_rumble, sizeof(enable_rumble));
|
||||
sendCommandString(exit_config, sizeof(exit_config));
|
||||
en_Rumble = true;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
bool PS2X::enablePressures() {
|
||||
sendCommandString(enter_config, sizeof(enter_config));
|
||||
sendCommandString(set_bytes_large, sizeof(set_bytes_large));
|
||||
sendCommandString(exit_config, sizeof(exit_config));
|
||||
|
||||
read_gamepad();
|
||||
read_gamepad();
|
||||
|
||||
if(PS2data[1] != 0x79)
|
||||
return false;
|
||||
|
||||
en_Pressures = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
void PS2X::reconfig_gamepad(){
|
||||
sendCommandString(enter_config, sizeof(enter_config));
|
||||
sendCommandString(set_mode, sizeof(set_mode));
|
||||
if (en_Rumble)
|
||||
sendCommandString(enable_rumble, sizeof(enable_rumble));
|
||||
if (en_Pressures)
|
||||
sendCommandString(set_bytes_large, sizeof(set_bytes_large));
|
||||
sendCommandString(exit_config, sizeof(exit_config));
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
#ifdef __AVR__
|
||||
inline void PS2X::CLK_SET(void) {
|
||||
register uint8_t old_sreg = SREG;
|
||||
cli();
|
||||
*_clk_oreg |= _clk_mask;
|
||||
SREG = old_sreg;
|
||||
}
|
||||
|
||||
inline void PS2X::CLK_CLR(void) {
|
||||
register uint8_t old_sreg = SREG;
|
||||
cli();
|
||||
*_clk_oreg &= ~_clk_mask;
|
||||
SREG = old_sreg;
|
||||
}
|
||||
|
||||
inline void PS2X::CMD_SET(void) {
|
||||
register uint8_t old_sreg = SREG;
|
||||
cli();
|
||||
*_cmd_oreg |= _cmd_mask; // SET(*_cmd_oreg,_cmd_mask);
|
||||
SREG = old_sreg;
|
||||
}
|
||||
|
||||
inline void PS2X::CMD_CLR(void) {
|
||||
register uint8_t old_sreg = SREG;
|
||||
cli();
|
||||
*_cmd_oreg &= ~_cmd_mask; // SET(*_cmd_oreg,_cmd_mask);
|
||||
SREG = old_sreg;
|
||||
}
|
||||
|
||||
inline void PS2X::ATT_SET(void) {
|
||||
register uint8_t old_sreg = SREG;
|
||||
cli();
|
||||
*_att_oreg |= _att_mask ;
|
||||
SREG = old_sreg;
|
||||
}
|
||||
|
||||
inline void PS2X::ATT_CLR(void) {
|
||||
register uint8_t old_sreg = SREG;
|
||||
cli();
|
||||
*_att_oreg &= ~_att_mask;
|
||||
SREG = old_sreg;
|
||||
}
|
||||
|
||||
inline bool PS2X::DAT_CHK(void) {
|
||||
return (*_dat_ireg & _dat_mask) ? true : false;
|
||||
}
|
||||
|
||||
#else
|
||||
// On pic32, use the set/clr registers to make them atomic...
|
||||
inline void PS2X::CLK_SET(void) {
|
||||
*_clk_lport_set |= _clk_mask;
|
||||
}
|
||||
|
||||
inline void PS2X::CLK_CLR(void) {
|
||||
*_clk_lport_clr |= _clk_mask;
|
||||
}
|
||||
|
||||
inline void PS2X::CMD_SET(void) {
|
||||
*_cmd_lport_set |= _cmd_mask;
|
||||
}
|
||||
|
||||
inline void PS2X::CMD_CLR(void) {
|
||||
*_cmd_lport_clr |= _cmd_mask;
|
||||
}
|
||||
|
||||
inline void PS2X::ATT_SET(void) {
|
||||
*_att_lport_set |= _att_mask;
|
||||
}
|
||||
|
||||
inline void PS2X::ATT_CLR(void) {
|
||||
*_att_lport_clr |= _att_mask;
|
||||
}
|
||||
|
||||
inline bool PS2X::DAT_CHK(void) {
|
||||
return (*_dat_lport & _dat_mask) ? true : false;
|
||||
}
|
||||
|
||||
#endif
|
||||
236
arduino-libs/arduino-cli/libraries/yfrobot/PS2X_lib.h
Normal file
236
arduino-libs/arduino-cli/libraries/yfrobot/PS2X_lib.h
Normal file
@@ -0,0 +1,236 @@
|
||||
/******************************************************************
|
||||
* Super amazing PS2 controller Arduino Library v1.8
|
||||
* details and example sketch:
|
||||
* http://www.billporter.info/?p=240
|
||||
*
|
||||
* Original code by Shutter on Arduino Forums
|
||||
*
|
||||
* Revamped, made into lib by and supporting continued development:
|
||||
* Bill Porter
|
||||
* www.billporter.info
|
||||
*
|
||||
* Contributers:
|
||||
* Eric Wetzel (thewetzel@gmail.com)
|
||||
* Kurt Eckhardt
|
||||
*
|
||||
* Lib version history
|
||||
* 0.1 made into library, added analog stick support.
|
||||
* 0.2 fixed config_gamepad miss-spelling
|
||||
* added new functions:
|
||||
* NewButtonState();
|
||||
* NewButtonState(unsigned int);
|
||||
* ButtonPressed(unsigned int);
|
||||
* ButtonReleased(unsigned int);
|
||||
* removed 'PS' from begining of ever function
|
||||
* 1.0 found and fixed bug that wasn't configuring controller
|
||||
* added ability to define pins
|
||||
* added time checking to reconfigure controller if not polled enough
|
||||
* Analog sticks and pressures all through 'ps2x.Analog()' function
|
||||
* added:
|
||||
* enableRumble();
|
||||
* enablePressures();
|
||||
* 1.1
|
||||
* added some debug stuff for end user. Reports if no controller found
|
||||
* added auto-increasing sentence delay to see if it helps compatibility.
|
||||
* 1.2
|
||||
* found bad math by Shutter for original clock. Was running at 50kHz, not the required 500kHz.
|
||||
* fixed some of the debug reporting.
|
||||
* 1.3
|
||||
* Changed clock back to 50kHz. CuriousInventor says it's suppose to be 500kHz, but doesn't seem to work for everybody.
|
||||
* 1.4
|
||||
* Removed redundant functions.
|
||||
* Fixed mode check to include two other possible modes the controller could be in.
|
||||
* Added debug code enabled by compiler directives. See below to enable debug mode.
|
||||
* Added button definitions for shapes as well as colors.
|
||||
* 1.41
|
||||
* Some simple bug fixes
|
||||
* Added Keywords.txt file
|
||||
* 1.5
|
||||
* Added proper Guitar Hero compatibility
|
||||
* Fixed issue with DEBUG mode, had to send serial at once instead of in bits
|
||||
* 1.6
|
||||
* Changed config_gamepad() call to include rumble and pressures options
|
||||
* This was to fix controllers that will only go into config mode once
|
||||
* Old methods should still work for backwards compatibility
|
||||
* 1.7
|
||||
* Integrated Kurt's fixes for the interrupts messing with servo signals
|
||||
* Reorganized directory so examples show up in Arduino IDE menu
|
||||
* 1.8
|
||||
* Added Arduino 1.0 compatibility.
|
||||
* 1.9
|
||||
* Kurt - Added detection and recovery from dropping from analog mode, plus
|
||||
* integreated Chipkit (pic32mx...) support
|
||||
*
|
||||
*
|
||||
*
|
||||
*This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
<http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
// $$$$$$$$$$$$ DEBUG ENABLE SECTION $$$$$$$$$$$$$$$$
|
||||
// to debug ps2 controller, uncomment these two lines to print out debug to uart
|
||||
// #define PS2X_DEBUG
|
||||
// #define PS2X_COM_DEBUG
|
||||
|
||||
#ifndef PS2X_lib_h
|
||||
#define PS2X_lib_h
|
||||
|
||||
#if ARDUINO > 22
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#ifdef __AVR__
|
||||
// AVR
|
||||
#include <avr/io.h>
|
||||
#define CTRL_CLK 4
|
||||
#define CTRL_BYTE_DELAY 3
|
||||
#else
|
||||
// Pic32...
|
||||
#include <pins_arduino.h>
|
||||
#define CTRL_CLK 5
|
||||
#define CTRL_CLK_HIGH 5
|
||||
#define CTRL_BYTE_DELAY 4
|
||||
#endif
|
||||
|
||||
//These are our button constants
|
||||
#define PSB_SELECT 0x0001
|
||||
#define PSB_L3 0x0002
|
||||
#define PSB_R3 0x0004
|
||||
#define PSB_START 0x0008
|
||||
#define PSB_PAD_UP 0x0010
|
||||
#define PSB_PAD_RIGHT 0x0020
|
||||
#define PSB_PAD_DOWN 0x0040
|
||||
#define PSB_PAD_LEFT 0x0080
|
||||
#define PSB_L2 0x0100
|
||||
#define PSB_R2 0x0200
|
||||
#define PSB_L1 0x0400
|
||||
#define PSB_R1 0x0800
|
||||
#define PSB_GREEN 0x1000
|
||||
#define PSB_RED 0x2000
|
||||
#define PSB_BLUE 0x4000
|
||||
#define PSB_PINK 0x8000
|
||||
#define PSB_TRIANGLE 0x1000
|
||||
#define PSB_CIRCLE 0x2000
|
||||
#define PSB_CROSS 0x4000
|
||||
#define PSB_SQUARE 0x8000
|
||||
|
||||
//Guitar button constants
|
||||
#define UP_STRUM 0x0010
|
||||
#define DOWN_STRUM 0x0040
|
||||
#define STAR_POWER 0x0100
|
||||
#define GREEN_FRET 0x0200
|
||||
#define YELLOW_FRET 0x1000
|
||||
#define RED_FRET 0x2000
|
||||
#define BLUE_FRET 0x4000
|
||||
#define ORANGE_FRET 0x8000
|
||||
#define WHAMMY_BAR 8
|
||||
|
||||
//These are stick values
|
||||
#define PSS_RX 5
|
||||
#define PSS_RY 6
|
||||
#define PSS_LX 7
|
||||
#define PSS_LY 8
|
||||
|
||||
//These are analog buttons
|
||||
#define PSAB_PAD_RIGHT 9
|
||||
#define PSAB_PAD_UP 11
|
||||
#define PSAB_PAD_DOWN 12
|
||||
#define PSAB_PAD_LEFT 10
|
||||
#define PSAB_L2 19
|
||||
#define PSAB_R2 20
|
||||
#define PSAB_L1 17
|
||||
#define PSAB_R1 18
|
||||
#define PSAB_GREEN 13
|
||||
#define PSAB_RED 14
|
||||
#define PSAB_BLUE 15
|
||||
#define PSAB_PINK 16
|
||||
#define PSAB_TRIANGLE 13
|
||||
#define PSAB_CIRCLE 14
|
||||
#define PSAB_CROSS 15
|
||||
#define PSAB_SQUARE 16
|
||||
|
||||
#define SET(x,y) (x|=(1<<y))
|
||||
#define CLR(x,y) (x&=(~(1<<y)))
|
||||
#define CHK(x,y) (x & (1<<y))
|
||||
#define TOG(x,y) (x^=(1<<y))
|
||||
|
||||
class PS2X {
|
||||
public:
|
||||
boolean Button(uint16_t); //will be TRUE if button is being pressed
|
||||
unsigned int ButtonDataByte();
|
||||
boolean NewButtonState();
|
||||
boolean NewButtonState(unsigned int); //will be TRUE if button was JUST pressed OR released
|
||||
boolean ButtonPressed(unsigned int); //will be TRUE if button was JUST pressed
|
||||
boolean ButtonReleased(unsigned int); //will be TRUE if button was JUST released
|
||||
void read_gamepad();
|
||||
boolean read_gamepad(boolean, byte);
|
||||
byte readType();
|
||||
byte config_gamepad(uint8_t, uint8_t, uint8_t, uint8_t);
|
||||
byte config_gamepad(uint8_t, uint8_t, uint8_t, uint8_t, bool, bool);
|
||||
void enableRumble();
|
||||
bool enablePressures();
|
||||
byte Analog(byte);
|
||||
void reconfig_gamepad();
|
||||
|
||||
private:
|
||||
inline void CLK_SET(void);
|
||||
inline void CLK_CLR(void);
|
||||
inline void CMD_SET(void);
|
||||
inline void CMD_CLR(void);
|
||||
inline void ATT_SET(void);
|
||||
inline void ATT_CLR(void);
|
||||
inline bool DAT_CHK(void);
|
||||
|
||||
unsigned char _gamepad_shiftinout (char);
|
||||
unsigned char PS2data[21];
|
||||
void sendCommandString(byte*, byte);
|
||||
unsigned char i;
|
||||
unsigned int last_buttons;
|
||||
unsigned int buttons;
|
||||
|
||||
#ifdef __AVR__
|
||||
uint8_t maskToBitNum(uint8_t);
|
||||
uint8_t _clk_mask;
|
||||
volatile uint8_t *_clk_oreg;
|
||||
uint8_t _cmd_mask;
|
||||
volatile uint8_t *_cmd_oreg;
|
||||
uint8_t _att_mask;
|
||||
volatile uint8_t *_att_oreg;
|
||||
uint8_t _dat_mask;
|
||||
volatile uint8_t *_dat_ireg;
|
||||
#else
|
||||
uint8_t maskToBitNum(uint8_t);
|
||||
uint16_t _clk_mask;
|
||||
volatile uint32_t *_clk_lport_set;
|
||||
volatile uint32_t *_clk_lport_clr;
|
||||
uint16_t _cmd_mask;
|
||||
volatile uint32_t *_cmd_lport_set;
|
||||
volatile uint32_t *_cmd_lport_clr;
|
||||
uint16_t _att_mask;
|
||||
volatile uint32_t *_att_lport_set;
|
||||
volatile uint32_t *_att_lport_clr;
|
||||
uint16_t _dat_mask;
|
||||
volatile uint32_t *_dat_lport;
|
||||
#endif
|
||||
|
||||
unsigned long last_read;
|
||||
byte read_delay;
|
||||
byte controller_type;
|
||||
boolean en_Rumble;
|
||||
boolean en_Pressures;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
700
arduino-libs/arduino-cli/libraries/yfrobot/QTRSensors.cpp
Normal file
700
arduino-libs/arduino-cli/libraries/yfrobot/QTRSensors.cpp
Normal file
@@ -0,0 +1,700 @@
|
||||
#include "QTRSensors.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
void QTRSensors::setTypeRC()
|
||||
{
|
||||
_type = QTRType::RC;
|
||||
_maxValue = _timeout;
|
||||
}
|
||||
|
||||
void QTRSensors::setTypeAnalog()
|
||||
{
|
||||
_type = QTRType::Analog;
|
||||
_maxValue = 1023; // Arduino analogRead() returns a 10-bit value by default
|
||||
}
|
||||
|
||||
void QTRSensors::setSensorPins(const uint8_t * pins, uint8_t sensorCount)
|
||||
{
|
||||
if (sensorCount > QTRMaxSensors) { sensorCount = QTRMaxSensors; }
|
||||
|
||||
// (Re)allocate and initialize the array if necessary.
|
||||
uint8_t * oldSensorPins = _sensorPins;
|
||||
_sensorPins = (uint8_t *)realloc(_sensorPins, sizeof(uint8_t) * sensorCount);
|
||||
if (_sensorPins == nullptr)
|
||||
{
|
||||
// Memory allocation failed; don't continue.
|
||||
free(oldSensorPins); // deallocate any memory used by old array
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < sensorCount; i++)
|
||||
{
|
||||
_sensorPins[i] = pins[i];
|
||||
}
|
||||
|
||||
_sensorCount = sensorCount;
|
||||
|
||||
// Any previous calibration values are no longer valid, and the calibration
|
||||
// arrays might need to be reallocated if the sensor count was changed.
|
||||
calibrationOn.initialized = false;
|
||||
calibrationOff.initialized = false;
|
||||
}
|
||||
|
||||
void QTRSensors::setTimeout(uint16_t timeout)
|
||||
{
|
||||
if (timeout > 32767) { timeout = 32767; }
|
||||
_timeout = timeout;
|
||||
if (_type == QTRType::RC) { _maxValue = timeout; }
|
||||
}
|
||||
|
||||
void QTRSensors::setSamplesPerSensor(uint8_t samples)
|
||||
{
|
||||
if (samples > 64) { samples = 64; }
|
||||
_samplesPerSensor = samples;
|
||||
}
|
||||
|
||||
void QTRSensors::setEmitterPin(uint8_t emitterPin)
|
||||
{
|
||||
releaseEmitterPins();
|
||||
|
||||
_oddEmitterPin = emitterPin;
|
||||
pinMode(_oddEmitterPin, OUTPUT);
|
||||
|
||||
_emitterPinCount = 1;
|
||||
}
|
||||
|
||||
void QTRSensors::setEmitterPins(uint8_t oddEmitterPin, uint8_t evenEmitterPin)
|
||||
{
|
||||
releaseEmitterPins();
|
||||
|
||||
_oddEmitterPin = oddEmitterPin;
|
||||
_evenEmitterPin = evenEmitterPin;
|
||||
pinMode(_oddEmitterPin, OUTPUT);
|
||||
pinMode(_evenEmitterPin, OUTPUT);
|
||||
|
||||
_emitterPinCount = 2;
|
||||
}
|
||||
|
||||
void QTRSensors::releaseEmitterPins()
|
||||
{
|
||||
if (_oddEmitterPin != QTRNoEmitterPin)
|
||||
{
|
||||
pinMode(_oddEmitterPin, INPUT);
|
||||
_oddEmitterPin = QTRNoEmitterPin;
|
||||
}
|
||||
|
||||
if (_evenEmitterPin != QTRNoEmitterPin)
|
||||
{
|
||||
pinMode(_evenEmitterPin, INPUT);
|
||||
_evenEmitterPin = QTRNoEmitterPin;
|
||||
}
|
||||
|
||||
_emitterPinCount = 0;
|
||||
}
|
||||
|
||||
void QTRSensors::setDimmingLevel(uint8_t dimmingLevel)
|
||||
{
|
||||
if (dimmingLevel > 31) { dimmingLevel = 31; }
|
||||
_dimmingLevel = dimmingLevel;
|
||||
}
|
||||
|
||||
// emitters defaults to QTREmitters::All; wait defaults to true
|
||||
void QTRSensors::emittersOff(QTREmitters emitters, bool wait)
|
||||
{
|
||||
bool pinChanged = false;
|
||||
|
||||
// Use odd emitter pin in these cases:
|
||||
// - 1 emitter pin, emitters = all
|
||||
// - 2 emitter pins, emitters = all
|
||||
// - 2 emitter pins, emitters = odd
|
||||
if (emitters == QTREmitters::All ||
|
||||
(_emitterPinCount == 2 && emitters == QTREmitters::Odd))
|
||||
{
|
||||
// Check if pin is defined and only turn off if not already off
|
||||
if ((_oddEmitterPin != QTRNoEmitterPin) &&
|
||||
(digitalRead(_oddEmitterPin) == HIGH))
|
||||
{
|
||||
digitalWrite(_oddEmitterPin, LOW);
|
||||
pinChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Use even emitter pin in these cases:
|
||||
// - 2 emitter pins, emitters = all
|
||||
// - 2 emitter pins, emitters = even
|
||||
if (_emitterPinCount == 2 &&
|
||||
(emitters == QTREmitters::All || emitters == QTREmitters::Even))
|
||||
{
|
||||
// Check if pin is defined and only turn off if not already off
|
||||
if ((_evenEmitterPin != QTRNoEmitterPin) &&
|
||||
(digitalRead(_evenEmitterPin) == HIGH))
|
||||
{
|
||||
digitalWrite(_evenEmitterPin, LOW);
|
||||
pinChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (wait && pinChanged)
|
||||
{
|
||||
if (_dimmable)
|
||||
{
|
||||
// driver min is 1 ms
|
||||
delayMicroseconds(1200);
|
||||
}
|
||||
else
|
||||
{
|
||||
delayMicroseconds(200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QTRSensors::emittersOn(QTREmitters emitters, bool wait)
|
||||
{
|
||||
bool pinChanged = false;
|
||||
uint16_t emittersOnStart;
|
||||
|
||||
// Use odd emitter pin in these cases:
|
||||
// - 1 emitter pin, emitters = all
|
||||
// - 2 emitter pins, emitters = all
|
||||
// - 2 emitter pins, emitters = odd
|
||||
if (emitters == QTREmitters::All ||
|
||||
(_emitterPinCount == 2 && emitters == QTREmitters::Odd))
|
||||
{
|
||||
// Check if pin is defined, and only turn on non-dimmable sensors if not
|
||||
// already on, but always turn dimmable sensors off and back on because
|
||||
// we might be changing the dimming level (emittersOnWithPin() should take
|
||||
// care of this)
|
||||
if ((_oddEmitterPin != QTRNoEmitterPin) &&
|
||||
( _dimmable || (digitalRead(_oddEmitterPin) == LOW)))
|
||||
{
|
||||
emittersOnStart = emittersOnWithPin(_oddEmitterPin);
|
||||
pinChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Use even emitter pin in these cases:
|
||||
// - 2 emitter pins, emitters = all
|
||||
// - 2 emitter pins, emitters = even
|
||||
if (_emitterPinCount == 2 &&
|
||||
(emitters == QTREmitters::All || emitters == QTREmitters::Even))
|
||||
{
|
||||
// Check if pin is defined, and only turn on non-dimmable sensors if not
|
||||
// already on, but always turn dimmable sensors off and back on because
|
||||
// we might be changing the dimming level (emittersOnWithPin() should take
|
||||
// care of this)
|
||||
if ((_evenEmitterPin != QTRNoEmitterPin) &&
|
||||
(_dimmable || (digitalRead(_evenEmitterPin) == LOW)))
|
||||
{
|
||||
emittersOnStart = emittersOnWithPin(_evenEmitterPin);
|
||||
pinChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (wait && pinChanged)
|
||||
{
|
||||
if (_dimmable)
|
||||
{
|
||||
// Make sure it's been at least 300 us since the emitter pin was first set
|
||||
// high before returning. (Driver min is 250 us.) Some time might have
|
||||
// already passed while we set the dimming level.
|
||||
while ((uint16_t)(micros() - emittersOnStart) < 300)
|
||||
{
|
||||
delayMicroseconds(10);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delayMicroseconds(200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// assumes pin is valid (not QTRNoEmitterPin)
|
||||
// returns time when pin was first set high (used by emittersSelect())
|
||||
uint16_t QTRSensors::emittersOnWithPin(uint8_t pin)
|
||||
{
|
||||
if (_dimmable && (digitalRead(pin) == HIGH))
|
||||
{
|
||||
// We are turning on dimmable emitters that are already on. To avoid messing
|
||||
// up the dimming level, we have to turn the emitters off and back on. This
|
||||
// means the turn-off delay will happen even if wait = false was passed to
|
||||
// emittersOn(). (Driver min is 1 ms.)
|
||||
digitalWrite(pin, LOW);
|
||||
delayMicroseconds(1200);
|
||||
}
|
||||
|
||||
digitalWrite(pin, HIGH);
|
||||
uint16_t emittersOnStart = micros();
|
||||
|
||||
if (_dimmable && (_dimmingLevel > 0))
|
||||
{
|
||||
noInterrupts();
|
||||
|
||||
for (uint8_t i = 0; i < _dimmingLevel; i++)
|
||||
{
|
||||
delayMicroseconds(1);
|
||||
digitalWrite(pin, LOW);
|
||||
delayMicroseconds(1);
|
||||
digitalWrite(pin, HIGH);
|
||||
}
|
||||
|
||||
interrupts();
|
||||
}
|
||||
|
||||
return emittersOnStart;
|
||||
}
|
||||
|
||||
void QTRSensors::emittersSelect(QTREmitters emitters)
|
||||
{
|
||||
QTREmitters offEmitters;
|
||||
|
||||
switch (emitters)
|
||||
{
|
||||
case QTREmitters::Odd:
|
||||
offEmitters = QTREmitters::Even;
|
||||
break;
|
||||
|
||||
case QTREmitters::Even:
|
||||
offEmitters = QTREmitters::Odd;
|
||||
break;
|
||||
|
||||
case QTREmitters::All:
|
||||
emittersOn();
|
||||
return;
|
||||
|
||||
case QTREmitters::None:
|
||||
emittersOff();
|
||||
return;
|
||||
|
||||
default: // invalid
|
||||
return;
|
||||
}
|
||||
|
||||
// Turn off the off-emitters; don't wait before proceeding, but record the time.
|
||||
emittersOff(offEmitters, false);
|
||||
uint16_t turnOffStart = micros();
|
||||
|
||||
// Turn on the on-emitters and wait.
|
||||
emittersOn(emitters);
|
||||
|
||||
if (_dimmable)
|
||||
{
|
||||
// Finish waiting for the off-emitters emitters to turn off: make sure it's been
|
||||
// at least 1200 us since the off-emitters was turned off before returning.
|
||||
// (Driver min is 1 ms.) Some time has already passed while we waited for
|
||||
// the on-emitters to turn on.
|
||||
while ((uint16_t)(micros() - turnOffStart) < 1200)
|
||||
{
|
||||
delayMicroseconds(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QTRSensors::resetCalibration()
|
||||
{
|
||||
for (uint8_t i = 0; i < _sensorCount; i++)
|
||||
{
|
||||
if (calibrationOn.maximum) { calibrationOn.maximum[i] = 0; }
|
||||
if (calibrationOff.maximum) { calibrationOff.maximum[i] = 0; }
|
||||
if (calibrationOn.minimum) { calibrationOn.minimum[i] = _maxValue; }
|
||||
if (calibrationOff.minimum) { calibrationOff.minimum[i] = _maxValue; }
|
||||
}
|
||||
}
|
||||
|
||||
void QTRSensors::calibrate(QTRReadMode mode)
|
||||
{
|
||||
// manual emitter control is not supported
|
||||
if (mode == QTRReadMode::Manual) { return; }
|
||||
|
||||
if (mode == QTRReadMode::On ||
|
||||
mode == QTRReadMode::OnAndOff)
|
||||
{
|
||||
calibrateOnOrOff(calibrationOn, QTRReadMode::On);
|
||||
}
|
||||
else if (mode == QTRReadMode::OddEven ||
|
||||
mode == QTRReadMode::OddEvenAndOff)
|
||||
{
|
||||
calibrateOnOrOff(calibrationOn, QTRReadMode::OddEven);
|
||||
}
|
||||
|
||||
if (mode == QTRReadMode::OnAndOff ||
|
||||
mode == QTRReadMode::OddEvenAndOff ||
|
||||
mode == QTRReadMode::Off)
|
||||
{
|
||||
calibrateOnOrOff(calibrationOff, QTRReadMode::Off);
|
||||
}
|
||||
}
|
||||
|
||||
void QTRSensors::calibrateOnOrOff(CalibrationData & calibration, QTRReadMode mode)
|
||||
{
|
||||
uint16_t sensorValues[QTRMaxSensors];
|
||||
uint16_t maxSensorValues[QTRMaxSensors];
|
||||
uint16_t minSensorValues[QTRMaxSensors];
|
||||
|
||||
// (Re)allocate and initialize the arrays if necessary.
|
||||
if (!calibration.initialized)
|
||||
{
|
||||
uint16_t * oldMaximum = calibration.maximum;
|
||||
calibration.maximum = (uint16_t *)realloc(calibration.maximum,
|
||||
sizeof(uint16_t) * _sensorCount);
|
||||
if (calibration.maximum == nullptr)
|
||||
{
|
||||
// Memory allocation failed; don't continue.
|
||||
free(oldMaximum); // deallocate any memory used by old array
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t * oldMinimum = calibration.minimum;
|
||||
calibration.minimum = (uint16_t *)realloc(calibration.minimum,
|
||||
sizeof(uint16_t) * _sensorCount);
|
||||
if (calibration.minimum == nullptr)
|
||||
{
|
||||
// Memory allocation failed; don't continue.
|
||||
free(oldMinimum); // deallocate any memory used by old array
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize the max and min calibrated values to values that
|
||||
// will cause the first reading to update them.
|
||||
for (uint8_t i = 0; i < _sensorCount; i++)
|
||||
{
|
||||
calibration.maximum[i] = 0;
|
||||
calibration.minimum[i] = _maxValue;
|
||||
}
|
||||
|
||||
calibration.initialized = true;
|
||||
}
|
||||
|
||||
for (uint8_t j = 0; j < 10; j++)
|
||||
{
|
||||
read(sensorValues, mode);
|
||||
|
||||
for (uint8_t i = 0; i < _sensorCount; i++)
|
||||
{
|
||||
// set the max we found THIS time
|
||||
if ((j == 0) || (sensorValues[i] > maxSensorValues[i]))
|
||||
{
|
||||
maxSensorValues[i] = sensorValues[i];
|
||||
}
|
||||
|
||||
// set the min we found THIS time
|
||||
if ((j == 0) || (sensorValues[i] < minSensorValues[i]))
|
||||
{
|
||||
minSensorValues[i] = sensorValues[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// record the min and max calibration values
|
||||
for (uint8_t i = 0; i < _sensorCount; i++)
|
||||
{
|
||||
// Update maximum only if the min of 10 readings was still higher than it
|
||||
// (we got 10 readings in a row higher than the existing maximum).
|
||||
if (minSensorValues[i] > calibration.maximum[i])
|
||||
{
|
||||
calibration.maximum[i] = minSensorValues[i];
|
||||
}
|
||||
|
||||
// Update minimum only if the max of 10 readings was still lower than it
|
||||
// (we got 10 readings in a row lower than the existing minimum).
|
||||
if (maxSensorValues[i] < calibration.minimum[i])
|
||||
{
|
||||
calibration.minimum[i] = maxSensorValues[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QTRSensors::read(uint16_t * sensorValues, QTRReadMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case QTRReadMode::Off:
|
||||
emittersOff();
|
||||
// fall through
|
||||
case QTRReadMode::Manual:
|
||||
readPrivate(sensorValues);
|
||||
return;
|
||||
|
||||
case QTRReadMode::On:
|
||||
case QTRReadMode::OnAndOff:
|
||||
emittersOn();
|
||||
readPrivate(sensorValues);
|
||||
emittersOff();
|
||||
break;
|
||||
|
||||
case QTRReadMode::OddEven:
|
||||
case QTRReadMode::OddEvenAndOff:
|
||||
// Turn on odd emitters and read the odd-numbered sensors.
|
||||
// (readPrivate takes a 0-based array index, so start = 0 to start with
|
||||
// the first sensor)
|
||||
emittersSelect(QTREmitters::Odd);
|
||||
readPrivate(sensorValues, 0, 2);
|
||||
|
||||
// Turn on even emitters and read the even-numbered sensors.
|
||||
// (readPrivate takes a 0-based array index, so start = 1 to start with
|
||||
// the second sensor)
|
||||
emittersSelect(QTREmitters::Even);
|
||||
readPrivate(sensorValues, 1, 2);
|
||||
|
||||
emittersOff();
|
||||
break;
|
||||
|
||||
default: // invalid - do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == QTRReadMode::OnAndOff ||
|
||||
mode == QTRReadMode::OddEvenAndOff)
|
||||
{
|
||||
// Take a second set of readings and return the values (on + max - off).
|
||||
|
||||
uint16_t offValues[QTRMaxSensors];
|
||||
readPrivate(offValues);
|
||||
|
||||
for (uint8_t i = 0; i < _sensorCount; i++)
|
||||
{
|
||||
sensorValues[i] += _maxValue - offValues[i];
|
||||
if (sensorValues[i] > _maxValue)
|
||||
{
|
||||
// This usually doesn't happen, because the sensor reading should
|
||||
// go up when the emitters are turned off.
|
||||
sensorValues[i] = _maxValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QTRSensors::readCalibrated(uint16_t * sensorValues, QTRReadMode mode)
|
||||
{
|
||||
// manual emitter control is not supported
|
||||
if (mode == QTRReadMode::Manual) { return; }
|
||||
|
||||
// if not calibrated, do nothing
|
||||
|
||||
if (mode == QTRReadMode::On ||
|
||||
mode == QTRReadMode::OnAndOff ||
|
||||
mode == QTRReadMode::OddEvenAndOff)
|
||||
{
|
||||
if (!calibrationOn.initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == QTRReadMode::Off ||
|
||||
mode == QTRReadMode::OnAndOff ||
|
||||
mode == QTRReadMode::OddEvenAndOff)
|
||||
{
|
||||
if (!calibrationOff.initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// read the needed values
|
||||
read(sensorValues, mode);
|
||||
|
||||
for (uint8_t i = 0; i < _sensorCount; i++)
|
||||
{
|
||||
uint16_t calmin, calmax;
|
||||
|
||||
// find the correct calibration
|
||||
if (mode == QTRReadMode::On ||
|
||||
mode == QTRReadMode::OddEven)
|
||||
{
|
||||
calmax = calibrationOn.maximum[i];
|
||||
calmin = calibrationOn.minimum[i];
|
||||
}
|
||||
else if (mode == QTRReadMode::Off)
|
||||
{
|
||||
calmax = calibrationOff.maximum[i];
|
||||
calmin = calibrationOff.minimum[i];
|
||||
}
|
||||
else // QTRReadMode::OnAndOff, QTRReadMode::OddEvenAndOff
|
||||
{
|
||||
if (calibrationOff.minimum[i] < calibrationOn.minimum[i])
|
||||
{
|
||||
// no meaningful signal
|
||||
calmin = _maxValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this won't go past _maxValue
|
||||
calmin = calibrationOn.minimum[i] + _maxValue - calibrationOff.minimum[i];
|
||||
}
|
||||
|
||||
if (calibrationOff.maximum[i] < calibrationOn.maximum[i])
|
||||
{
|
||||
// no meaningful signal
|
||||
calmax = _maxValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this won't go past _maxValue
|
||||
calmax = calibrationOn.maximum[i] + _maxValue - calibrationOff.maximum[i];
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t denominator = calmax - calmin;
|
||||
int16_t value = 0;
|
||||
|
||||
if (denominator != 0)
|
||||
{
|
||||
value = (((int32_t)sensorValues[i]) - calmin) * 1000 / denominator;
|
||||
}
|
||||
|
||||
if (value < 0) { value = 0; }
|
||||
else if (value > 1000) { value = 1000; }
|
||||
|
||||
sensorValues[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Reads the first of every [step] sensors, starting with [start] (0-indexed, so
|
||||
// start = 0 means start with the first sensor).
|
||||
// For example, step = 2, start = 1 means read the *even-numbered* sensors.
|
||||
// start defaults to 0, step defaults to 1
|
||||
void QTRSensors::readPrivate(uint16_t * sensorValues, uint8_t start, uint8_t step)
|
||||
{
|
||||
if (_sensorPins == nullptr) { return; }
|
||||
|
||||
switch (_type)
|
||||
{
|
||||
case QTRType::RC:
|
||||
for (uint8_t i = start; i < _sensorCount; i += step)
|
||||
{
|
||||
sensorValues[i] = _maxValue;
|
||||
// make sensor line an output (drives low briefly, but doesn't matter)
|
||||
pinMode(_sensorPins[i], OUTPUT);
|
||||
// drive sensor line high
|
||||
digitalWrite(_sensorPins[i], HIGH);
|
||||
}
|
||||
|
||||
delayMicroseconds(10); // charge lines for 10 us
|
||||
|
||||
{
|
||||
// disable interrupts so we can switch all the pins as close to the same
|
||||
// time as possible
|
||||
noInterrupts();
|
||||
|
||||
// record start time before the first sensor is switched to input
|
||||
// (similarly, time is checked before the first sensor is read in the
|
||||
// loop below)
|
||||
uint32_t startTime = micros();
|
||||
uint16_t time = 0;
|
||||
|
||||
for (uint8_t i = start; i < _sensorCount; i += step)
|
||||
{
|
||||
// make sensor line an input (should also ensure pull-up is disabled)
|
||||
pinMode(_sensorPins[i], INPUT);
|
||||
}
|
||||
|
||||
interrupts(); // re-enable
|
||||
|
||||
while (time < _maxValue)
|
||||
{
|
||||
// disable interrupts so we can read all the pins as close to the same
|
||||
// time as possible
|
||||
noInterrupts();
|
||||
|
||||
time = micros() - startTime;
|
||||
for (uint8_t i = start; i < _sensorCount; i += step)
|
||||
{
|
||||
if ((digitalRead(_sensorPins[i]) == LOW) && (time < sensorValues[i]))
|
||||
{
|
||||
// record the first time the line reads low
|
||||
sensorValues[i] = time;
|
||||
}
|
||||
}
|
||||
|
||||
interrupts(); // re-enable
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
case QTRType::Analog:
|
||||
// reset the values
|
||||
for (uint8_t i = start; i < _sensorCount; i += step)
|
||||
{
|
||||
sensorValues[i] = 0;
|
||||
}
|
||||
|
||||
for (uint8_t j = 0; j < _samplesPerSensor; j++)
|
||||
{
|
||||
for (uint8_t i = start; i < _sensorCount; i += step)
|
||||
{
|
||||
// add the conversion result
|
||||
sensorValues[i] += analogRead(_sensorPins[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// get the rounded average of the readings for each sensor
|
||||
for (uint8_t i = start; i < _sensorCount; i += step)
|
||||
{
|
||||
sensorValues[i] = (sensorValues[i] + (_samplesPerSensor >> 1)) /
|
||||
_samplesPerSensor;
|
||||
}
|
||||
return;
|
||||
|
||||
default: // QTRType::Undefined or invalid - do nothing
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t QTRSensors::readLinePrivate(uint16_t * sensorValues, QTRReadMode mode,
|
||||
bool invertReadings)
|
||||
{
|
||||
bool onLine = false;
|
||||
uint32_t avg = 0; // this is for the weighted total
|
||||
uint16_t sum = 0; // this is for the denominator, which is <= 64000
|
||||
|
||||
// manual emitter control is not supported
|
||||
if (mode == QTRReadMode::Manual) { return 0; }
|
||||
|
||||
readCalibrated(sensorValues, mode);
|
||||
|
||||
for (uint8_t i = 0; i < _sensorCount; i++)
|
||||
{
|
||||
uint16_t value = sensorValues[i];
|
||||
if (invertReadings) { value = 1000 - value; }
|
||||
|
||||
// keep track of whether we see the line at all
|
||||
if (value > 200) { onLine = true; }
|
||||
|
||||
// only average in values that are above a noise threshold
|
||||
if (value > 50)
|
||||
{
|
||||
avg += (uint32_t)value * (i * 1000);
|
||||
sum += value;
|
||||
}
|
||||
}
|
||||
|
||||
if (!onLine)
|
||||
{
|
||||
// If it last read to the left of center, return 0.
|
||||
if (_lastPosition < (_sensorCount - 1) * 1000 / 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// If it last read to the right of center, return the max.
|
||||
else
|
||||
{
|
||||
return (_sensorCount - 1) * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
_lastPosition = avg / sum;
|
||||
return _lastPosition;
|
||||
}
|
||||
|
||||
// the destructor frees up allocated memory
|
||||
QTRSensors::~QTRSensors()
|
||||
{
|
||||
releaseEmitterPins();
|
||||
|
||||
if (_sensorPins) { free(_sensorPins); }
|
||||
if (calibrationOn.maximum) { free(calibrationOn.maximum); }
|
||||
if (calibrationOff.maximum) { free(calibrationOff.maximum); }
|
||||
if (calibrationOn.minimum) { free(calibrationOn.minimum); }
|
||||
if (calibrationOff.minimum) { free(calibrationOff.minimum); }
|
||||
}
|
||||
579
arduino-libs/arduino-cli/libraries/yfrobot/QTRSensors.h
Normal file
579
arduino-libs/arduino-cli/libraries/yfrobot/QTRSensors.h
Normal file
@@ -0,0 +1,579 @@
|
||||
/// \file QTRSensors.h
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/// \brief Emitter behavior when taking readings.
|
||||
///
|
||||
/// Note that emitter control will only work if you specify a valid emitter pin
|
||||
/// with setEmitterPin(), and the odd/even modes will only work if you are
|
||||
/// using a second-generation QTR or QTRX sensor with two emitter control pins
|
||||
/// and you specify both pins with setEmitterPins().
|
||||
enum class QTRReadMode : uint8_t {
|
||||
/// Each reading is made without turning on the infrared (IR) emitters. The
|
||||
/// reading represents ambient light levels near the sensor.
|
||||
Off,
|
||||
|
||||
/// Each reading is made with the emitters on. The reading is a measure of
|
||||
/// reflectance.
|
||||
On,
|
||||
|
||||
/// For each sensor, a reading is made in both the on and off states. The
|
||||
/// value returned is **on + max − off**, where **on** and **off** are
|
||||
/// the reading with the emitters on and off, respectively, and **max** is
|
||||
/// the maximum possible sensor reading. This mode can reduce the amount of
|
||||
/// interference from uneven ambient lighting.
|
||||
OnAndOff,
|
||||
|
||||
/// The odd-numbered sensors are read with the odd-numbered emitters on, then
|
||||
/// the even-numbered sensors are read with the even-numbered emitters on.
|
||||
/// This mode can reduce interference between adjacent sensors, especially on
|
||||
/// QTRX sensor boards. It is only usable with second-generation QTR and QTRX
|
||||
/// sensor arrays that have two emitter control pins.
|
||||
OddEven,
|
||||
|
||||
/// The odd and even sensors are read separately with the respective emitters
|
||||
/// on, then all sensors are read with emitters off and **on + max −
|
||||
/// off** is returned. (In other words, this mode combines OddEven and
|
||||
/// OnAndOff.)
|
||||
OddEvenAndOff,
|
||||
|
||||
/// Calling read() with this mode prevents it from automatically controlling
|
||||
/// the emitters: they are left in their existing states, which allows manual
|
||||
/// control of the emitters for testing and advanced use. Calibrating and
|
||||
/// obtaining calibrated readings are not supported with this mode.
|
||||
Manual
|
||||
};
|
||||
|
||||
/// Sensor types.
|
||||
enum class QTRType : uint8_t {
|
||||
Undefined,
|
||||
RC,
|
||||
Analog
|
||||
};
|
||||
|
||||
/// Emitters selected to turn on or off.
|
||||
enum class QTREmitters : uint8_t {
|
||||
All,
|
||||
Odd,
|
||||
Even,
|
||||
None
|
||||
};
|
||||
|
||||
/// Represents an undefined emitter control pin.
|
||||
const uint8_t QTRNoEmitterPin = 255;
|
||||
|
||||
/// Default timeout for RC sensors (in microseconds).
|
||||
const uint16_t QTRRCDefaultTimeout = 2500;
|
||||
|
||||
/// The maximum number of sensors supported by an instance of this class.
|
||||
const uint8_t QTRMaxSensors = 31;
|
||||
|
||||
/// \brief Represents a QTR sensor array.
|
||||
///
|
||||
/// An instance of this class represents a QTR sensor array, consisting of one
|
||||
/// or more sensors of the same type. This could be either a single QTR sensor
|
||||
/// board or multiple boards controlled as a group.
|
||||
///
|
||||
/// See \ref md_usage for an overview of how this library can be used and some
|
||||
/// example code.
|
||||
class QTRSensors
|
||||
{
|
||||
public:
|
||||
|
||||
QTRSensors() = default;
|
||||
|
||||
~QTRSensors();
|
||||
|
||||
/// \brief Specifies that the sensors are RC.
|
||||
///
|
||||
/// Call this function to set up RC-type sensors.
|
||||
void setTypeRC();
|
||||
|
||||
/// \brief Specifies that the sensor type is analog.
|
||||
///
|
||||
/// Call this function to set up A-type sensors.
|
||||
void setTypeAnalog();
|
||||
|
||||
/// \brief Returns the type of the sensors.
|
||||
///
|
||||
/// \return The sensor type as a member of the ::QTRType enum.
|
||||
///
|
||||
/// See also setTypeRC() and setTypeAnalog().
|
||||
QTRType getType() { return _type; }
|
||||
|
||||
/// \brief Sets the sensor pins.
|
||||
///
|
||||
/// \param[in] pins A pointer to an array containing the Arduino pins that
|
||||
/// the sensors are connected to.
|
||||
///
|
||||
/// \param sensorCount The number of sensors, which should match the length
|
||||
/// of the pins array.
|
||||
///
|
||||
/// Example usage:
|
||||
/// ~~~{.cpp}
|
||||
/// // Set pins for four RC sensors connected to pins 6, 7, A0, and A1.
|
||||
/// // (Most analog pins can also be used as digital pins.)
|
||||
/// qtr.setTypeRC();
|
||||
/// qtr.setSensorPins((const uint8_t[]){6, 7, A0, A1}, 4);
|
||||
/// ~~~
|
||||
/// ~~~{.cpp}
|
||||
/// // Set pins for four analog sensors connected to pins A2, A3, A4, and A5.
|
||||
/// qtr.setTypeAnalog();
|
||||
/// qtr.setSensorPins((const uint8_t[]){A2, A3, A4, A5}, 4);
|
||||
/// ~~~
|
||||
///
|
||||
/// If \link CalibrationData calibration data \endlink has already been
|
||||
/// stored, calling this method will force the storage for the calibration
|
||||
/// values to be reallocated and reinitialized the next time calibrate() is
|
||||
/// called (it sets `calibrationOn.initialized` and
|
||||
/// `calibrationOff.initialized` to false).
|
||||
void setSensorPins(const uint8_t * pins, uint8_t sensorCount);
|
||||
|
||||
/// \brief Sets the timeout for RC sensors.
|
||||
///
|
||||
/// \param timeout The length of time, in microseconds, beyond which you
|
||||
/// consider the sensor reading completely black.
|
||||
///
|
||||
/// If the pulse length for a pin exceeds \p timeout, pulse timing will
|
||||
/// stop and the reading for that pin will be considered full black. It is
|
||||
/// recommended that you set \p timeout to be between 1000 and 3000
|
||||
/// µs, depending on factors like the height of your sensors and
|
||||
/// ambient lighting. This allows you to shorten the duration of a
|
||||
/// sensor-reading cycle while maintaining useful measurements of
|
||||
/// reflectance. The default timeout is 2500 µs.
|
||||
///
|
||||
/// The maximum allowed timeout is 32767.
|
||||
/// (This prevents any possibility of an overflow when using
|
||||
/// QTRReadMode::OnAndOff or QTRReadMode::OddEvenAndOff).
|
||||
///
|
||||
/// The timeout setting only applies to RC sensors.
|
||||
void setTimeout(uint16_t timeout);
|
||||
|
||||
/// \brief Returns the timeout for RC sensors.
|
||||
///
|
||||
/// \return The RC sensor timeout in microseconds.
|
||||
///
|
||||
/// See also setTimeout().
|
||||
uint16_t getTimeout() { return _timeout; }
|
||||
|
||||
/// \brief Sets the number of analog readings to average per analog sensor.
|
||||
///
|
||||
/// \param samples The number of 10-bit analog samples (analog-to-digital
|
||||
/// conversions) to average per sensor each time it is read.
|
||||
///
|
||||
/// Increasing \p samples increases noise suppression at the cost of sample
|
||||
/// rate. The maximum number of samples per sensor is 64; the default is 4.
|
||||
///
|
||||
/// The samples per sensor setting only applies to analog sensors.
|
||||
void setSamplesPerSensor(uint8_t samples);
|
||||
|
||||
/// \brief Returns the number of analog readings to average per analog
|
||||
/// sensor.
|
||||
///
|
||||
/// \return The samples per channel for analog sensors.
|
||||
///
|
||||
/// See also setSamplesPerSensor().
|
||||
uint16_t getSamplesPerSensor() { return _samplesPerSensor; }
|
||||
|
||||
/// \brief Sets the emitter control pin for the sensors.
|
||||
///
|
||||
/// \param emitterPin The Arduino digital pin that controls whether the IR
|
||||
/// LEDs are on or off.
|
||||
///
|
||||
/// Specifying an emitter pin is optional, and the pin is not present on
|
||||
/// some QTR sensor boards. If a valid pin is connected and specified, the
|
||||
/// emitters will only be turned on during a reading; otherwise, the IR
|
||||
/// emitters will always be on. No emitter pin is specified by default.
|
||||
///
|
||||
/// With second-generation QTR or QTRX sensor arrays that have two emitter
|
||||
/// control pins, you can control all of the emitters together by
|
||||
/// specifying a single emitter pin connected to either the CTRL ODD or
|
||||
/// CTRL EVEN pin on the sensor board. For independent control of the odd-
|
||||
/// and even-numbered emitters, see setEmitterPins().
|
||||
///
|
||||
/// If you call this function after an emitter pin/pins have already been
|
||||
/// specified, any existing emitter pins will be released; see also
|
||||
/// releaseEmitterPins().
|
||||
void setEmitterPin(uint8_t emitterPin);
|
||||
|
||||
/// \brief Sets separate odd and even emitter control pins for the sensors.
|
||||
///
|
||||
/// \param oddEmitterPin The Arduino digital pin that controls the
|
||||
/// odd-numbered IR LEDs.
|
||||
///
|
||||
/// \param evenEmitterPin The Arduino digital pin that controls the
|
||||
/// even-numbered IR LEDs.
|
||||
///
|
||||
/// This function only works with second-generation QTR or QTRX sensor
|
||||
/// arrays that have two emitter control pins. To specify a single emitter
|
||||
/// pin for all sensors, see setEmitterPin().
|
||||
///
|
||||
/// If you call this function after an emitter pin/pins have already been
|
||||
/// specified, any existing emitter pins will be released; see also
|
||||
/// releaseEmitterPins().
|
||||
void setEmitterPins(uint8_t oddEmitterPin, uint8_t evenEmitterPin);
|
||||
|
||||
/// \brief Releases emitter pin/pins that have been set.
|
||||
///
|
||||
/// This function releases any emitter pins that were previously specified,
|
||||
/// making them inputs and stopping further control of the emitters through
|
||||
/// them.
|
||||
///
|
||||
/// See also setEmitterPin() and setEmitterPins().
|
||||
void releaseEmitterPins();
|
||||
|
||||
/// \brief Returns the number of emitter control pins in use.
|
||||
///
|
||||
/// \return The number of emitter control pins previously specified (1 with
|
||||
/// setEmitterPin() or 2 with setEmitterPins()). If no emitter pins have
|
||||
/// been specified (the default), or if previously specified pins were
|
||||
/// released with releaseEmitterPins(), this function returns 0.
|
||||
uint8_t getEmitterPinCount() { return _emitterPinCount; }
|
||||
|
||||
/// \brief Returns the emitter control pin.
|
||||
///
|
||||
/// \return The Arduino digital pin number of the emitter control pin
|
||||
/// (QTRNoEmitterPin if undefined).
|
||||
///
|
||||
/// This function is intended for use when there is a single emitter pin
|
||||
/// specified; you can use getOddEmitterPin() and getEvenEmitterPin()
|
||||
/// instead when two are specified.
|
||||
///
|
||||
/// See also setEmitterPin().
|
||||
uint8_t getEmitterPin() { return _oddEmitterPin; }
|
||||
|
||||
/// \brief Returns the odd emitter control pin.
|
||||
///
|
||||
/// \return The Arduino digital pin number of the odd emitter control pin
|
||||
/// (QTRNoEmitterPin if undefined).
|
||||
///
|
||||
/// This function is intended for use when there are separate odd and even
|
||||
/// emitter pins specified; you can use getEmitterPin() instead when only
|
||||
/// one is specified.
|
||||
///
|
||||
/// See also getEvenEmitterPin() and setEmitterPins().
|
||||
uint8_t getOddEmitterPin() { return _oddEmitterPin; }
|
||||
|
||||
/// \brief Returns the even emitter control pin.
|
||||
///
|
||||
/// \return The Arduino digital pin number of the even emitter control pin
|
||||
/// (QTRNoEmitterPin if undefined).
|
||||
///
|
||||
/// This function is intended for use when there are separate odd and even
|
||||
/// emitter pins specified; you can use getEmitterPin() instead when only
|
||||
/// one is specified.
|
||||
///
|
||||
/// See also getOddEmitterPin() and setEmitterPins().
|
||||
uint8_t getEvenEmitterPin() { return _evenEmitterPin; }
|
||||
|
||||
/// \brief Specifies that the sensors are dimmable.
|
||||
///
|
||||
/// Calling this function is optional when setting up second-generation QTR
|
||||
/// or QTRX sensors. By default, the library assumes the sensors are
|
||||
/// dimmable.
|
||||
///
|
||||
/// For first-generation QTR sensors, see setNonDimmable().
|
||||
void setDimmable() { _dimmable = true; }
|
||||
|
||||
/// \brief Specifies that the sensors are non-dimmable.
|
||||
///
|
||||
/// Call this function to set up first-generation QTR sensors and allow
|
||||
/// them to be read slightly faster (since their emitters can be turned on
|
||||
/// and off slightly more quickly than those on dimmable sensors).
|
||||
///
|
||||
/// See also setDimmable().
|
||||
void setNonDimmable() { _dimmable = false; }
|
||||
|
||||
/// \brief Returns whether the sensors are dimmable.
|
||||
///
|
||||
/// \return True if this object is configured to treat the sensors as
|
||||
/// dimmable, false otherwise.
|
||||
///
|
||||
/// See also setDimmable() and setNonDimmable().
|
||||
bool getDimmable() { return _dimmable; }
|
||||
|
||||
/// \brief Sets the dimming level.
|
||||
///
|
||||
/// \param dimmingLevel The dimming level (0 to 31). A dimming level of 0
|
||||
/// corresponds to full current and brightness, with higher dimming levels
|
||||
/// meaning lower currents.
|
||||
///
|
||||
/// See your sensor board's product page or documentation for details on
|
||||
/// the relationship of the dimming level to the LED current.
|
||||
///
|
||||
/// The dimming level will take effect the next time emittersOn() is called
|
||||
/// (either from your own program or by one of the library's read methods),
|
||||
/// and it will be applied again whenever the emitters are turned on after
|
||||
/// that.
|
||||
///
|
||||
/// This setting is only used by dimmable sensors, and an emitter control
|
||||
/// pin/pins must be connected and defined for dimming to be applied.
|
||||
void setDimmingLevel(uint8_t dimmingLevel);
|
||||
|
||||
/// \brief Returns the dimming level.
|
||||
///
|
||||
/// \return The dimming level.
|
||||
///
|
||||
/// See also setDimmingLevel().
|
||||
uint8_t getDimmingLevel() { return _dimmingLevel; }
|
||||
|
||||
/// \brief Turns the IR LEDs off.
|
||||
///
|
||||
/// \param emitters Which emitters to turn off, as a member of the
|
||||
/// ::QTREmitters enum. The default is QTREmitters::All.
|
||||
///
|
||||
/// \param wait If true (the default), this function delays to give the
|
||||
/// sensors time to turn off before returning. Otherwise, it returns
|
||||
/// immediately.
|
||||
///
|
||||
/// This function is mainly for use by the read() method. Since read()
|
||||
/// normally turns the emitters on and off automatically for each reading,
|
||||
/// calling this function yourself will not affect the readings unless the
|
||||
/// read mode is QTRReadMode::Manual, which tells read() to leave the
|
||||
/// emitters alone.
|
||||
void emittersOff(QTREmitters emitters = QTREmitters::All, bool wait = true);
|
||||
|
||||
/// \brief Turns the IR LEDs on.
|
||||
///
|
||||
/// \param emitters Which emitters to turn on, as a member of the
|
||||
/// ::QTREmitters enum. The default is QTREmitters::All.
|
||||
///
|
||||
/// \param wait If true (the default), this function delays to give the
|
||||
/// sensors time to turn on before returning. Otherwise, it returns
|
||||
/// immediately.
|
||||
///
|
||||
/// If the sensors are dimmable and a dimming level is set, this function
|
||||
/// will apply the dimming level after turning the emitters on.
|
||||
///
|
||||
/// This function is mainly for use by the read() method. Since read()
|
||||
/// normally turns the emitters on and off automatically for each reading,
|
||||
/// calling this function yourself will not affect the readings unless the
|
||||
/// read mode is QTRReadMode::Manual, which tells read() to leave the
|
||||
/// emitters alone.
|
||||
void emittersOn(QTREmitters emitters = QTREmitters::All, bool wait = true);
|
||||
|
||||
/// \brief Turns on the selected emitters and turns off the other emitters
|
||||
/// with optimized timing.
|
||||
///
|
||||
/// \param emitters Which emitters to turn on, as a member of the
|
||||
/// ::QTREmitters enum. The other emitters will be turned off.
|
||||
///
|
||||
/// This function turns on the selected emitters while it waits for the
|
||||
/// other emitters to turn off. For example,
|
||||
/// `emittersSelect(QTREmitters::Odd)` turns on the odd-numbered emitters
|
||||
/// while turning off the even-numbered emitters. Using this method avoids
|
||||
/// unnecessary delays compared to calling emittersOff() and emittersOn()
|
||||
/// separately, but it still waits for all emitters to be in the right
|
||||
/// states before returning.
|
||||
void emittersSelect(QTREmitters emitters);
|
||||
|
||||
/// \brief Reads the sensors for calibration.
|
||||
///
|
||||
/// \param mode The emitter behavior during calibration, as a member of the
|
||||
/// ::QTRReadMode enum. The default is QTRReadMode::On. Manual emitter
|
||||
/// control with QTRReadMode::Manual is not supported.
|
||||
///
|
||||
/// This method reads the sensors 10 times and uses the results for
|
||||
/// calibration. The sensor values are not returned; instead, the maximum
|
||||
/// and minimum values found over time are stored in #calibrationOn and/or
|
||||
/// #calibrationOff for use by the readCalibrated() method.
|
||||
///
|
||||
/// If the storage for the calibration values has not been initialized,
|
||||
/// this function will (re)allocate the arrays and initialize the maximum
|
||||
/// and minimum values to 0 and the maximum possible sensor reading,
|
||||
/// respectively, so that the very first calibration sensor reading will
|
||||
/// update both of them.
|
||||
///
|
||||
/// Note that the `minimum` and `maximum` pointers in the CalibrationData
|
||||
/// structs will point to arrays of length \p sensorCount, as specified in
|
||||
/// setSensorPins(), and they will only be allocated when calibrate() is
|
||||
/// called. If you only calibrate with the emitters on, the calibration
|
||||
/// arrays that hold the off values will not be allocated (and vice versa).
|
||||
///
|
||||
/// See \ref md_usage for more information and example code.
|
||||
void calibrate(QTRReadMode mode = QTRReadMode::On);
|
||||
|
||||
/// \brief Resets all calibration that has been done.
|
||||
void resetCalibration();
|
||||
|
||||
/// \brief Reads the raw sensor values into an array.
|
||||
///
|
||||
/// \param[out] sensorValues A pointer to an array in which to store the
|
||||
/// raw sensor readings. There **MUST** be space in the array for as many
|
||||
/// values as there were sensors specified in setSensorPins().
|
||||
///
|
||||
/// \param mode The emitter behavior during the read, as a member of the
|
||||
/// ::QTRReadMode enum. The default is QTRReadMode::On.
|
||||
///
|
||||
/// Example usage:
|
||||
/// ~~~{.cpp}
|
||||
/// uint16_t sensorValues[8];
|
||||
/// qtr.read(sensorValues);
|
||||
/// ~~~
|
||||
///
|
||||
/// The values returned are a measure of the reflectance in abstract units,
|
||||
/// with higher values corresponding to lower reflectance (e.g. a black
|
||||
/// surface or a void).
|
||||
///
|
||||
/// Analog sensors will return a raw value between 0 and 1023 (like
|
||||
/// Arduino's `analogRead()` function).
|
||||
///
|
||||
/// RC sensors will return a raw value in microseconds between 0 and the
|
||||
/// timeout setting configured with setTimeout() (the default timeout is
|
||||
/// 2500 µs).
|
||||
///
|
||||
/// See \ref md_usage for more information and example code.
|
||||
void read(uint16_t * sensorValues, QTRReadMode mode = QTRReadMode::On);
|
||||
|
||||
/// \brief Reads the sensors and provides calibrated values between 0 and
|
||||
/// 1000.
|
||||
///
|
||||
/// \param[out] sensorValues A pointer to an array in which to store the
|
||||
/// calibrated sensor readings. There **MUST** be space in the array for
|
||||
/// as many values as there were sensors specified in setSensorPins().
|
||||
///
|
||||
/// \param mode The emitter behavior during the read, as a member of the
|
||||
/// ::QTRReadMode enum. The default is QTRReadMode::On. Manual emitter
|
||||
/// control with QTRReadMode::Manual is not supported.
|
||||
///
|
||||
/// 0 corresponds to the minimum value stored in #calibrationOn or
|
||||
/// #calibrationOff, depending on \p mode, and 1000 corresponds to the
|
||||
/// maximum value. Calibration values are typically obtained by calling
|
||||
/// calibrate(), and they are stored separately for each sensor, so that
|
||||
/// differences in the sensors are accounted for automatically.
|
||||
///
|
||||
/// See \ref md_usage for more information and example code.
|
||||
void readCalibrated(uint16_t * sensorValues, QTRReadMode mode = QTRReadMode::On);
|
||||
|
||||
/// \brief Reads the sensors, provides calibrated values, and returns an
|
||||
/// estimated black line position.
|
||||
///
|
||||
/// \param[out] sensorValues A pointer to an array in which to store the
|
||||
/// calibrated sensor readings. There **MUST** be space in the array for
|
||||
/// as many values as there were sensors specified in setSensorPins().
|
||||
///
|
||||
/// \param mode The emitter behavior during the read, as a member of the
|
||||
/// ::QTRReadMode enum. The default is QTRReadMode::On. Manual emitter
|
||||
/// control with QTRReadMode::Manual is not supported.
|
||||
///
|
||||
/// \return An estimate of the position of a black line under the sensors.
|
||||
///
|
||||
/// The estimate is made using a weighted average of the sensor indices
|
||||
/// multiplied by 1000, so that a return value of 0 indicates that the line
|
||||
/// is directly below sensor 0, a return value of 1000 indicates that the
|
||||
/// line is directly below sensor 1, 2000 indicates that it's below sensor
|
||||
/// 2000, etc. Intermediate values indicate that the line is between two
|
||||
/// sensors. The formula is (where \f$v_0\f$ represents the value from the
|
||||
/// first sensor):
|
||||
///
|
||||
/// \f[
|
||||
/// {(0 \times v_0) + (1000 \times v_1) + (2000 \times v_2) + \cdots
|
||||
/// \over
|
||||
/// v_0 + v_1 + v_2 + \cdots}
|
||||
/// \f]
|
||||
///
|
||||
/// As long as your sensors aren’t spaced too far apart relative to the
|
||||
/// line, this returned value is designed to be monotonic, which makes it
|
||||
/// great for use in closed-loop PID control. Additionally, this method
|
||||
/// remembers where it last saw the line, so if you ever lose the line to
|
||||
/// the left or the right, its line position will continue to indicate the
|
||||
/// direction you need to go to reacquire the line. For example, if sensor
|
||||
/// 4 is your rightmost sensor and you end up completely off the line to
|
||||
/// the left, this function will continue to return 4000.
|
||||
///
|
||||
/// This function is intended to detect a black (or dark-colored) line on a
|
||||
/// white (or light-colored) background. For a white line, see
|
||||
/// readLineWhite().
|
||||
///
|
||||
/// See \ref md_usage for more information and example code.
|
||||
uint16_t readLineBlack(uint16_t * sensorValues, QTRReadMode mode = QTRReadMode::On)
|
||||
{
|
||||
return readLinePrivate(sensorValues, mode, false);
|
||||
}
|
||||
|
||||
/// \brief Reads the sensors, provides calibrated values, and returns an
|
||||
/// estimated white line position.
|
||||
///
|
||||
/// \param[out] sensorValues A pointer to an array in which to store the
|
||||
/// calibrated sensor readings. There **MUST** be space in the array for
|
||||
/// as many values as there were sensors specified in setSensorPins().
|
||||
///
|
||||
/// \param mode The emitter behavior during the read, as a member of the
|
||||
/// ::QTRReadMode enum. The default is QTRReadMode::On. Manual emitter
|
||||
/// control with QTRReadMode::Manual is not supported.
|
||||
///
|
||||
/// \return An estimate of the position of a white line under the sensors.
|
||||
///
|
||||
/// This function is intended to detect a white (or light-colored) line on
|
||||
/// a black (or dark-colored) background. For a black line, see
|
||||
/// readLineBlack().
|
||||
///
|
||||
/// See \ref md_usage for more information and example code.
|
||||
uint16_t readLineWhite(uint16_t * sensorValues, QTRReadMode mode = QTRReadMode::On)
|
||||
{
|
||||
return readLinePrivate(sensorValues, mode, true);
|
||||
}
|
||||
|
||||
|
||||
/// \brief Stores sensor calibration data.
|
||||
///
|
||||
/// See calibrate() and readCalibrated() for details.
|
||||
struct CalibrationData
|
||||
{
|
||||
/// Whether array pointers have been allocated and initialized.
|
||||
bool initialized = false;
|
||||
/// Lowest readings seen during calibration.
|
||||
uint16_t * minimum = nullptr;
|
||||
/// Highest readings seen during calibration.
|
||||
uint16_t * maximum = nullptr;
|
||||
};
|
||||
|
||||
/// \name Calibration data
|
||||
///
|
||||
/// See calibrate() and readCalibrated() for details.
|
||||
///
|
||||
/// These variables are made public so that you can use them for your own
|
||||
/// calculations and do things like saving the values to EEPROM, performing
|
||||
/// sanity checking, etc.
|
||||
/// \{
|
||||
|
||||
/// Data from calibrating with emitters on.
|
||||
CalibrationData calibrationOn;
|
||||
|
||||
/// Data from calibrating with emitters off.
|
||||
CalibrationData calibrationOff;
|
||||
|
||||
/// \}
|
||||
|
||||
private:
|
||||
|
||||
uint16_t emittersOnWithPin(uint8_t pin);
|
||||
|
||||
// Handles the actual calibration, including (re)allocating and
|
||||
// initializing the storage for the calibration values if necessary.
|
||||
void calibrateOnOrOff(CalibrationData & calibration, QTRReadMode mode);
|
||||
|
||||
void readPrivate(uint16_t * sensorValues, uint8_t start = 0, uint8_t step = 1);
|
||||
|
||||
uint16_t readLinePrivate(uint16_t * sensorValues, QTRReadMode mode, bool invertReadings);
|
||||
|
||||
QTRType _type = QTRType::Undefined;
|
||||
|
||||
uint8_t * _sensorPins = nullptr;
|
||||
uint8_t _sensorCount = 0;
|
||||
|
||||
uint16_t _timeout = QTRRCDefaultTimeout; // only used for RC sensors
|
||||
uint16_t _maxValue = QTRRCDefaultTimeout; // the maximum value returned by readPrivate()
|
||||
uint8_t _samplesPerSensor = 4; // only used for analog sensors
|
||||
|
||||
uint8_t _oddEmitterPin = QTRNoEmitterPin; // also used for single emitter pin
|
||||
uint8_t _evenEmitterPin = QTRNoEmitterPin;
|
||||
uint8_t _emitterPinCount = 0;
|
||||
|
||||
bool _dimmable = true;
|
||||
uint8_t _dimmingLevel = 0;
|
||||
|
||||
uint16_t _lastPosition = 0;
|
||||
};
|
||||
218
arduino-libs/arduino-cli/libraries/yfrobot/RtcDS1307.h
Normal file
218
arduino-libs/arduino-cli/libraries/yfrobot/RtcDS1307.h
Normal file
@@ -0,0 +1,218 @@
|
||||
|
||||
|
||||
#ifndef __RTCDS1307_H__
|
||||
#define __RTCDS1307_H__
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "RtcDateTime.h"
|
||||
#include "RtcUtility.h"
|
||||
|
||||
//I2C Slave Address
|
||||
const uint8_t DS1307_ADDRESS = 0x68;
|
||||
|
||||
//DS1307 Register Addresses
|
||||
const uint8_t DS1307_REG_TIMEDATE = 0x00;
|
||||
const uint8_t DS1307_REG_STATUS = 0x00;
|
||||
const uint8_t DS1307_REG_CONTROL = 0x07;
|
||||
const uint8_t DS1307_REG_RAMSTART = 0x08;
|
||||
const uint8_t DS1307_REG_RAMEND = 0x3f;
|
||||
const uint8_t DS1307_REG_RAMSIZE = DS1307_REG_RAMEND - DS1307_REG_RAMSTART;
|
||||
|
||||
//DS1307 Register Data Size if not just 1
|
||||
const uint8_t DS1307_REG_TIMEDATE_SIZE = 7;
|
||||
|
||||
// DS1307 Control Register Bits
|
||||
const uint8_t DS1307_RS0 = 0;
|
||||
const uint8_t DS1307_RS1 = 1;
|
||||
const uint8_t DS1307_SQWE = 4;
|
||||
const uint8_t DS1307_OUT = 7;
|
||||
|
||||
// DS1307 Status Register Bits
|
||||
const uint8_t DS1307_CH = 7;
|
||||
|
||||
enum DS1307SquareWaveOut
|
||||
{
|
||||
DS1307SquareWaveOut_1Hz = 0b00010000,
|
||||
DS1307SquareWaveOut_4kHz = 0b00010001,
|
||||
DS1307SquareWaveOut_8kHz = 0b00010010,
|
||||
DS1307SquareWaveOut_32kHz = 0b00010011,
|
||||
DS1307SquareWaveOut_High = 0b10000000,
|
||||
DS1307SquareWaveOut_Low = 0b00000000,
|
||||
};
|
||||
|
||||
template<class T_WIRE_METHOD> class RtcDS1307
|
||||
{
|
||||
public:
|
||||
RtcDS1307(T_WIRE_METHOD& wire) :
|
||||
_wire(wire)
|
||||
{
|
||||
}
|
||||
|
||||
void Begin()
|
||||
{
|
||||
_wire.begin();
|
||||
}
|
||||
|
||||
bool IsDateTimeValid()
|
||||
{
|
||||
return GetIsRunning();
|
||||
}
|
||||
|
||||
bool GetIsRunning()
|
||||
{
|
||||
uint8_t sreg = getReg(DS1307_REG_STATUS);
|
||||
return !(sreg & _BV(DS1307_CH));
|
||||
}
|
||||
void SetIsRunning(bool isRunning)
|
||||
{
|
||||
uint8_t sreg = getReg(DS1307_REG_STATUS);
|
||||
if (isRunning)
|
||||
{
|
||||
sreg &= ~_BV(DS1307_CH);
|
||||
}
|
||||
else
|
||||
{
|
||||
sreg |= _BV(DS1307_CH);
|
||||
}
|
||||
setReg(DS1307_REG_STATUS, sreg);
|
||||
}
|
||||
|
||||
void SetDateTime(const RtcDateTime& dt)
|
||||
{
|
||||
// retain running state
|
||||
uint8_t sreg = getReg(DS1307_REG_STATUS) & _BV(DS1307_CH);
|
||||
|
||||
// set the date time
|
||||
_wire.beginTransmission(DS1307_ADDRESS);
|
||||
_wire.write(DS1307_REG_TIMEDATE);
|
||||
|
||||
_wire.write(Uint8ToBcd(dt.Second()) | sreg);
|
||||
_wire.write(Uint8ToBcd(dt.Minute()));
|
||||
_wire.write(Uint8ToBcd(dt.Hour())); // 24 hour mode only
|
||||
|
||||
_wire.write(Uint8ToBcd(dt.DayOfWeek()));
|
||||
_wire.write(Uint8ToBcd(dt.Day()));
|
||||
_wire.write(Uint8ToBcd(dt.Month()));
|
||||
_wire.write(Uint8ToBcd(dt.Year() - 2000));
|
||||
|
||||
_wire.endTransmission();
|
||||
}
|
||||
RtcDateTime GetDateTime()
|
||||
{
|
||||
_wire.beginTransmission(DS1307_ADDRESS);
|
||||
_wire.write(DS1307_REG_TIMEDATE);
|
||||
_wire.endTransmission();
|
||||
|
||||
_wire.requestFrom(DS1307_ADDRESS, DS1307_REG_TIMEDATE_SIZE);
|
||||
uint8_t second = BcdToUint8(_wire.read() & 0x7F);
|
||||
uint8_t minute = BcdToUint8(_wire.read());
|
||||
uint8_t hour = BcdToBin24Hour(_wire.read());
|
||||
|
||||
_wire.read(); // throwing away day of week as we calculate it
|
||||
|
||||
uint8_t dayOfMonth = BcdToUint8(_wire.read());
|
||||
uint8_t month = BcdToUint8(_wire.read());
|
||||
uint16_t year = BcdToUint8(_wire.read()) + 2000;
|
||||
|
||||
return RtcDateTime(year, month, dayOfMonth, hour, minute, second);
|
||||
}
|
||||
|
||||
void SetMemory(uint8_t memoryAddress, uint8_t value)
|
||||
{
|
||||
uint8_t address = memoryAddress + DS1307_REG_RAMSTART;
|
||||
if (address <= DS1307_REG_RAMEND)
|
||||
{
|
||||
setReg(address, value);
|
||||
}
|
||||
}
|
||||
uint8_t GetMemory(uint8_t memoryAddress)
|
||||
{
|
||||
uint8_t value = 0;
|
||||
uint8_t address = memoryAddress + DS1307_REG_RAMSTART;
|
||||
if (address <= DS1307_REG_RAMEND)
|
||||
{
|
||||
value = getReg(address);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
uint8_t SetMemory(uint8_t memoryAddress, const uint8_t* pValue, uint8_t countBytes)
|
||||
{
|
||||
uint8_t address = memoryAddress + DS1307_REG_RAMSTART;
|
||||
uint8_t countWritten = 0;
|
||||
if (address <= DS1307_REG_RAMEND)
|
||||
{
|
||||
_wire.beginTransmission(DS1307_ADDRESS);
|
||||
_wire.write(address);
|
||||
|
||||
while (countBytes > 0 && address <= DS1307_REG_RAMEND)
|
||||
{
|
||||
_wire.write(*pValue++);
|
||||
address++;
|
||||
countBytes--;
|
||||
countWritten++;
|
||||
}
|
||||
|
||||
_wire.endTransmission();
|
||||
}
|
||||
return countWritten;
|
||||
}
|
||||
|
||||
uint8_t GetMemory(uint8_t memoryAddress, uint8_t* pValue, uint8_t countBytes)
|
||||
{
|
||||
uint8_t address = memoryAddress + DS1307_REG_RAMSTART;
|
||||
uint8_t countRead = 0;
|
||||
if (address <= DS1307_REG_RAMEND)
|
||||
{
|
||||
if (countBytes > DS1307_REG_RAMSIZE)
|
||||
{
|
||||
countBytes = DS1307_REG_RAMSIZE;
|
||||
}
|
||||
|
||||
_wire.beginTransmission(DS1307_ADDRESS);
|
||||
_wire.write(address);
|
||||
_wire.endTransmission();
|
||||
|
||||
_wire.requestFrom(DS1307_ADDRESS, countBytes);
|
||||
|
||||
while (countBytes-- > 0)
|
||||
{
|
||||
*pValue++ = _wire.read();
|
||||
countRead++;
|
||||
}
|
||||
}
|
||||
|
||||
return countRead;
|
||||
}
|
||||
|
||||
void SetSquareWavePin(DS1307SquareWaveOut pinMode)
|
||||
{
|
||||
setReg(DS1307_REG_CONTROL, pinMode);
|
||||
}
|
||||
|
||||
private:
|
||||
T_WIRE_METHOD& _wire;
|
||||
|
||||
uint8_t getReg(uint8_t regAddress)
|
||||
{
|
||||
_wire.beginTransmission(DS1307_ADDRESS);
|
||||
_wire.write(regAddress);
|
||||
_wire.endTransmission();
|
||||
|
||||
// control register
|
||||
_wire.requestFrom(DS1307_ADDRESS, (uint8_t)1);
|
||||
|
||||
uint8_t regValue = _wire.read();
|
||||
return regValue;
|
||||
}
|
||||
|
||||
void setReg(uint8_t regAddress, uint8_t regValue)
|
||||
{
|
||||
_wire.beginTransmission(DS1307_ADDRESS);
|
||||
_wire.write(regAddress);
|
||||
_wire.write(regValue);
|
||||
_wire.endTransmission();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __RTCDS1307_H__
|
||||
528
arduino-libs/arduino-cli/libraries/yfrobot/RtcDS3231.h
Normal file
528
arduino-libs/arduino-cli/libraries/yfrobot/RtcDS3231.h
Normal file
@@ -0,0 +1,528 @@
|
||||
|
||||
|
||||
#ifndef __RTCDS3231_H__
|
||||
#define __RTCDS3231_H__
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "RtcDateTime.h"
|
||||
#include "RtcTemperature.h"
|
||||
#include "RtcUtility.h"
|
||||
|
||||
|
||||
//I2C Slave Address
|
||||
const uint8_t DS3231_ADDRESS = 0x68;
|
||||
|
||||
//DS3231 Register Addresses
|
||||
const uint8_t DS3231_REG_TIMEDATE = 0x00;
|
||||
const uint8_t DS3231_REG_ALARMONE = 0x07;
|
||||
const uint8_t DS3231_REG_ALARMTWO = 0x0B;
|
||||
|
||||
const uint8_t DS3231_REG_CONTROL = 0x0E;
|
||||
const uint8_t DS3231_REG_STATUS = 0x0F;
|
||||
const uint8_t DS3231_REG_AGING = 0x10;
|
||||
|
||||
const uint8_t DS3231_REG_TEMP = 0x11;
|
||||
|
||||
//DS3231 Register Data Size if not just 1
|
||||
const uint8_t DS3231_REG_TIMEDATE_SIZE = 7;
|
||||
const uint8_t DS3231_REG_ALARMONE_SIZE = 4;
|
||||
const uint8_t DS3231_REG_ALARMTWO_SIZE = 3;
|
||||
|
||||
const uint8_t DS3231_REG_TEMP_SIZE = 2;
|
||||
|
||||
// DS3231 Control Register Bits
|
||||
const uint8_t DS3231_A1IE = 0;
|
||||
const uint8_t DS3231_A2IE = 1;
|
||||
const uint8_t DS3231_INTCN = 2;
|
||||
const uint8_t DS3231_RS1 = 3;
|
||||
const uint8_t DS3231_RS2 = 4;
|
||||
const uint8_t DS3231_CONV = 5;
|
||||
const uint8_t DS3231_BBSQW = 6;
|
||||
const uint8_t DS3231_EOSC = 7;
|
||||
const uint8_t DS3231_AIEMASK = (_BV(DS3231_A1IE) | _BV(DS3231_A2IE));
|
||||
const uint8_t DS3231_RSMASK = (_BV(DS3231_RS1) | _BV(DS3231_RS2));
|
||||
|
||||
// DS3231 Status Register Bits
|
||||
const uint8_t DS3231_A1F = 0;
|
||||
const uint8_t DS3231_A2F = 1;
|
||||
const uint8_t DS3231_BSY = 2;
|
||||
const uint8_t DS3231_EN32KHZ = 3;
|
||||
const uint8_t DS3231_OSF = 7;
|
||||
const uint8_t DS3231_AIFMASK = (_BV(DS3231_A1F) | _BV(DS3231_A2F));
|
||||
|
||||
|
||||
// seconds accuracy
|
||||
enum DS3231AlarmOneControl
|
||||
{
|
||||
// bit order: A1M4 DY/DT A1M3 A1M2 A1M1
|
||||
DS3231AlarmOneControl_HoursMinutesSecondsDayOfMonthMatch = 0x00,
|
||||
DS3231AlarmOneControl_OncePerSecond = 0x17,
|
||||
DS3231AlarmOneControl_SecondsMatch = 0x16,
|
||||
DS3231AlarmOneControl_MinutesSecondsMatch = 0x14,
|
||||
DS3231AlarmOneControl_HoursMinutesSecondsMatch = 0x10,
|
||||
DS3231AlarmOneControl_HoursMinutesSecondsDayOfWeekMatch = 0x08,
|
||||
};
|
||||
|
||||
class DS3231AlarmOne
|
||||
{
|
||||
public:
|
||||
DS3231AlarmOne( uint8_t dayOf,
|
||||
uint8_t hour,
|
||||
uint8_t minute,
|
||||
uint8_t second,
|
||||
DS3231AlarmOneControl controlFlags) :
|
||||
_flags(controlFlags),
|
||||
_dayOf(dayOf),
|
||||
_hour(hour),
|
||||
_minute(minute),
|
||||
_second(second)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t DayOf() const
|
||||
{
|
||||
return _dayOf;
|
||||
}
|
||||
|
||||
uint8_t Hour() const
|
||||
{
|
||||
return _hour;
|
||||
}
|
||||
|
||||
uint8_t Minute() const
|
||||
{
|
||||
return _minute;
|
||||
}
|
||||
|
||||
uint8_t Second() const
|
||||
{
|
||||
return _second;
|
||||
}
|
||||
|
||||
DS3231AlarmOneControl ControlFlags() const
|
||||
{
|
||||
return _flags;
|
||||
}
|
||||
|
||||
bool operator == (const DS3231AlarmOne& other) const
|
||||
{
|
||||
return (_dayOf == other._dayOf &&
|
||||
_hour == other._hour &&
|
||||
_minute == other._minute &&
|
||||
_second == other._second &&
|
||||
_flags == other._flags);
|
||||
}
|
||||
|
||||
bool operator != (const DS3231AlarmOne& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
protected:
|
||||
DS3231AlarmOneControl _flags;
|
||||
|
||||
uint8_t _dayOf;
|
||||
uint8_t _hour;
|
||||
uint8_t _minute;
|
||||
uint8_t _second;
|
||||
};
|
||||
|
||||
// minutes accuracy
|
||||
enum DS3231AlarmTwoControl
|
||||
{
|
||||
// bit order: A2M4 DY/DT A2M3 A2M2
|
||||
DS3231AlarmTwoControl_HoursMinutesDayOfMonthMatch = 0x00,
|
||||
DS3231AlarmTwoControl_OncePerMinute = 0x0b,
|
||||
DS3231AlarmTwoControl_MinutesMatch = 0x0a,
|
||||
DS3231AlarmTwoControl_HoursMinutesMatch = 0x08,
|
||||
DS3231AlarmTwoControl_HoursMinutesDayOfWeekMatch = 0x04,
|
||||
};
|
||||
|
||||
class DS3231AlarmTwo
|
||||
{
|
||||
public:
|
||||
DS3231AlarmTwo( uint8_t dayOf,
|
||||
uint8_t hour,
|
||||
uint8_t minute,
|
||||
DS3231AlarmTwoControl controlFlags) :
|
||||
_flags(controlFlags),
|
||||
_dayOf(dayOf),
|
||||
_hour(hour),
|
||||
_minute(minute)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t DayOf() const
|
||||
{
|
||||
return _dayOf;
|
||||
}
|
||||
|
||||
uint8_t Hour() const
|
||||
{
|
||||
return _hour;
|
||||
}
|
||||
|
||||
uint8_t Minute() const
|
||||
{
|
||||
return _minute;
|
||||
}
|
||||
|
||||
DS3231AlarmTwoControl ControlFlags() const
|
||||
{
|
||||
return _flags;
|
||||
}
|
||||
|
||||
bool operator == (const DS3231AlarmTwo& other) const
|
||||
{
|
||||
return (_dayOf == other._dayOf &&
|
||||
_hour == other._hour &&
|
||||
_minute == other._minute &&
|
||||
_flags == other._flags);
|
||||
}
|
||||
|
||||
bool operator != (const DS3231AlarmTwo& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
protected:
|
||||
DS3231AlarmTwoControl _flags;
|
||||
|
||||
uint8_t _dayOf;
|
||||
uint8_t _hour;
|
||||
uint8_t _minute;
|
||||
};
|
||||
|
||||
|
||||
enum DS3231SquareWaveClock
|
||||
{
|
||||
DS3231SquareWaveClock_1Hz = 0b00000000,
|
||||
DS3231SquareWaveClock_1kHz = 0b00001000,
|
||||
DS3231SquareWaveClock_4kHz = 0b00010000,
|
||||
DS3231SquareWaveClock_8kHz = 0b00011000,
|
||||
};
|
||||
|
||||
enum DS3231SquareWavePinMode
|
||||
{
|
||||
DS3231SquareWavePin_ModeNone,
|
||||
DS3231SquareWavePin_ModeBatteryBackup,
|
||||
DS3231SquareWavePin_ModeClock,
|
||||
DS3231SquareWavePin_ModeAlarmOne,
|
||||
DS3231SquareWavePin_ModeAlarmTwo,
|
||||
DS3231SquareWavePin_ModeAlarmBoth
|
||||
};
|
||||
|
||||
enum DS3231AlarmFlag
|
||||
{
|
||||
DS3231AlarmFlag_Alarm1 = 0x01,
|
||||
DS3231AlarmFlag_Alarm2 = 0x02,
|
||||
DS3231AlarmFlag_AlarmBoth = 0x03,
|
||||
};
|
||||
|
||||
template<class T_WIRE_METHOD> class RtcDS3231
|
||||
{
|
||||
public:
|
||||
RtcDS3231(T_WIRE_METHOD& wire) :
|
||||
_wire(wire)
|
||||
{
|
||||
}
|
||||
|
||||
void Begin()
|
||||
{
|
||||
_wire.begin();
|
||||
}
|
||||
|
||||
bool IsDateTimeValid()
|
||||
{
|
||||
uint8_t status = getReg(DS3231_REG_STATUS);
|
||||
return !(status & _BV(DS3231_OSF));
|
||||
}
|
||||
|
||||
bool GetIsRunning()
|
||||
{
|
||||
uint8_t creg = getReg(DS3231_REG_CONTROL);
|
||||
return !(creg & _BV(DS3231_EOSC));
|
||||
}
|
||||
void SetIsRunning(bool isRunning)
|
||||
{
|
||||
uint8_t creg = getReg(DS3231_REG_CONTROL);
|
||||
if (isRunning)
|
||||
{
|
||||
creg &= ~_BV(DS3231_EOSC);
|
||||
}
|
||||
else
|
||||
{
|
||||
creg |= _BV(DS3231_EOSC);
|
||||
}
|
||||
setReg(DS3231_REG_CONTROL, creg);
|
||||
}
|
||||
|
||||
void SetDateTime(const RtcDateTime& dt)
|
||||
{
|
||||
// clear the invalid flag
|
||||
uint8_t status = getReg(DS3231_REG_STATUS);
|
||||
status &= ~_BV(DS3231_OSF); // clear the flag
|
||||
setReg(DS3231_REG_STATUS, status);
|
||||
|
||||
// set the date time
|
||||
_wire.beginTransmission(DS3231_ADDRESS);
|
||||
_wire.write(DS3231_REG_TIMEDATE);
|
||||
|
||||
_wire.write(Uint8ToBcd(dt.Second()));
|
||||
_wire.write(Uint8ToBcd(dt.Minute()));
|
||||
_wire.write(Uint8ToBcd(dt.Hour())); // 24 hour mode only
|
||||
|
||||
uint8_t year = dt.Year() - 2000;
|
||||
uint8_t centuryFlag = 0;
|
||||
|
||||
if (year >= 100)
|
||||
{
|
||||
year -= 100;
|
||||
centuryFlag = _BV(7);
|
||||
}
|
||||
|
||||
_wire.write(Uint8ToBcd(dt.DayOfWeek()));
|
||||
_wire.write(Uint8ToBcd(dt.Day()));
|
||||
_wire.write(Uint8ToBcd(dt.Month()) | centuryFlag);
|
||||
_wire.write(Uint8ToBcd(year));
|
||||
|
||||
_wire.endTransmission();
|
||||
}
|
||||
RtcDateTime GetDateTime()
|
||||
{
|
||||
_wire.beginTransmission(DS3231_ADDRESS);
|
||||
_wire.write(DS3231_REG_TIMEDATE);
|
||||
_wire.endTransmission();
|
||||
|
||||
_wire.requestFrom(DS3231_ADDRESS, DS3231_REG_TIMEDATE_SIZE);
|
||||
uint8_t second = BcdToUint8(_wire.read() & 0x7F);
|
||||
uint8_t minute = BcdToUint8(_wire.read());
|
||||
uint8_t hour = BcdToBin24Hour(_wire.read());
|
||||
|
||||
_wire.read(); // throwing away day of week as we calculate it
|
||||
|
||||
uint8_t dayOfMonth = BcdToUint8(_wire.read());
|
||||
uint8_t monthRaw = _wire.read();
|
||||
uint16_t year = BcdToUint8(_wire.read()) + 2000;
|
||||
|
||||
if (monthRaw & _BV(7)) // century wrap flag
|
||||
{
|
||||
year += 100;
|
||||
}
|
||||
uint8_t month = BcdToUint8(monthRaw & 0x7f);
|
||||
|
||||
|
||||
return RtcDateTime(year, month, dayOfMonth, hour, minute, second);
|
||||
}
|
||||
|
||||
RtcTemperature GetTemperature()
|
||||
{
|
||||
_wire.beginTransmission(DS3231_ADDRESS);
|
||||
_wire.write(DS3231_REG_TEMP);
|
||||
_wire.endTransmission();
|
||||
|
||||
_wire.requestFrom(DS3231_ADDRESS, DS3231_REG_TEMP_SIZE);
|
||||
int8_t degrees = _wire.read();
|
||||
// fraction is just the upper bits
|
||||
// representing 1/4 of a degree
|
||||
uint8_t fract = (_wire.read() >> 6) * 25;
|
||||
|
||||
return RtcTemperature(degrees, fract);
|
||||
}
|
||||
|
||||
void Enable32kHzPin(bool enable)
|
||||
{
|
||||
uint8_t sreg = getReg(DS3231_REG_STATUS);
|
||||
|
||||
if (enable == true)
|
||||
{
|
||||
sreg |= _BV(DS3231_EN32KHZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
sreg &= ~_BV(DS3231_EN32KHZ);
|
||||
}
|
||||
|
||||
setReg(DS3231_REG_STATUS, sreg);
|
||||
}
|
||||
void SetSquareWavePin(DS3231SquareWavePinMode pinMode)
|
||||
{
|
||||
uint8_t creg = getReg(DS3231_REG_CONTROL);
|
||||
|
||||
// clear all relevant bits to a known "off" state
|
||||
creg &= ~(DS3231_AIEMASK | _BV(DS3231_BBSQW));
|
||||
creg |= _BV(DS3231_INTCN); // set INTCN to disables SQW
|
||||
|
||||
switch (pinMode)
|
||||
{
|
||||
case DS3231SquareWavePin_ModeNone:
|
||||
break;
|
||||
|
||||
case DS3231SquareWavePin_ModeBatteryBackup:
|
||||
creg |= _BV(DS3231_BBSQW); // set battery backup flag
|
||||
creg &= ~_BV(DS3231_INTCN); // clear INTCN to enable SQW
|
||||
break;
|
||||
|
||||
case DS3231SquareWavePin_ModeClock:
|
||||
creg &= ~_BV(DS3231_INTCN); // clear INTCN to enable SQW
|
||||
break;
|
||||
|
||||
case DS3231SquareWavePin_ModeAlarmOne:
|
||||
creg |= _BV(DS3231_A1IE);
|
||||
break;
|
||||
|
||||
case DS3231SquareWavePin_ModeAlarmTwo:
|
||||
creg |= _BV(DS3231_A2IE);
|
||||
break;
|
||||
|
||||
case DS3231SquareWavePin_ModeAlarmBoth:
|
||||
creg |= _BV(DS3231_A1IE) | _BV(DS3231_A2IE);
|
||||
break;
|
||||
}
|
||||
|
||||
setReg(DS3231_REG_CONTROL, creg);
|
||||
}
|
||||
|
||||
void SetSquareWavePinClockFrequency(DS3231SquareWaveClock freq)
|
||||
{
|
||||
uint8_t creg = getReg(DS3231_REG_CONTROL);
|
||||
|
||||
creg &= ~DS3231_RSMASK; // Set to 0
|
||||
creg |= (freq & DS3231_RSMASK); // Set freq bits
|
||||
|
||||
setReg(DS3231_REG_CONTROL, creg);
|
||||
}
|
||||
|
||||
|
||||
void SetAlarmOne(const DS3231AlarmOne& alarm)
|
||||
{
|
||||
_wire.beginTransmission(DS3231_ADDRESS);
|
||||
_wire.write(DS3231_REG_ALARMONE);
|
||||
|
||||
_wire.write(Uint8ToBcd(alarm.Second()) | ((alarm.ControlFlags() & 0x01) << 7));
|
||||
_wire.write(Uint8ToBcd(alarm.Minute()) | ((alarm.ControlFlags() & 0x02) << 6));
|
||||
_wire.write(Uint8ToBcd(alarm.Hour()) | ((alarm.ControlFlags() & 0x04) << 5)); // 24 hour mode only
|
||||
|
||||
_wire.write(Uint8ToBcd(alarm.DayOf()) | ((alarm.ControlFlags() & 0x18) << 3));
|
||||
|
||||
_wire.endTransmission();
|
||||
}
|
||||
void SetAlarmTwo(const DS3231AlarmTwo& alarm)
|
||||
{
|
||||
_wire.beginTransmission(DS3231_ADDRESS);
|
||||
_wire.write(DS3231_REG_ALARMTWO);
|
||||
|
||||
_wire.write(Uint8ToBcd(alarm.Minute()) | ((alarm.ControlFlags() & 0x01) << 7));
|
||||
_wire.write(Uint8ToBcd(alarm.Hour()) | ((alarm.ControlFlags() & 0x02) << 6)); // 24 hour mode only
|
||||
|
||||
_wire.write(Uint8ToBcd(alarm.DayOf()) | ((alarm.ControlFlags() & 0x0c) << 4));
|
||||
|
||||
_wire.endTransmission();
|
||||
}
|
||||
DS3231AlarmOne GetAlarmOne()
|
||||
{
|
||||
_wire.beginTransmission(DS3231_ADDRESS);
|
||||
_wire.write(DS3231_REG_ALARMONE);
|
||||
_wire.endTransmission();
|
||||
|
||||
_wire.requestFrom(DS3231_ADDRESS, DS3231_REG_ALARMONE_SIZE);
|
||||
|
||||
uint8_t raw = _wire.read();
|
||||
uint8_t flags = (raw & 0x80) >> 7;
|
||||
uint8_t second = BcdToUint8(raw & 0x7F);
|
||||
|
||||
raw = _wire.read();
|
||||
flags |= (raw & 0x80) >> 6;
|
||||
uint8_t minute = BcdToUint8(raw & 0x7F);
|
||||
|
||||
raw = _wire.read();
|
||||
flags |= (raw & 0x80) >> 5;
|
||||
uint8_t hour = BcdToBin24Hour(raw & 0x7f);
|
||||
|
||||
raw = _wire.read();
|
||||
flags |= (raw & 0xc0) >> 3;
|
||||
uint8_t dayOf = BcdToUint8(raw & 0x3f);
|
||||
|
||||
return DS3231AlarmOne(dayOf, hour, minute, second, (DS3231AlarmOneControl)flags);
|
||||
}
|
||||
DS3231AlarmTwo GetAlarmTwo()
|
||||
{
|
||||
_wire.beginTransmission(DS3231_ADDRESS);
|
||||
_wire.write(DS3231_REG_ALARMTWO);
|
||||
_wire.endTransmission();
|
||||
|
||||
_wire.requestFrom(DS3231_ADDRESS, DS3231_REG_ALARMTWO_SIZE);
|
||||
|
||||
uint8_t raw = _wire.read();
|
||||
uint8_t flags = (raw & 0x80) >> 7;
|
||||
uint8_t minute = BcdToUint8(raw & 0x7F);
|
||||
|
||||
raw = _wire.read();
|
||||
flags |= (raw & 0x80) >> 6;
|
||||
uint8_t hour = BcdToBin24Hour(raw & 0x7f);
|
||||
|
||||
raw = _wire.read();
|
||||
flags |= (raw & 0xc0) >> 4;
|
||||
uint8_t dayOf = BcdToUint8(raw & 0x3f);
|
||||
|
||||
return DS3231AlarmTwo(dayOf, hour, minute, (DS3231AlarmTwoControl)flags);
|
||||
}
|
||||
// Latch must be called after an alarm otherwise it will not
|
||||
// trigger again
|
||||
DS3231AlarmFlag LatchAlarmsTriggeredFlags()
|
||||
{
|
||||
uint8_t sreg = getReg(DS3231_REG_STATUS);
|
||||
uint8_t alarmFlags = (sreg & DS3231_AIFMASK);
|
||||
sreg &= ~DS3231_AIFMASK; // clear the flags
|
||||
setReg(DS3231_REG_STATUS, sreg);
|
||||
return (DS3231AlarmFlag)alarmFlags;
|
||||
}
|
||||
|
||||
void ForceTemperatureCompensationUpdate(bool block)
|
||||
{
|
||||
uint8_t creg = getReg(DS3231_REG_CONTROL);
|
||||
creg |= _BV(DS3231_CONV); // Write CONV bit
|
||||
setReg(DS3231_REG_CONTROL, creg);
|
||||
|
||||
while (block && (creg & _BV(DS3231_CONV)) != 0)
|
||||
{
|
||||
// Block until CONV is 0
|
||||
creg = getReg(DS3231_REG_CONTROL);
|
||||
}
|
||||
}
|
||||
|
||||
int8_t GetAgingOffset()
|
||||
{
|
||||
return getReg(DS3231_REG_AGING);
|
||||
}
|
||||
void SetAgingOffset(int8_t value)
|
||||
{
|
||||
setReg(DS3231_REG_AGING, value);
|
||||
}
|
||||
|
||||
private:
|
||||
T_WIRE_METHOD& _wire;
|
||||
|
||||
uint8_t getReg(uint8_t regAddress)
|
||||
{
|
||||
_wire.beginTransmission(DS3231_ADDRESS);
|
||||
_wire.write(regAddress);
|
||||
_wire.endTransmission();
|
||||
|
||||
// control register
|
||||
_wire.requestFrom(DS3231_ADDRESS, (uint8_t)1);
|
||||
|
||||
uint8_t regValue = _wire.read();
|
||||
return regValue;
|
||||
}
|
||||
void setReg(uint8_t regAddress, uint8_t regValue)
|
||||
{
|
||||
_wire.beginTransmission(DS3231_ADDRESS);
|
||||
_wire.write(regAddress);
|
||||
_wire.write(regValue);
|
||||
_wire.endTransmission();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __RTCDS3231_H__
|
||||
111
arduino-libs/arduino-cli/libraries/yfrobot/RtcDateTime.cpp
Normal file
111
arduino-libs/arduino-cli/libraries/yfrobot/RtcDateTime.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "RtcDateTime.h"
|
||||
|
||||
const uint8_t c_daysInMonth[] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 };
|
||||
|
||||
RtcDateTime::RtcDateTime(uint32_t secondsFrom2000)
|
||||
{
|
||||
_initWithSecondsFrom2000<uint32_t>(secondsFrom2000);
|
||||
}
|
||||
|
||||
|
||||
uint8_t StringToUint8(const char* pString)
|
||||
{
|
||||
uint8_t value = 0;
|
||||
|
||||
// skip leading 0 and spaces
|
||||
while ('0' == *pString || *pString == ' ')
|
||||
{
|
||||
pString++;
|
||||
}
|
||||
|
||||
// calculate number until we hit non-numeral char
|
||||
while ('0' <= *pString && *pString <= '9')
|
||||
{
|
||||
value *= 10;
|
||||
value += *pString - '0';
|
||||
pString++;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
RtcDateTime::RtcDateTime(const char* date, const char* time)
|
||||
{
|
||||
// sample input: date = "Dec 26 2009", time = "12:34:56"
|
||||
_yearFrom2000 = StringToUint8(date + 9);
|
||||
// Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
|
||||
switch (date[0])
|
||||
{
|
||||
case 'J':
|
||||
if ( date[1] == 'a' )
|
||||
_month = 1;
|
||||
else if ( date[2] == 'n' )
|
||||
_month = 6;
|
||||
else
|
||||
_month = 7;
|
||||
break;
|
||||
case 'F':
|
||||
_month = 2;
|
||||
break;
|
||||
case 'A':
|
||||
_month = date[1] == 'p' ? 4 : 8;
|
||||
break;
|
||||
case 'M':
|
||||
_month = date[2] == 'r' ? 3 : 5;
|
||||
break;
|
||||
case 'S':
|
||||
_month = 9;
|
||||
break;
|
||||
case 'O':
|
||||
_month = 10;
|
||||
break;
|
||||
case 'N':
|
||||
_month = 11;
|
||||
break;
|
||||
case 'D':
|
||||
_month = 12;
|
||||
break;
|
||||
}
|
||||
_dayOfMonth = StringToUint8(date + 4);
|
||||
_hour = StringToUint8(time);
|
||||
_minute = StringToUint8(time + 3);
|
||||
_second = StringToUint8(time + 6);
|
||||
}
|
||||
|
||||
template <typename T> T DaysSinceFirstOfYear2000(uint16_t year, uint8_t month, uint8_t dayOfMonth)
|
||||
{
|
||||
T days = dayOfMonth;
|
||||
for (uint8_t indexMonth = 1; indexMonth < month; ++indexMonth)
|
||||
{
|
||||
days += pgm_read_byte(c_daysInMonth + indexMonth - 1);
|
||||
}
|
||||
if (month > 2 && year % 4 == 0)
|
||||
{
|
||||
days++;
|
||||
}
|
||||
return days + 365 * year + (year + 3) / 4 - 1;
|
||||
}
|
||||
|
||||
template <typename T> T SecondsIn(T days, uint8_t hours, uint8_t minutes, uint8_t seconds)
|
||||
{
|
||||
return ((days * 24L + hours) * 60 + minutes) * 60 + seconds;
|
||||
}
|
||||
|
||||
uint8_t RtcDateTime::DayOfWeek() const
|
||||
{
|
||||
uint16_t days = DaysSinceFirstOfYear2000<uint16_t>(_yearFrom2000, _month, _dayOfMonth);
|
||||
return (days + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6
|
||||
}
|
||||
|
||||
uint32_t RtcDateTime::TotalSeconds() const
|
||||
{
|
||||
uint16_t days = DaysSinceFirstOfYear2000<uint16_t>(_yearFrom2000, _month, _dayOfMonth);
|
||||
return SecondsIn<uint32_t>(days, _hour, _minute, _second);
|
||||
}
|
||||
|
||||
uint64_t RtcDateTime::TotalSeconds64() const
|
||||
{
|
||||
uint32_t days = DaysSinceFirstOfYear2000<uint32_t>(_yearFrom2000, _month, _dayOfMonth);
|
||||
return SecondsIn<uint64_t>(days, _hour, _minute, _second);
|
||||
}
|
||||
146
arduino-libs/arduino-cli/libraries/yfrobot/RtcDateTime.h
Normal file
146
arduino-libs/arduino-cli/libraries/yfrobot/RtcDateTime.h
Normal file
@@ -0,0 +1,146 @@
|
||||
|
||||
|
||||
#ifndef __RTCDATETIME_H__
|
||||
#define __RTCDATETIME_H__
|
||||
|
||||
// ESP32 complains if not included
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
const uint16_t c_OriginYear = 2000;
|
||||
const uint32_t c_Epoch32OfOriginYear = 946684800;
|
||||
extern const uint8_t c_daysInMonth[] PROGMEM;
|
||||
|
||||
class RtcDateTime
|
||||
{
|
||||
public:
|
||||
RtcDateTime(uint32_t secondsFrom2000 = 0);
|
||||
RtcDateTime(uint16_t year,
|
||||
uint8_t month,
|
||||
uint8_t dayOfMonth,
|
||||
uint8_t hour,
|
||||
uint8_t minute,
|
||||
uint8_t second) :
|
||||
_yearFrom2000((year >= c_OriginYear) ? year - c_OriginYear : year),
|
||||
_month(month),
|
||||
_dayOfMonth(dayOfMonth),
|
||||
_hour(hour),
|
||||
_minute(minute),
|
||||
_second(second)
|
||||
{
|
||||
}
|
||||
|
||||
// RtcDateTime compileDateTime(__DATE__, __TIME__);
|
||||
RtcDateTime(const char* date, const char* time);
|
||||
|
||||
uint16_t Year() const
|
||||
{
|
||||
return c_OriginYear + _yearFrom2000;
|
||||
}
|
||||
uint8_t Month() const
|
||||
{
|
||||
return _month;
|
||||
}
|
||||
uint8_t Day() const
|
||||
{
|
||||
return _dayOfMonth;
|
||||
}
|
||||
uint8_t Hour() const
|
||||
{
|
||||
return _hour;
|
||||
}
|
||||
uint8_t Minute() const
|
||||
{
|
||||
return _minute;
|
||||
}
|
||||
uint8_t Second() const
|
||||
{
|
||||
return _second;
|
||||
}
|
||||
uint8_t DayOfWeek() const;
|
||||
|
||||
// 32-bit times as seconds since 1/1/2000
|
||||
uint32_t TotalSeconds() const;
|
||||
uint64_t TotalSeconds64() const;
|
||||
|
||||
// add seconds
|
||||
void operator += (uint32_t seconds)
|
||||
{
|
||||
RtcDateTime after = RtcDateTime( TotalSeconds() + seconds );
|
||||
*this = after;
|
||||
}
|
||||
|
||||
// remove seconds
|
||||
void operator -= (uint32_t seconds)
|
||||
{
|
||||
RtcDateTime before = RtcDateTime( TotalSeconds() - seconds );
|
||||
*this = before;
|
||||
}
|
||||
|
||||
// allows for comparisons to just work (==, <, >, <=, >=, !=)
|
||||
operator uint32_t() const
|
||||
{
|
||||
return TotalSeconds();
|
||||
}
|
||||
|
||||
// Epoch32 support
|
||||
uint32_t Epoch32Time() const
|
||||
{
|
||||
return TotalSeconds() + c_Epoch32OfOriginYear;
|
||||
}
|
||||
void InitWithEpoch32Time(uint32_t time)
|
||||
{
|
||||
_initWithSecondsFrom2000<uint32_t>(time - c_Epoch32OfOriginYear);
|
||||
}
|
||||
|
||||
// Epoch64 support
|
||||
uint64_t Epoch64Time() const
|
||||
{
|
||||
return TotalSeconds64() + c_Epoch32OfOriginYear;
|
||||
}
|
||||
void InitWithEpoch64Time(uint64_t time)
|
||||
{
|
||||
_initWithSecondsFrom2000<uint64_t>(time - c_Epoch32OfOriginYear);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t _yearFrom2000;
|
||||
uint8_t _month;
|
||||
uint8_t _dayOfMonth;
|
||||
uint8_t _hour;
|
||||
uint8_t _minute;
|
||||
uint8_t _second;
|
||||
|
||||
template <typename T> void _initWithSecondsFrom2000(T secondsFrom2000)
|
||||
{
|
||||
_second = secondsFrom2000 % 60;
|
||||
T timeFrom2000 = secondsFrom2000 / 60;
|
||||
_minute = timeFrom2000 % 60;
|
||||
timeFrom2000 /= 60;
|
||||
_hour = timeFrom2000 % 24;
|
||||
T days = timeFrom2000 / 24;
|
||||
T leapDays;
|
||||
|
||||
for (_yearFrom2000 = 0;; ++_yearFrom2000)
|
||||
{
|
||||
leapDays = (_yearFrom2000 % 4 == 0) ? 1 : 0;
|
||||
if (days < 365U + leapDays)
|
||||
break;
|
||||
days -= 365 + leapDays;
|
||||
}
|
||||
for (_month = 1;; ++_month)
|
||||
{
|
||||
uint8_t daysPerMonth = pgm_read_byte(c_daysInMonth + _month - 1);
|
||||
if (leapDays && _month == 2)
|
||||
daysPerMonth++;
|
||||
if (days < daysPerMonth)
|
||||
break;
|
||||
days -= daysPerMonth;
|
||||
}
|
||||
_dayOfMonth = days + 1;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // __RTCDATETIME_H__
|
||||
38
arduino-libs/arduino-cli/libraries/yfrobot/RtcTemperature.h
Normal file
38
arduino-libs/arduino-cli/libraries/yfrobot/RtcTemperature.h
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
|
||||
#ifndef __RTCTEMPERATURE_H__
|
||||
#define __RTCTEMPERATURE_H__
|
||||
|
||||
|
||||
class RtcTemperature
|
||||
{
|
||||
public:
|
||||
RtcTemperature(int8_t degrees, uint8_t fraction) :
|
||||
integerDegrees(degrees),
|
||||
decimalFraction(fraction)
|
||||
{
|
||||
}
|
||||
|
||||
float AsFloat()
|
||||
{
|
||||
float degrees = (float)integerDegrees;
|
||||
degrees += (float)decimalFraction / ((degrees < 0) ? -100.0f : 100.0f) ;
|
||||
return degrees;
|
||||
}
|
||||
|
||||
int8_t AsWholeDegrees()
|
||||
{
|
||||
return integerDegrees;
|
||||
}
|
||||
|
||||
uint8_t GetFractional()
|
||||
{
|
||||
return decimalFraction;
|
||||
}
|
||||
|
||||
protected:
|
||||
int8_t integerDegrees;
|
||||
uint8_t decimalFraction;
|
||||
};
|
||||
|
||||
#endif // __RTCTEMPERATURE_H__
|
||||
34
arduino-libs/arduino-cli/libraries/yfrobot/RtcUtility.cpp
Normal file
34
arduino-libs/arduino-cli/libraries/yfrobot/RtcUtility.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "RtcUtility.h"
|
||||
|
||||
uint8_t BcdToUint8(uint8_t val)
|
||||
{
|
||||
return val - 6 * (val >> 4);
|
||||
}
|
||||
|
||||
uint8_t Uint8ToBcd(uint8_t val)
|
||||
{
|
||||
return val + 6 * (val / 10);
|
||||
}
|
||||
|
||||
uint8_t BcdToBin24Hour(uint8_t bcdHour)
|
||||
{
|
||||
uint8_t hour;
|
||||
if (bcdHour & 0x40)
|
||||
{
|
||||
// 12 hour mode, convert to 24
|
||||
bool isPm = ((bcdHour & 0x20) != 0);
|
||||
|
||||
hour = BcdToUint8(bcdHour & 0x1f);
|
||||
if (isPm)
|
||||
{
|
||||
hour += 12;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hour = BcdToUint8(bcdHour);
|
||||
}
|
||||
return hour;
|
||||
}
|
||||
19
arduino-libs/arduino-cli/libraries/yfrobot/RtcUtility.h
Normal file
19
arduino-libs/arduino-cli/libraries/yfrobot/RtcUtility.h
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
#ifndef __RTCUTILITY_H__
|
||||
#define __RTCUTILITY_H__
|
||||
|
||||
// ESP32 complains if not included
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
// for some reason, the DUE board support does not define this, even though other non AVR archs do
|
||||
#ifndef _BV
|
||||
#define _BV(b) (1UL << (b))
|
||||
#endif
|
||||
|
||||
extern uint8_t BcdToUint8(uint8_t val);
|
||||
extern uint8_t Uint8ToBcd(uint8_t val);
|
||||
extern uint8_t BcdToBin24Hour(uint8_t bcdHour);
|
||||
|
||||
#endif // __RTCUTILITY_H__
|
||||
209
arduino-libs/arduino-cli/libraries/yfrobot/TimerOne.cpp
Normal file
209
arduino-libs/arduino-cli/libraries/yfrobot/TimerOne.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Interrupt and PWM utilities for 16 bit Timer1 on ATmega168/328
|
||||
* Original code by Jesse Tane for http://labs.ideo.com August 2008
|
||||
* Modified March 2009 by Jérôme Despatis and Jesse Tane for ATmega328 support
|
||||
* Modified June 2009 by Michael Polli and Jesse Tane to fix a bug in setPeriod() which caused the timer to stop
|
||||
* Modified June 2011 by Lex Talionis to add a function to read the timer
|
||||
* Modified Oct 2011 by Andrew Richards to avoid certain problems:
|
||||
* - Add (long) assignments and casts to TimerOne::read() to ensure calculations involving tmp, ICR1 and TCNT1 aren't truncated
|
||||
* - Ensure 16 bit registers accesses are atomic - run with interrupts disabled when accessing
|
||||
* - Remove global enable of interrupts (sei())- could be running within an interrupt routine)
|
||||
* - Disable interrupts whilst TCTN1 == 0. Datasheet vague on this, but experiment shows that overflow interrupt
|
||||
* flag gets set whilst TCNT1 == 0, resulting in a phantom interrupt. Could just set to 1, but gets inaccurate
|
||||
* at very short durations
|
||||
* - startBottom() added to start counter at 0 and handle all interrupt enabling.
|
||||
* - start() amended to enable interrupts
|
||||
* - restart() amended to point at startBottom()
|
||||
* Modiied 7:26 PM Sunday, October 09, 2011 by Lex Talionis
|
||||
* - renamed start() to resume() to reflect it's actual role
|
||||
* - renamed startBottom() to start(). This breaks some old code that expects start to continue counting where it left off
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See Google Code project http://code.google.com/p/arduino-timerone/ for latest
|
||||
*/
|
||||
#ifndef TIMERONE_cpp
|
||||
#define TIMERONE_cpp
|
||||
|
||||
#include "TimerOne.h"
|
||||
|
||||
TimerOne Timer1; // preinstatiate
|
||||
|
||||
ISR(TIMER1_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt
|
||||
{
|
||||
Timer1.isrCallback();
|
||||
}
|
||||
|
||||
|
||||
void TimerOne::initialize(long microseconds)
|
||||
{
|
||||
TCCR1A = 0; // clear control register A
|
||||
TCCR1B = _BV(WGM13); // set mode 8: phase and frequency correct pwm, stop the timer
|
||||
setPeriod(microseconds);
|
||||
}
|
||||
|
||||
|
||||
void TimerOne::setPeriod(long microseconds) // AR modified for atomic access
|
||||
{
|
||||
|
||||
long cycles = (F_CPU / 2000000) * microseconds; // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
|
||||
if(cycles < RESOLUTION) clockSelectBits = _BV(CS10); // no prescale, full xtal
|
||||
else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11); // prescale by /8
|
||||
else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10); // prescale by /64
|
||||
else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12); // prescale by /256
|
||||
else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10); // prescale by /1024
|
||||
else cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10); // request was out of bounds, set as maximum
|
||||
|
||||
oldSREG = SREG;
|
||||
cli(); // Disable interrupts for 16 bit register access
|
||||
ICR1 = pwmPeriod = cycles; // ICR1 is TOP in p & f correct pwm mode
|
||||
SREG = oldSREG;
|
||||
|
||||
TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
|
||||
TCCR1B |= clockSelectBits; // reset clock select register, and starts the clock
|
||||
}
|
||||
|
||||
void TimerOne::setPwmDuty(char pin, int duty)
|
||||
{
|
||||
unsigned long dutyCycle = pwmPeriod;
|
||||
|
||||
dutyCycle *= duty;
|
||||
dutyCycle >>= 10;
|
||||
|
||||
oldSREG = SREG;
|
||||
cli();
|
||||
if(pin == 1 || pin == 9) OCR1A = dutyCycle;
|
||||
else if(pin == 2 || pin == 10) OCR1B = dutyCycle;
|
||||
SREG = oldSREG;
|
||||
}
|
||||
|
||||
void TimerOne::pwm(char pin, int duty, long microseconds) // expects duty cycle to be 10 bit (1024)
|
||||
{
|
||||
if(microseconds > 0) setPeriod(microseconds);
|
||||
if(pin == 1 || pin == 9) {
|
||||
DDRB |= _BV(PORTB1); // sets data direction register for pwm output pin
|
||||
TCCR1A |= _BV(COM1A1); // activates the output pin
|
||||
}
|
||||
else if(pin == 2 || pin == 10) {
|
||||
DDRB |= _BV(PORTB2);
|
||||
TCCR1A |= _BV(COM1B1);
|
||||
}
|
||||
setPwmDuty(pin, duty);
|
||||
resume(); // Lex - make sure the clock is running. We don't want to restart the count, in case we are starting the second WGM
|
||||
// and the first one is in the middle of a cycle
|
||||
}
|
||||
|
||||
void TimerOne::disablePwm(char pin)
|
||||
{
|
||||
if(pin == 1 || pin == 9) TCCR1A &= ~_BV(COM1A1); // clear the bit that enables pwm on PB1
|
||||
else if(pin == 2 || pin == 10) TCCR1A &= ~_BV(COM1B1); // clear the bit that enables pwm on PB2
|
||||
}
|
||||
|
||||
void TimerOne::attachInterrupt(void (*isr)(), long microseconds)
|
||||
{
|
||||
if(microseconds > 0) setPeriod(microseconds);
|
||||
isrCallback = isr; // register the user's callback with the real ISR
|
||||
TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit
|
||||
// might be running with interrupts disabled (eg inside an ISR), so don't touch the global state
|
||||
// sei();
|
||||
resume();
|
||||
}
|
||||
|
||||
void TimerOne::detachInterrupt()
|
||||
{
|
||||
TIMSK1 &= ~_BV(TOIE1); // clears the timer overflow interrupt enable bit
|
||||
// timer continues to count without calling the isr
|
||||
}
|
||||
|
||||
void TimerOne::resume() // AR suggested
|
||||
{
|
||||
TCCR1B |= clockSelectBits;
|
||||
}
|
||||
|
||||
void TimerOne::restart() // Depricated - Public interface to start at zero - Lex 10/9/2011
|
||||
{
|
||||
start();
|
||||
}
|
||||
|
||||
void TimerOne::start() // AR addition, renamed by Lex to reflect it's actual role
|
||||
{
|
||||
unsigned int tcnt1;
|
||||
|
||||
TIMSK1 &= ~_BV(TOIE1); // AR added
|
||||
GTCCR |= _BV(PSRSYNC); // AR added - reset prescaler (NB: shared with all 16 bit timers);
|
||||
|
||||
oldSREG = SREG; // AR - save status register
|
||||
cli(); // AR - Disable interrupts
|
||||
TCNT1 = 0;
|
||||
SREG = oldSREG; // AR - Restore status register
|
||||
resume();
|
||||
do { // Nothing -- wait until timer moved on from zero - otherwise get a phantom interrupt
|
||||
oldSREG = SREG;
|
||||
cli();
|
||||
tcnt1 = TCNT1;
|
||||
SREG = oldSREG;
|
||||
} while (tcnt1==0);
|
||||
|
||||
// TIFR1 = 0xff; // AR - Clear interrupt flags
|
||||
// TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit
|
||||
}
|
||||
|
||||
void TimerOne::stop()
|
||||
{
|
||||
TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); // clears all clock selects bits
|
||||
}
|
||||
|
||||
unsigned long TimerOne::read() //returns the value of the timer in microseconds
|
||||
{ //rember! phase and freq correct mode counts up to then down again
|
||||
unsigned long tmp; // AR amended to hold more than 65536 (could be nearly double this)
|
||||
unsigned int tcnt1; // AR added
|
||||
|
||||
oldSREG= SREG;
|
||||
cli();
|
||||
tmp=TCNT1;
|
||||
SREG = oldSREG;
|
||||
|
||||
char scale=0;
|
||||
switch (clockSelectBits)
|
||||
{
|
||||
case 1:// no prescalse
|
||||
scale=0;
|
||||
break;
|
||||
case 2:// x8 prescale
|
||||
scale=3;
|
||||
break;
|
||||
case 3:// x64
|
||||
scale=6;
|
||||
break;
|
||||
case 4:// x256
|
||||
scale=8;
|
||||
break;
|
||||
case 5:// x1024
|
||||
scale=10;
|
||||
break;
|
||||
}
|
||||
|
||||
do { // Nothing -- max delay here is ~1023 cycles. AR modified
|
||||
oldSREG = SREG;
|
||||
cli();
|
||||
tcnt1 = TCNT1;
|
||||
SREG = oldSREG;
|
||||
} while (tcnt1==tmp); //if the timer has not ticked yet
|
||||
|
||||
//if we are counting down add the top value to how far we have counted down
|
||||
tmp = ( (tcnt1>tmp) ? (tmp) : (long)(ICR1-tcnt1)+(long)ICR1 ); // AR amended to add casts and reuse previous TCNT1
|
||||
return ((tmp*1000L)/(F_CPU /1000L))<<scale;
|
||||
}
|
||||
|
||||
#endif
|
||||
70
arduino-libs/arduino-cli/libraries/yfrobot/TimerOne.h
Normal file
70
arduino-libs/arduino-cli/libraries/yfrobot/TimerOne.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Interrupt and PWM utilities for 16 bit Timer1 on ATmega168/328
|
||||
* Original code by Jesse Tane for http://labs.ideo.com August 2008
|
||||
* Modified March 2009 by Jérôme Despatis and Jesse Tane for ATmega328 support
|
||||
* Modified June 2009 by Michael Polli and Jesse Tane to fix a bug in setPeriod() which caused the timer to stop
|
||||
* Modified June 2011 by Lex Talionis to add a function to read the timer
|
||||
* Modified Oct 2011 by Andrew Richards to avoid certain problems:
|
||||
* - Add (long) assignments and casts to TimerOne::read() to ensure calculations involving tmp, ICR1 and TCNT1 aren't truncated
|
||||
* - Ensure 16 bit registers accesses are atomic - run with interrupts disabled when accessing
|
||||
* - Remove global enable of interrupts (sei())- could be running within an interrupt routine)
|
||||
* - Disable interrupts whilst TCTN1 == 0. Datasheet vague on this, but experiment shows that overflow interrupt
|
||||
* flag gets set whilst TCNT1 == 0, resulting in a phantom interrupt. Could just set to 1, but gets inaccurate
|
||||
* at very short durations
|
||||
* - startBottom() added to start counter at 0 and handle all interrupt enabling.
|
||||
* - start() amended to enable interrupts
|
||||
* - restart() amended to point at startBottom()
|
||||
* Modiied 7:26 PM Sunday, October 09, 2011 by Lex Talionis
|
||||
* - renamed start() to resume() to reflect it's actual role
|
||||
* - renamed startBottom() to start(). This breaks some old code that expects start to continue counting where it left off
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See Google Code project http://code.google.com/p/arduino-timerone/ for latest
|
||||
*/
|
||||
#ifndef TIMERONE_h
|
||||
#define TIMERONE_h
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#define RESOLUTION 65536 // Timer1 is 16 bit
|
||||
|
||||
class TimerOne
|
||||
{
|
||||
public:
|
||||
|
||||
// properties
|
||||
unsigned int pwmPeriod;
|
||||
unsigned char clockSelectBits;
|
||||
char oldSREG; // To hold Status Register while ints disabled
|
||||
|
||||
// methods
|
||||
void initialize(long microseconds=1000000);
|
||||
void start();
|
||||
void stop();
|
||||
void restart();
|
||||
void resume();
|
||||
unsigned long read();
|
||||
void pwm(char pin, int duty, long microseconds=-1);
|
||||
void disablePwm(char pin);
|
||||
void attachInterrupt(void (*isr)(), long microseconds=-1);
|
||||
void detachInterrupt();
|
||||
void setPeriod(long microseconds);
|
||||
void setPwmDuty(char pin, int duty);
|
||||
void (*isrCallback)();
|
||||
};
|
||||
|
||||
extern TimerOne Timer1;
|
||||
#endif
|
||||
478
arduino-libs/arduino-cli/libraries/yfrobot/YFTM1650.h
Normal file
478
arduino-libs/arduino-cli/libraries/yfrobot/YFTM1650.h
Normal file
@@ -0,0 +1,478 @@
|
||||
/*-------------------------------------------------------------------------------------
|
||||
|
||||
YFTM1650.h -
|
||||
8-segment display driver of YFRobot 4-bit digital tube module based on YFTM1650 chip
|
||||
Created by yfrobot,Released into the public domain.
|
||||
Product: https://item.taobao.com/item.htm?id=561918482249
|
||||
Changelog:
|
||||
v1.0:
|
||||
2017/12/25 - Initial release
|
||||
v1.1:
|
||||
2020/03/25 - 统一修改TM1650为YFTM1650(避免与其他库混淆)
|
||||
新增显示float/double/int类型函数
|
||||
新增显示滚动字符函数
|
||||
|
||||
----------------------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _TM1650_H_
|
||||
#define _TM1650_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#define TM1650_USE_PROGMEM
|
||||
|
||||
#ifdef TM1650_USE_PROGMEM
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
/** Definitions **/
|
||||
|
||||
#define _8_SEGMENT_MODE 0x00 // 8段显示模式
|
||||
#define _7_SEGMENT_MODE 0x08 // 7段显示模式
|
||||
|
||||
#define NORMAL_MODE 0x00 // 正常工作模式
|
||||
#define STANDBY_MODE 0x04 // 待机工作模式
|
||||
|
||||
#define DISPLAY_ON 0x01
|
||||
#define DISPLAY_OFF 0x00
|
||||
|
||||
#define CMD_SYSTEM_CONFIG 0x48
|
||||
// #define CMD_READ_KEYPAD 0x4F
|
||||
|
||||
#define DIG1_ADDRESS 0x68
|
||||
#define DIG2_ADDRESS 0x6A
|
||||
#define DIG3_ADDRESS 0x6C
|
||||
#define DIG4_ADDRESS 0x6E
|
||||
|
||||
#define TM1650_NUM_DIGITS 16 // max number of digits 最大数字位数
|
||||
#define TM1650_MAX_STRING 128 // number of digits 位数
|
||||
|
||||
const unsigned char Brightness[9] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x00};
|
||||
const unsigned char DisplayAddressArray[4] = {DIG1_ADDRESS,DIG2_ADDRESS,DIG3_ADDRESS,DIG4_ADDRESS};
|
||||
const unsigned int iNumDigits = 4;
|
||||
//number 0-9 code
|
||||
//const unsigned char Number_arr[10] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f};
|
||||
|
||||
#ifndef TM1650_USE_PROGMEM
|
||||
const byte TM1650_CDigits[128] {
|
||||
#else
|
||||
const PROGMEM byte TM1650_CDigits[128] {
|
||||
#endif
|
||||
//0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10
|
||||
0x00, 0x82, 0x21, 0x00, 0x00, 0x00, 0x00, 0x02, 0x39, 0x0F, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, // 0x20
|
||||
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7f, 0x6f, 0x00, 0x00, 0x00, 0x48, 0x00, 0x53, // 0x30
|
||||
0x00, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x6F, 0x76, 0x06, 0x1E, 0x00, 0x38, 0x00, 0x54, 0x3F, // 0x40
|
||||
0x73, 0x67, 0x50, 0x6D, 0x78, 0x3E, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x39, 0x00, 0x0F, 0x00, 0x08, // 0x50
|
||||
0x63, 0x5F, 0x7C, 0x58, 0x5E, 0x7B, 0x71, 0x6F, 0x74, 0x02, 0x1E, 0x00, 0x06, 0x00, 0x54, 0x5C, // 0x60
|
||||
0x73, 0x67, 0x50, 0x6D, 0x78, 0x1C, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x39, 0x30, 0x0F, 0x00, 0x00 // 0x70
|
||||
};
|
||||
|
||||
class YFTM1650
|
||||
{
|
||||
public:
|
||||
YFTM1650(int pin_SCK,int pin_DIO);
|
||||
void init();
|
||||
void clear();
|
||||
// void clearDot();
|
||||
void displayString(char *aString);
|
||||
void displayString(String sString);
|
||||
void displayString(float value);
|
||||
void displayString(double value);// 与float完全相同,arduino中double和float精度完全相同
|
||||
void displayString(int value);
|
||||
boolean displayOneDigi(unsigned char digi,unsigned char cha);
|
||||
void displayOn();
|
||||
void displayOff();
|
||||
boolean displayOff(unsigned char lightLevel,unsigned char SegmentMode,unsigned char WorkMode);
|
||||
boolean displayOn(unsigned char lightLevel,unsigned char SegmentMode,unsigned char WorkMode);
|
||||
void setDot(unsigned int aPos, bool aState);
|
||||
void setBrightness(unsigned int iBrightness);
|
||||
int displayRunning(String aString);
|
||||
int displayRunning(char *aString);
|
||||
int displayRunningShift();
|
||||
|
||||
private:
|
||||
int _pin_SCK; //clock in pin
|
||||
int _pin_DIO; //data in and out pin
|
||||
|
||||
char *iPosition;
|
||||
char iString[TM1650_MAX_STRING+1];
|
||||
byte iBuffer_num[TM1650_NUM_DIGITS+1]; // 数字位
|
||||
byte iBuffer_dot[TM1650_NUM_DIGITS+1]; // 小数点位
|
||||
byte SegmentMode;
|
||||
byte WorkMode;
|
||||
byte DsplayONOFF;
|
||||
|
||||
void FrameStart_1650(void);
|
||||
void FrameEnd_1650(void);
|
||||
boolean FrameAck_1650(void);
|
||||
boolean writeByte(unsigned char firstByte,unsigned char secondByte);
|
||||
};
|
||||
|
||||
|
||||
/*==================================================*/
|
||||
|
||||
/**
|
||||
*/
|
||||
YFTM1650::YFTM1650(int pin_SCK,int pin_DIO)
|
||||
{
|
||||
pinMode(pin_SCK, OUTPUT);
|
||||
pinMode(pin_DIO, OUTPUT);
|
||||
|
||||
_pin_SCK = pin_SCK;
|
||||
_pin_DIO = pin_DIO;
|
||||
}
|
||||
|
||||
/** FrameStart_1650
|
||||
*/
|
||||
void YFTM1650::FrameStart_1650(void)
|
||||
{
|
||||
|
||||
digitalWrite(_pin_DIO , HIGH);
|
||||
digitalWrite(_pin_SCK , HIGH);
|
||||
digitalWrite(_pin_DIO , LOW);
|
||||
}
|
||||
|
||||
/** FrameEnd_1650
|
||||
*/
|
||||
void YFTM1650::FrameEnd_1650(void)
|
||||
{
|
||||
digitalWrite(_pin_DIO , LOW);
|
||||
digitalWrite(_pin_SCK , HIGH);
|
||||
digitalWrite(_pin_DIO , HIGH);
|
||||
}
|
||||
|
||||
/** FrameAck_1650
|
||||
*/
|
||||
boolean YFTM1650::FrameAck_1650(void)
|
||||
{
|
||||
if(digitalRead(_pin_DIO) == LOW)
|
||||
{
|
||||
digitalWrite(_pin_SCK , HIGH);
|
||||
digitalWrite(_pin_SCK , LOW);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/** writeByte
|
||||
*/
|
||||
boolean YFTM1650::writeByte(unsigned char firstByte,unsigned char secondByte)
|
||||
{
|
||||
unsigned char tmp;
|
||||
unsigned char i=0;
|
||||
boolean err=0;
|
||||
|
||||
tmp=firstByte;
|
||||
|
||||
FrameStart_1650();
|
||||
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
if(tmp&0x80)
|
||||
{
|
||||
digitalWrite(_pin_DIO , HIGH);
|
||||
}
|
||||
else
|
||||
{
|
||||
digitalWrite(_pin_DIO , LOW);
|
||||
}
|
||||
|
||||
digitalWrite(_pin_SCK , LOW);
|
||||
digitalWrite(_pin_SCK , HIGH);
|
||||
digitalWrite(_pin_SCK , LOW);
|
||||
|
||||
tmp=tmp<<1;
|
||||
}
|
||||
|
||||
if(FrameAck_1650()==1)
|
||||
{
|
||||
err=1;
|
||||
}
|
||||
|
||||
tmp=secondByte;
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
if(tmp&0x80)
|
||||
{
|
||||
digitalWrite(_pin_DIO , HIGH);
|
||||
}
|
||||
else
|
||||
{
|
||||
digitalWrite(_pin_DIO , LOW);
|
||||
}
|
||||
|
||||
digitalWrite(_pin_SCK , LOW);
|
||||
digitalWrite(_pin_SCK , HIGH);
|
||||
digitalWrite(_pin_SCK , LOW);
|
||||
|
||||
tmp=tmp<<1;
|
||||
}
|
||||
|
||||
if(FrameAck_1650()==1)
|
||||
{
|
||||
err=1;
|
||||
}
|
||||
|
||||
FrameEnd_1650();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/** init 初始化
|
||||
*/
|
||||
void YFTM1650::init()
|
||||
{
|
||||
iPosition = NULL;
|
||||
for (int i=0; i<iNumDigits; i++) {
|
||||
// iCtrl[i] = 0;
|
||||
iBuffer_num[i] = 0;
|
||||
iBuffer_dot[i] = 0;
|
||||
}
|
||||
SegmentMode = _8_SEGMENT_MODE;
|
||||
WorkMode = NORMAL_MODE;
|
||||
DsplayONOFF = DISPLAY_ON;
|
||||
clear();
|
||||
displayOn();
|
||||
}
|
||||
|
||||
/** display n --
|
||||
*
|
||||
*/
|
||||
boolean YFTM1650::displayOneDigi(unsigned char digi,unsigned char cha)
|
||||
{
|
||||
unsigned char tmp = 0;
|
||||
boolean err = 0;
|
||||
err = writeByte(DisplayAddressArray[digi-1],cha);
|
||||
return err;
|
||||
}
|
||||
|
||||
/** displayString -- 显示字符串
|
||||
*
|
||||
*/
|
||||
void YFTM1650::displayString(char *aString)
|
||||
{
|
||||
for (int i=0; i<iNumDigits; i++) {
|
||||
byte a = ((byte) aString[i]) & 0b01111111;
|
||||
#ifndef TM1650_USE_PROGMEM
|
||||
iBuffer_num[i] = TM1650_CDigits[a];
|
||||
#else
|
||||
iBuffer_num[i] = pgm_read_byte_near(TM1650_CDigits + a);
|
||||
#endif
|
||||
if (a) {
|
||||
writeByte(DisplayAddressArray[i],iBuffer_num[i] | iBuffer_dot[i]);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
/** displayString -- 显示字符串
|
||||
*
|
||||
*/
|
||||
void YFTM1650::displayString(String sString)
|
||||
{
|
||||
for (int i=0; i<iNumDigits; i++) {
|
||||
byte a = ((byte) sString.c_str()[i]) & 0b01111111;
|
||||
#ifndef TM1650_USE_PROGMEM
|
||||
iBuffer_num[i] = TM1650_CDigits[a];
|
||||
#else
|
||||
iBuffer_num[i] = pgm_read_byte_near(TM1650_CDigits + a);
|
||||
#endif
|
||||
if (a) {
|
||||
writeByte(DisplayAddressArray[i],iBuffer_num[i] | iBuffer_dot[i]);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
/** displayString -- 显示float
|
||||
* 保留两位小数
|
||||
*/
|
||||
void YFTM1650::displayString(float value)
|
||||
{
|
||||
int f_value = int(value*100); // float值 放大100倍,并转换int类型
|
||||
if(f_value > 9999){ // 当数字大于9999(四位数)则只显示后四位
|
||||
f_value = f_value%10000;
|
||||
}
|
||||
if(f_value < -999){
|
||||
iBuffer_dot[1] = 0; // 无法显示
|
||||
}else{
|
||||
iBuffer_dot[1] = 0b10000000; // 保留两位小数
|
||||
}
|
||||
displayString(f_value);
|
||||
iBuffer_dot[1] = 0; // 数码管小数点位清除
|
||||
}
|
||||
|
||||
/** displayString -- 显示double
|
||||
* 保留两位小数
|
||||
* 与float完全相同,arduino中double和float精度完全相同
|
||||
*/
|
||||
void YFTM1650::displayString(double value)
|
||||
{
|
||||
displayString(float(value));
|
||||
}
|
||||
|
||||
/** displayString -- 显示int
|
||||
* value 范围:-999 ~ 9999
|
||||
* 超出显示范围,则不显示
|
||||
*/
|
||||
void YFTM1650::displayString(int value)
|
||||
{
|
||||
if(value > 9999 || value < -999){
|
||||
// 超出显示范围,则不显示
|
||||
}else{
|
||||
String aString = String("") + value;
|
||||
unsigned int slen = aString.length();
|
||||
|
||||
for (int i = 0; i < 4 - slen; i++)
|
||||
aString = " " + aString;
|
||||
for (int i = 0; i<iNumDigits; i++) {
|
||||
byte a = ((byte)aString.charAt(i)) & 0b01111111;
|
||||
#ifndef TM1650_USE_PROGMEM
|
||||
iBuffer_num[i] = TM1650_CDigits[a];
|
||||
#else
|
||||
iBuffer_num[i] = pgm_read_byte_near(TM1650_CDigits + a);
|
||||
#endif
|
||||
if (a) {
|
||||
writeByte(DisplayAddressArray[i],iBuffer_num[i] | iBuffer_dot[i]);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** display off -- 关闭显示
|
||||
* lightLevel 亮度等级
|
||||
* SegmentMode 显示模式(7/8段显示)
|
||||
* WorkMode 工作模式(待机/正常工作模式)
|
||||
*/
|
||||
boolean YFTM1650::displayOff(unsigned char lightLevel,unsigned char SegmentMode,unsigned char WorkMode)
|
||||
{
|
||||
unsigned char tmp = 0;
|
||||
boolean err = 0;
|
||||
tmp = lightLevel | SegmentMode | WorkMode | DISPLAY_OFF;
|
||||
err = writeByte(CMD_SYSTEM_CONFIG,tmp);
|
||||
|
||||
if(err == 1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** display off -- 关闭显示
|
||||
*/
|
||||
void YFTM1650::displayOff(){
|
||||
displayOff(Brightness[7], SegmentMode, WorkMode);
|
||||
}
|
||||
|
||||
/** display on -- 打开显示
|
||||
* lightLevel 亮度等级
|
||||
* SegmentMode 显示模式(7/8段显示)
|
||||
* WorkMode 工作模式(待机/正常工作模式)
|
||||
*/
|
||||
boolean YFTM1650::displayOn(unsigned char lightLevel,unsigned char SegmentMode,unsigned char WorkMode)
|
||||
{
|
||||
unsigned char tmp = 0;
|
||||
boolean err = 0;
|
||||
tmp = lightLevel | SegmentMode | WorkMode | DISPLAY_ON;
|
||||
err = writeByte(CMD_SYSTEM_CONFIG,tmp);
|
||||
|
||||
if(err == 1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** display on -- 打开显示
|
||||
*/
|
||||
void YFTM1650::displayOn(){
|
||||
displayOn(Brightness[7], SegmentMode, WorkMode);
|
||||
}
|
||||
|
||||
/** clear -- 清除显示
|
||||
*/
|
||||
void YFTM1650::clear(){
|
||||
for (int i=0; i<iNumDigits; i++) {
|
||||
iBuffer_num[i] = 0;
|
||||
iBuffer_dot[i] = 0;
|
||||
writeByte(DisplayAddressArray[i],iBuffer_num[i] | iBuffer_dot[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Directly set/clear a 'dot' next to a specific position 直接设置/清除特定位置旁边的“点”
|
||||
* aPos = position to set/clear the dot for aPos =设置/清除点的位置
|
||||
* aState = display the dot if true, clear if false aState =如果为真则显示点,否则清除
|
||||
*
|
||||
* Internal buffer is updated as well 内部缓冲区也被更新
|
||||
*/
|
||||
void YFTM1650::setDot(unsigned int aPos, bool aState) {
|
||||
iBuffer_dot[aPos] = aState ? 0b10000000 : 0;
|
||||
if (aPos < iNumDigits) {
|
||||
writeByte(DisplayAddressArray[aPos] , iBuffer_num[aPos] | iBuffer_dot[aPos]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Set brightness of all digits equally 平均设置所有数字的亮度
|
||||
* aValue - brightness value with 1 being the lowest, and 8 being the brightest
|
||||
* aValue - 亮度值1代表最低,8代表最亮(实际设置值0~7)
|
||||
*/
|
||||
void YFTM1650::setBrightness(unsigned int aValue) {
|
||||
unsigned int iBrightness = Brightness[((aValue > 8) ? 8 : (aValue < 1) ? 1 : aValue) - 1];
|
||||
writeByte(CMD_SYSTEM_CONFIG, iBrightness | SegmentMode | WorkMode | DsplayONOFF);
|
||||
}
|
||||
|
||||
/** Display string on the display in a running fashion
|
||||
* aString = character array to be displayed
|
||||
*
|
||||
* Starts with first N positions of the string.
|
||||
* Subsequent characters are displayed with 1 char shift each time displayRunningShift() is called
|
||||
*
|
||||
* returns: number of iterations remaining to display the whole string
|
||||
*/
|
||||
int YFTM1650::displayRunning(String aString){
|
||||
strncpy(iString, aString.c_str(), TM1650_MAX_STRING+1);
|
||||
iPosition = iString;
|
||||
iString[TM1650_MAX_STRING] = '\0'; //just in case.
|
||||
displayString(iPosition);
|
||||
|
||||
int l = strlen(iPosition);
|
||||
if (l <= iNumDigits) return 0;
|
||||
return (l - iNumDigits);
|
||||
}
|
||||
|
||||
int YFTM1650::displayRunning(char *aString){
|
||||
strncpy(iString, aString, TM1650_MAX_STRING+1);
|
||||
iPosition = iString;
|
||||
iString[TM1650_MAX_STRING] = '\0'; //just in case.
|
||||
displayString(iPosition);
|
||||
|
||||
int l = strlen(iPosition);
|
||||
if (l <= iNumDigits) return 0;
|
||||
return (l - iNumDigits);
|
||||
}
|
||||
|
||||
/** Display next segment (shifting to the left) of the string set by displayRunning()
|
||||
* Starts with first N positions of the string.
|
||||
* Subsequent characters are displayed with 1 char shift each time displayRunningShift is called
|
||||
*
|
||||
* returns: number of iterations remaining to display the whole string
|
||||
*/
|
||||
int YFTM1650::displayRunningShift() {
|
||||
if (strlen(iPosition) <= iNumDigits) return 0;
|
||||
displayString(++iPosition);
|
||||
return (strlen(iPosition) - iNumDigits);
|
||||
}
|
||||
|
||||
#endif
|
||||
201
arduino-libs/arduino-cli/libraries/yfrobot/dht.cpp
Normal file
201
arduino-libs/arduino-cli/libraries/yfrobot/dht.cpp
Normal file
@@ -0,0 +1,201 @@
|
||||
//
|
||||
// FILE: dht.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.22
|
||||
// PURPOSE: DHT Temperature & Humidity Sensor library for Arduino
|
||||
// URL: http://arduino.cc/playground/Main/DHTLib
|
||||
//
|
||||
// HISTORY:
|
||||
// 0.1.22 undo delayMicroseconds() for wakeups larger than 8
|
||||
// 0.1.21 replace delay with delayMicroseconds() + small fix
|
||||
// 0.1.20 Reduce footprint by using uint8_t as error codes. (thanks to chaveiro)
|
||||
// 0.1.19 masking error for DHT11 - FIXED (thanks Richard for noticing)
|
||||
// 0.1.18 version 1.16/17 broke the DHT11 - FIXED
|
||||
// 0.1.17 replaced micros() with adaptive loopcount
|
||||
// removed DHTLIB_INVALID_VALUE
|
||||
// added DHTLIB_ERROR_CONNECT
|
||||
// added DHTLIB_ERROR_ACK_L DHTLIB_ERROR_ACK_H
|
||||
// 0.1.16 masking unused bits (less errors); refactored bits[]
|
||||
// 0.1.15 reduced # micros calls 2->1 in inner loop.
|
||||
// 0.1.14 replace digital read with faster (~3x) code => more robust low MHz machines.
|
||||
//
|
||||
// 0.1.13 fix negative temperature
|
||||
// 0.1.12 support DHT33 and DHT44 initial version
|
||||
// 0.1.11 renamed DHTLIB_TIMEOUT
|
||||
// 0.1.10 optimized faster WAKEUP + TIMEOUT
|
||||
// 0.1.09 optimize size: timeout check + use of mask
|
||||
// 0.1.08 added formula for timeout based upon clockspeed
|
||||
// 0.1.07 added support for DHT21
|
||||
// 0.1.06 minimize footprint (2012-12-27)
|
||||
// 0.1.05 fixed negative temperature bug (thanks to Roseman)
|
||||
// 0.1.04 improved readability of code using DHTLIB_OK in code
|
||||
// 0.1.03 added error values for temp and humidity when read failed
|
||||
// 0.1.02 added error codes
|
||||
// 0.1.01 added support for Arduino 1.0, fixed typos (31/12/2011)
|
||||
// 0.1.00 by Rob Tillaart (01/04/2011)
|
||||
//
|
||||
// inspired by DHT11 library
|
||||
//
|
||||
// Released to the public domain
|
||||
//
|
||||
|
||||
#include "dht.h"
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//
|
||||
// PUBLIC
|
||||
//
|
||||
|
||||
int8_t dht::read11(uint8_t pin)
|
||||
{
|
||||
// READ VALUES
|
||||
int8_t result = _readSensor(pin, DHTLIB_DHT11_WAKEUP, DHTLIB_DHT11_LEADING_ZEROS);
|
||||
|
||||
// these bits are always zero, masking them reduces errors.
|
||||
bits[0] &= 0x7F;
|
||||
bits[2] &= 0x7F;
|
||||
|
||||
// CONVERT AND STORE
|
||||
humidity = bits[0]; // bits[1] == 0;
|
||||
temperature = bits[2]; // bits[3] == 0;
|
||||
|
||||
// TEST CHECKSUM
|
||||
// bits[1] && bits[3] both 0
|
||||
uint8_t sum = bits[0] + bits[2];
|
||||
if (bits[4] != sum)
|
||||
{
|
||||
return DHTLIB_ERROR_CHECKSUM;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int8_t dht::read(uint8_t pin)
|
||||
{
|
||||
// READ VALUES
|
||||
int8_t result = _readSensor(pin, DHTLIB_DHT_WAKEUP, DHTLIB_DHT_LEADING_ZEROS);
|
||||
|
||||
// these bits are always zero, masking them reduces errors.
|
||||
bits[0] &= 0x03;
|
||||
bits[2] &= 0x83;
|
||||
|
||||
// CONVERT AND STORE
|
||||
humidity = (bits[0]*256 + bits[1]) * 0.1;
|
||||
temperature = ((bits[2] & 0x7F)*256 + bits[3]) * 0.1;
|
||||
if (bits[2] & 0x80) // negative temperature
|
||||
{
|
||||
temperature = -temperature;
|
||||
}
|
||||
|
||||
// TEST CHECKSUM
|
||||
uint8_t sum = bits[0] + bits[1] + bits[2] + bits[3];
|
||||
if (bits[4] != sum)
|
||||
{
|
||||
return DHTLIB_ERROR_CHECKSUM;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//
|
||||
// PRIVATE
|
||||
//
|
||||
|
||||
int8_t dht::_readSensor(uint8_t pin, uint8_t wakeupDelay, uint8_t leadingZeroBits)
|
||||
{
|
||||
// INIT BUFFERVAR TO RECEIVE DATA
|
||||
uint8_t mask = 128;
|
||||
uint8_t idx = 0;
|
||||
|
||||
uint8_t data = 0;
|
||||
uint8_t state = LOW;
|
||||
uint8_t pstate = LOW;
|
||||
uint16_t zeroLoop = DHTLIB_TIMEOUT;
|
||||
uint16_t delta = 0;
|
||||
|
||||
leadingZeroBits = 40 - leadingZeroBits; // reverse counting...
|
||||
|
||||
// replace digitalRead() with Direct Port Reads.
|
||||
// reduces footprint ~100 bytes => portability issue?
|
||||
// direct port read is about 3x faster
|
||||
uint8_t bit = digitalPinToBitMask(pin);
|
||||
uint8_t port = digitalPinToPort(pin);
|
||||
volatile uint8_t *PIR = portInputRegister(port);
|
||||
|
||||
// REQUEST SAMPLE
|
||||
pinMode(pin, OUTPUT);
|
||||
digitalWrite(pin, LOW); // T-be
|
||||
if (wakeupDelay > 8) delay(wakeupDelay);
|
||||
else delayMicroseconds(wakeupDelay * 1000UL);
|
||||
digitalWrite(pin, HIGH); // T-go
|
||||
pinMode(pin, INPUT);
|
||||
|
||||
uint16_t loopCount = DHTLIB_TIMEOUT * 2; // 200uSec max
|
||||
// while(digitalRead(pin) == HIGH)
|
||||
while ((*PIR & bit) != LOW )
|
||||
{
|
||||
if (--loopCount == 0) return DHTLIB_ERROR_CONNECT;
|
||||
}
|
||||
|
||||
// GET ACKNOWLEDGE or TIMEOUT
|
||||
loopCount = DHTLIB_TIMEOUT;
|
||||
// while(digitalRead(pin) == LOW)
|
||||
while ((*PIR & bit) == LOW ) // T-rel
|
||||
{
|
||||
if (--loopCount == 0) return DHTLIB_ERROR_ACK_L;
|
||||
}
|
||||
|
||||
loopCount = DHTLIB_TIMEOUT;
|
||||
// while(digitalRead(pin) == HIGH)
|
||||
while ((*PIR & bit) != LOW ) // T-reh
|
||||
{
|
||||
if (--loopCount == 0) return DHTLIB_ERROR_ACK_H;
|
||||
}
|
||||
|
||||
loopCount = DHTLIB_TIMEOUT;
|
||||
|
||||
// READ THE OUTPUT - 40 BITS => 5 BYTES
|
||||
for (uint8_t i = 40; i != 0; )
|
||||
{
|
||||
// WAIT FOR FALLING EDGE
|
||||
state = (*PIR & bit);
|
||||
if (state == LOW && pstate != LOW)
|
||||
{
|
||||
if (i > leadingZeroBits) // DHT22 first 6 bits are all zero !! DHT11 only 1
|
||||
{
|
||||
zeroLoop = min(zeroLoop, loopCount);
|
||||
delta = (DHTLIB_TIMEOUT - zeroLoop)/4;
|
||||
}
|
||||
else if ( loopCount <= (zeroLoop - delta) ) // long -> one
|
||||
{
|
||||
data |= mask;
|
||||
}
|
||||
mask >>= 1;
|
||||
if (mask == 0) // next byte
|
||||
{
|
||||
mask = 128;
|
||||
bits[idx] = data;
|
||||
idx++;
|
||||
data = 0;
|
||||
}
|
||||
// next bit
|
||||
--i;
|
||||
|
||||
// reset timeout flag
|
||||
loopCount = DHTLIB_TIMEOUT;
|
||||
}
|
||||
pstate = state;
|
||||
// Check timeout
|
||||
if (--loopCount == 0)
|
||||
{
|
||||
return DHTLIB_ERROR_TIMEOUT;
|
||||
}
|
||||
|
||||
}
|
||||
pinMode(pin, OUTPUT);
|
||||
digitalWrite(pin, HIGH);
|
||||
|
||||
return DHTLIB_OK;
|
||||
}
|
||||
//
|
||||
// END OF FILE
|
||||
//
|
||||
77
arduino-libs/arduino-cli/libraries/yfrobot/dht.h
Normal file
77
arduino-libs/arduino-cli/libraries/yfrobot/dht.h
Normal file
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// FILE: dht.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.22
|
||||
// PURPOSE: DHT Temperature & Humidity Sensor library for Arduino
|
||||
// URL: http://arduino.cc/playground/Main/DHTLib
|
||||
//
|
||||
// HISTORY:
|
||||
// see dht.cpp file
|
||||
//
|
||||
|
||||
#ifndef dht_h
|
||||
#define dht_h
|
||||
|
||||
#if ARDUINO < 100
|
||||
#include <WProgram.h>
|
||||
#include <pins_arduino.h> // fix for broken pre 1.0 version - TODO TEST
|
||||
#else
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
#define DHT_LIB_VERSION "0.1.22"
|
||||
|
||||
#define DHTLIB_OK 0
|
||||
#define DHTLIB_ERROR_CHECKSUM -1
|
||||
#define DHTLIB_ERROR_TIMEOUT -2
|
||||
#define DHTLIB_ERROR_CONNECT -3
|
||||
#define DHTLIB_ERROR_ACK_L -4
|
||||
#define DHTLIB_ERROR_ACK_H -5
|
||||
|
||||
#define DHTLIB_DHT11_WAKEUP 18
|
||||
#define DHTLIB_DHT_WAKEUP 1
|
||||
|
||||
#define DHTLIB_DHT11_LEADING_ZEROS 1
|
||||
#define DHTLIB_DHT_LEADING_ZEROS 6
|
||||
|
||||
// max timeout is 100 usec.
|
||||
// For a 16 Mhz proc 100 usec is 1600 clock cycles
|
||||
// loops using DHTLIB_TIMEOUT use at least 4 clock cycli
|
||||
// so 100 us takes max 400 loops
|
||||
// so by dividing F_CPU by 40000 we "fail" as fast as possible
|
||||
#ifndef F_CPU
|
||||
#define DHTLIB_TIMEOUT 1000 // ahould be approx. clock/40000
|
||||
#else
|
||||
#define DHTLIB_TIMEOUT (F_CPU/40000)
|
||||
#endif
|
||||
|
||||
class dht
|
||||
{
|
||||
public:
|
||||
dht() {};
|
||||
// return values:
|
||||
// DHTLIB_OK
|
||||
// DHTLIB_ERROR_CHECKSUM
|
||||
// DHTLIB_ERROR_TIMEOUT
|
||||
// DHTLIB_ERROR_CONNECT
|
||||
// DHTLIB_ERROR_ACK_L
|
||||
// DHTLIB_ERROR_ACK_H
|
||||
int8_t read11(uint8_t pin);
|
||||
int8_t read(uint8_t pin);
|
||||
|
||||
inline int8_t read21(uint8_t pin) { return read(pin); };
|
||||
inline int8_t read22(uint8_t pin) { return read(pin); };
|
||||
inline int8_t read33(uint8_t pin) { return read(pin); };
|
||||
inline int8_t read44(uint8_t pin) { return read(pin); };
|
||||
|
||||
double humidity;
|
||||
double temperature;
|
||||
|
||||
private:
|
||||
uint8_t bits[5]; // buffer to receive data
|
||||
int8_t _readSensor(uint8_t pin, uint8_t wakeupDelay, uint8_t leadingZeroBits);
|
||||
};
|
||||
#endif
|
||||
//
|
||||
// END OF FILE
|
||||
//
|
||||
67
arduino-libs/arduino-cli/libraries/yfrobot/esp8266.c
Normal file
67
arduino-libs/arduino-cli/libraries/yfrobot/esp8266.c
Normal file
@@ -0,0 +1,67 @@
|
||||
// This is a mash-up of the Due show() code + insights from Michael Miller's
|
||||
// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus
|
||||
// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution.
|
||||
|
||||
#ifdef ESP8266
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <eagle_soc.h>
|
||||
|
||||
static uint32_t _getCycleCount(void) __attribute__((always_inline));
|
||||
static inline uint32_t _getCycleCount(void) {
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR espShow(
|
||||
uint8_t pin, uint8_t *pixels, uint32_t numBytes, boolean is800KHz) {
|
||||
|
||||
#define CYCLES_800_T0H (F_CPU / 2500000) // 0.4us
|
||||
#define CYCLES_800_T1H (F_CPU / 1250000) // 0.8us
|
||||
#define CYCLES_800 (F_CPU / 800000) // 1.25us per bit
|
||||
#define CYCLES_400_T0H (F_CPU / 2000000) // 0.5uS
|
||||
#define CYCLES_400_T1H (F_CPU / 833333) // 1.2us
|
||||
#define CYCLES_400 (F_CPU / 400000) // 2.5us per bit
|
||||
|
||||
uint8_t *p, *end, pix, mask;
|
||||
uint32_t t, time0, time1, period, c, startTime, pinMask;
|
||||
|
||||
pinMask = _BV(pin);
|
||||
p = pixels;
|
||||
end = p + numBytes;
|
||||
pix = *p++;
|
||||
mask = 0x80;
|
||||
startTime = 0;
|
||||
|
||||
#ifdef NEO_KHZ400
|
||||
if(is800KHz) {
|
||||
#endif
|
||||
time0 = CYCLES_800_T0H;
|
||||
time1 = CYCLES_800_T1H;
|
||||
period = CYCLES_800;
|
||||
#ifdef NEO_KHZ400
|
||||
} else { // 400 KHz bitstream
|
||||
time0 = CYCLES_400_T0H;
|
||||
time1 = CYCLES_400_T1H;
|
||||
period = CYCLES_400;
|
||||
}
|
||||
#endif
|
||||
|
||||
for(t = time0;; t = time0) {
|
||||
if(pix & mask) t = time1; // Bit high duration
|
||||
while(((c = _getCycleCount()) - startTime) < period); // Wait for bit start
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high
|
||||
startTime = c; // Save start time
|
||||
while(((c = _getCycleCount()) - startTime) < t); // Wait high duration
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low
|
||||
if(!(mask >>= 1)) { // Next bit/byte
|
||||
if(p >= end) break;
|
||||
pix = *p++;
|
||||
mask = 0x80;
|
||||
}
|
||||
}
|
||||
while((_getCycleCount() - startTime) < period); // Wait for last bit
|
||||
}
|
||||
|
||||
#endif // ESP8266
|
||||
270
arduino-libs/arduino-cli/libraries/yfrobot/glcdfont.c
Normal file
270
arduino-libs/arduino-cli/libraries/yfrobot/glcdfont.c
Normal file
@@ -0,0 +1,270 @@
|
||||
#ifndef FONT5X7_H
|
||||
#define FONT5X7_H
|
||||
|
||||
#ifdef __AVR__
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#else
|
||||
#define PROGMEM
|
||||
#endif
|
||||
|
||||
// Standard ASCII 5x7 font
|
||||
|
||||
static const unsigned char font[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x3E, 0x5B, 0x4F, 0x5B, 0x3E,
|
||||
0x3E, 0x6B, 0x4F, 0x6B, 0x3E,
|
||||
0x1C, 0x3E, 0x7C, 0x3E, 0x1C,
|
||||
0x18, 0x3C, 0x7E, 0x3C, 0x18,
|
||||
0x1C, 0x57, 0x7D, 0x57, 0x1C,
|
||||
0x1C, 0x5E, 0x7F, 0x5E, 0x1C,
|
||||
0x00, 0x18, 0x3C, 0x18, 0x00,
|
||||
0xFF, 0xE7, 0xC3, 0xE7, 0xFF,
|
||||
0x00, 0x18, 0x24, 0x18, 0x00,
|
||||
0xFF, 0xE7, 0xDB, 0xE7, 0xFF,
|
||||
0x30, 0x48, 0x3A, 0x06, 0x0E,
|
||||
0x26, 0x29, 0x79, 0x29, 0x26,
|
||||
0x40, 0x7F, 0x05, 0x05, 0x07,
|
||||
0x40, 0x7F, 0x05, 0x25, 0x3F,
|
||||
0x5A, 0x3C, 0xE7, 0x3C, 0x5A,
|
||||
0x7F, 0x3E, 0x1C, 0x1C, 0x08,
|
||||
0x08, 0x1C, 0x1C, 0x3E, 0x7F,
|
||||
0x14, 0x22, 0x7F, 0x22, 0x14,
|
||||
0x5F, 0x5F, 0x00, 0x5F, 0x5F,
|
||||
0x06, 0x09, 0x7F, 0x01, 0x7F,
|
||||
0x00, 0x66, 0x89, 0x95, 0x6A,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60,
|
||||
0x94, 0xA2, 0xFF, 0xA2, 0x94,
|
||||
0x08, 0x04, 0x7E, 0x04, 0x08,
|
||||
0x10, 0x20, 0x7E, 0x20, 0x10,
|
||||
0x08, 0x08, 0x2A, 0x1C, 0x08,
|
||||
0x08, 0x1C, 0x2A, 0x08, 0x08,
|
||||
0x1E, 0x10, 0x10, 0x10, 0x10,
|
||||
0x0C, 0x1E, 0x0C, 0x1E, 0x0C,
|
||||
0x30, 0x38, 0x3E, 0x38, 0x30,
|
||||
0x06, 0x0E, 0x3E, 0x0E, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x5F, 0x00, 0x00,
|
||||
0x00, 0x07, 0x00, 0x07, 0x00,
|
||||
0x14, 0x7F, 0x14, 0x7F, 0x14,
|
||||
0x24, 0x2A, 0x7F, 0x2A, 0x12,
|
||||
0x23, 0x13, 0x08, 0x64, 0x62,
|
||||
0x36, 0x49, 0x56, 0x20, 0x50,
|
||||
0x00, 0x08, 0x07, 0x03, 0x00,
|
||||
0x00, 0x1C, 0x22, 0x41, 0x00,
|
||||
0x00, 0x41, 0x22, 0x1C, 0x00,
|
||||
0x2A, 0x1C, 0x7F, 0x1C, 0x2A,
|
||||
0x08, 0x08, 0x3E, 0x08, 0x08,
|
||||
0x00, 0x80, 0x70, 0x30, 0x00,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x00, 0x00, 0x60, 0x60, 0x00,
|
||||
0x20, 0x10, 0x08, 0x04, 0x02,
|
||||
0x3E, 0x51, 0x49, 0x45, 0x3E,
|
||||
0x00, 0x42, 0x7F, 0x40, 0x00,
|
||||
0x72, 0x49, 0x49, 0x49, 0x46,
|
||||
0x21, 0x41, 0x49, 0x4D, 0x33,
|
||||
0x18, 0x14, 0x12, 0x7F, 0x10,
|
||||
0x27, 0x45, 0x45, 0x45, 0x39,
|
||||
0x3C, 0x4A, 0x49, 0x49, 0x31,
|
||||
0x41, 0x21, 0x11, 0x09, 0x07,
|
||||
0x36, 0x49, 0x49, 0x49, 0x36,
|
||||
0x46, 0x49, 0x49, 0x29, 0x1E,
|
||||
0x00, 0x00, 0x14, 0x00, 0x00,
|
||||
0x00, 0x40, 0x34, 0x00, 0x00,
|
||||
0x00, 0x08, 0x14, 0x22, 0x41,
|
||||
0x14, 0x14, 0x14, 0x14, 0x14,
|
||||
0x00, 0x41, 0x22, 0x14, 0x08,
|
||||
0x02, 0x01, 0x59, 0x09, 0x06,
|
||||
0x3E, 0x41, 0x5D, 0x59, 0x4E,
|
||||
0x7C, 0x12, 0x11, 0x12, 0x7C,
|
||||
0x7F, 0x49, 0x49, 0x49, 0x36,
|
||||
0x3E, 0x41, 0x41, 0x41, 0x22,
|
||||
0x7F, 0x41, 0x41, 0x41, 0x3E,
|
||||
0x7F, 0x49, 0x49, 0x49, 0x41,
|
||||
0x7F, 0x09, 0x09, 0x09, 0x01,
|
||||
0x3E, 0x41, 0x41, 0x51, 0x73,
|
||||
0x7F, 0x08, 0x08, 0x08, 0x7F,
|
||||
0x00, 0x41, 0x7F, 0x41, 0x00,
|
||||
0x20, 0x40, 0x41, 0x3F, 0x01,
|
||||
0x7F, 0x08, 0x14, 0x22, 0x41,
|
||||
0x7F, 0x40, 0x40, 0x40, 0x40,
|
||||
0x7F, 0x02, 0x1C, 0x02, 0x7F,
|
||||
0x7F, 0x04, 0x08, 0x10, 0x7F,
|
||||
0x3E, 0x41, 0x41, 0x41, 0x3E,
|
||||
0x7F, 0x09, 0x09, 0x09, 0x06,
|
||||
0x3E, 0x41, 0x51, 0x21, 0x5E,
|
||||
0x7F, 0x09, 0x19, 0x29, 0x46,
|
||||
0x26, 0x49, 0x49, 0x49, 0x32,
|
||||
0x03, 0x01, 0x7F, 0x01, 0x03,
|
||||
0x3F, 0x40, 0x40, 0x40, 0x3F,
|
||||
0x1F, 0x20, 0x40, 0x20, 0x1F,
|
||||
0x3F, 0x40, 0x38, 0x40, 0x3F,
|
||||
0x63, 0x14, 0x08, 0x14, 0x63,
|
||||
0x03, 0x04, 0x78, 0x04, 0x03,
|
||||
0x61, 0x59, 0x49, 0x4D, 0x43,
|
||||
0x00, 0x7F, 0x41, 0x41, 0x41,
|
||||
0x02, 0x04, 0x08, 0x10, 0x20,
|
||||
0x00, 0x41, 0x41, 0x41, 0x7F,
|
||||
0x04, 0x02, 0x01, 0x02, 0x04,
|
||||
0x40, 0x40, 0x40, 0x40, 0x40,
|
||||
0x00, 0x03, 0x07, 0x08, 0x00,
|
||||
0x20, 0x54, 0x54, 0x78, 0x40,
|
||||
0x7F, 0x28, 0x44, 0x44, 0x38,
|
||||
0x38, 0x44, 0x44, 0x44, 0x28,
|
||||
0x38, 0x44, 0x44, 0x28, 0x7F,
|
||||
0x38, 0x54, 0x54, 0x54, 0x18,
|
||||
0x00, 0x08, 0x7E, 0x09, 0x02,
|
||||
0x18, 0xA4, 0xA4, 0x9C, 0x78,
|
||||
0x7F, 0x08, 0x04, 0x04, 0x78,
|
||||
0x00, 0x44, 0x7D, 0x40, 0x00,
|
||||
0x20, 0x40, 0x40, 0x3D, 0x00,
|
||||
0x7F, 0x10, 0x28, 0x44, 0x00,
|
||||
0x00, 0x41, 0x7F, 0x40, 0x00,
|
||||
0x7C, 0x04, 0x78, 0x04, 0x78,
|
||||
0x7C, 0x08, 0x04, 0x04, 0x78,
|
||||
0x38, 0x44, 0x44, 0x44, 0x38,
|
||||
0xFC, 0x18, 0x24, 0x24, 0x18,
|
||||
0x18, 0x24, 0x24, 0x18, 0xFC,
|
||||
0x7C, 0x08, 0x04, 0x04, 0x08,
|
||||
0x48, 0x54, 0x54, 0x54, 0x24,
|
||||
0x04, 0x04, 0x3F, 0x44, 0x24,
|
||||
0x3C, 0x40, 0x40, 0x20, 0x7C,
|
||||
0x1C, 0x20, 0x40, 0x20, 0x1C,
|
||||
0x3C, 0x40, 0x30, 0x40, 0x3C,
|
||||
0x44, 0x28, 0x10, 0x28, 0x44,
|
||||
0x4C, 0x90, 0x90, 0x90, 0x7C,
|
||||
0x44, 0x64, 0x54, 0x4C, 0x44,
|
||||
0x00, 0x08, 0x36, 0x41, 0x00,
|
||||
0x00, 0x00, 0x77, 0x00, 0x00,
|
||||
0x00, 0x41, 0x36, 0x08, 0x00,
|
||||
0x02, 0x01, 0x02, 0x04, 0x02,
|
||||
0x3C, 0x26, 0x23, 0x26, 0x3C,
|
||||
0x1E, 0xA1, 0xA1, 0x61, 0x12,
|
||||
0x3A, 0x40, 0x40, 0x20, 0x7A,
|
||||
0x38, 0x54, 0x54, 0x55, 0x59,
|
||||
0x21, 0x55, 0x55, 0x79, 0x41,
|
||||
0x21, 0x54, 0x54, 0x78, 0x41,
|
||||
0x21, 0x55, 0x54, 0x78, 0x40,
|
||||
0x20, 0x54, 0x55, 0x79, 0x40,
|
||||
0x0C, 0x1E, 0x52, 0x72, 0x12,
|
||||
0x39, 0x55, 0x55, 0x55, 0x59,
|
||||
0x39, 0x54, 0x54, 0x54, 0x59,
|
||||
0x39, 0x55, 0x54, 0x54, 0x58,
|
||||
0x00, 0x00, 0x45, 0x7C, 0x41,
|
||||
0x00, 0x02, 0x45, 0x7D, 0x42,
|
||||
0x00, 0x01, 0x45, 0x7C, 0x40,
|
||||
0xF0, 0x29, 0x24, 0x29, 0xF0,
|
||||
0xF0, 0x28, 0x25, 0x28, 0xF0,
|
||||
0x7C, 0x54, 0x55, 0x45, 0x00,
|
||||
0x20, 0x54, 0x54, 0x7C, 0x54,
|
||||
0x7C, 0x0A, 0x09, 0x7F, 0x49,
|
||||
0x32, 0x49, 0x49, 0x49, 0x32,
|
||||
0x32, 0x48, 0x48, 0x48, 0x32,
|
||||
0x32, 0x4A, 0x48, 0x48, 0x30,
|
||||
0x3A, 0x41, 0x41, 0x21, 0x7A,
|
||||
0x3A, 0x42, 0x40, 0x20, 0x78,
|
||||
0x00, 0x9D, 0xA0, 0xA0, 0x7D,
|
||||
0x39, 0x44, 0x44, 0x44, 0x39,
|
||||
0x3D, 0x40, 0x40, 0x40, 0x3D,
|
||||
0x3C, 0x24, 0xFF, 0x24, 0x24,
|
||||
0x48, 0x7E, 0x49, 0x43, 0x66,
|
||||
0x2B, 0x2F, 0xFC, 0x2F, 0x2B,
|
||||
0xFF, 0x09, 0x29, 0xF6, 0x20,
|
||||
0xC0, 0x88, 0x7E, 0x09, 0x03,
|
||||
0x20, 0x54, 0x54, 0x79, 0x41,
|
||||
0x00, 0x00, 0x44, 0x7D, 0x41,
|
||||
0x30, 0x48, 0x48, 0x4A, 0x32,
|
||||
0x38, 0x40, 0x40, 0x22, 0x7A,
|
||||
0x00, 0x7A, 0x0A, 0x0A, 0x72,
|
||||
0x7D, 0x0D, 0x19, 0x31, 0x7D,
|
||||
0x26, 0x29, 0x29, 0x2F, 0x28,
|
||||
0x26, 0x29, 0x29, 0x29, 0x26,
|
||||
0x30, 0x48, 0x4D, 0x40, 0x20,
|
||||
0x38, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x38,
|
||||
0x2F, 0x10, 0xC8, 0xAC, 0xBA,
|
||||
0x2F, 0x10, 0x28, 0x34, 0xFA,
|
||||
0x00, 0x00, 0x7B, 0x00, 0x00,
|
||||
0x08, 0x14, 0x2A, 0x14, 0x22,
|
||||
0x22, 0x14, 0x2A, 0x14, 0x08,
|
||||
0xAA, 0x00, 0x55, 0x00, 0xAA,
|
||||
0xAA, 0x55, 0xAA, 0x55, 0xAA,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00,
|
||||
0x10, 0x10, 0x10, 0xFF, 0x00,
|
||||
0x14, 0x14, 0x14, 0xFF, 0x00,
|
||||
0x10, 0x10, 0xFF, 0x00, 0xFF,
|
||||
0x10, 0x10, 0xF0, 0x10, 0xF0,
|
||||
0x14, 0x14, 0x14, 0xFC, 0x00,
|
||||
0x14, 0x14, 0xF7, 0x00, 0xFF,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x14, 0x14, 0xF4, 0x04, 0xFC,
|
||||
0x14, 0x14, 0x17, 0x10, 0x1F,
|
||||
0x10, 0x10, 0x1F, 0x10, 0x1F,
|
||||
0x14, 0x14, 0x14, 0x1F, 0x00,
|
||||
0x10, 0x10, 0x10, 0xF0, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x10,
|
||||
0x10, 0x10, 0x10, 0x1F, 0x10,
|
||||
0x10, 0x10, 0x10, 0xF0, 0x10,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0xFF, 0x10,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x14,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x1F, 0x10, 0x17,
|
||||
0x00, 0x00, 0xFC, 0x04, 0xF4,
|
||||
0x14, 0x14, 0x17, 0x10, 0x17,
|
||||
0x14, 0x14, 0xF4, 0x04, 0xF4,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xF7,
|
||||
0x14, 0x14, 0x14, 0x14, 0x14,
|
||||
0x14, 0x14, 0xF7, 0x00, 0xF7,
|
||||
0x14, 0x14, 0x14, 0x17, 0x14,
|
||||
0x10, 0x10, 0x1F, 0x10, 0x1F,
|
||||
0x14, 0x14, 0x14, 0xF4, 0x14,
|
||||
0x10, 0x10, 0xF0, 0x10, 0xF0,
|
||||
0x00, 0x00, 0x1F, 0x10, 0x1F,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x14,
|
||||
0x00, 0x00, 0x00, 0xFC, 0x14,
|
||||
0x00, 0x00, 0xF0, 0x10, 0xF0,
|
||||
0x10, 0x10, 0xFF, 0x10, 0xFF,
|
||||
0x14, 0x14, 0x14, 0xFF, 0x14,
|
||||
0x10, 0x10, 0x10, 0x1F, 0x00,
|
||||
0x00, 0x00, 0x00, 0xF0, 0x10,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
|
||||
0x38, 0x44, 0x44, 0x38, 0x44,
|
||||
0x7C, 0x2A, 0x2A, 0x3E, 0x14,
|
||||
0x7E, 0x02, 0x02, 0x06, 0x06,
|
||||
0x02, 0x7E, 0x02, 0x7E, 0x02,
|
||||
0x63, 0x55, 0x49, 0x41, 0x63,
|
||||
0x38, 0x44, 0x44, 0x3C, 0x04,
|
||||
0x40, 0x7E, 0x20, 0x1E, 0x20,
|
||||
0x06, 0x02, 0x7E, 0x02, 0x02,
|
||||
0x99, 0xA5, 0xE7, 0xA5, 0x99,
|
||||
0x1C, 0x2A, 0x49, 0x2A, 0x1C,
|
||||
0x4C, 0x72, 0x01, 0x72, 0x4C,
|
||||
0x30, 0x4A, 0x4D, 0x4D, 0x30,
|
||||
0x30, 0x48, 0x78, 0x48, 0x30,
|
||||
0xBC, 0x62, 0x5A, 0x46, 0x3D,
|
||||
0x3E, 0x49, 0x49, 0x49, 0x00,
|
||||
0x7E, 0x01, 0x01, 0x01, 0x7E,
|
||||
0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
|
||||
0x44, 0x44, 0x5F, 0x44, 0x44,
|
||||
0x40, 0x51, 0x4A, 0x44, 0x40,
|
||||
0x40, 0x44, 0x4A, 0x51, 0x40,
|
||||
0x00, 0x00, 0xFF, 0x01, 0x03,
|
||||
0xE0, 0x80, 0xFF, 0x00, 0x00,
|
||||
0x08, 0x08, 0x6B, 0x6B, 0x08,
|
||||
0x36, 0x12, 0x36, 0x24, 0x36,
|
||||
0x06, 0x0F, 0x09, 0x0F, 0x06,
|
||||
0x00, 0x00, 0x18, 0x18, 0x00,
|
||||
0x00, 0x00, 0x10, 0x10, 0x00,
|
||||
0x30, 0x40, 0xFF, 0x01, 0x01,
|
||||
0x00, 0x1F, 0x01, 0x01, 0x1E,
|
||||
0x00, 0x19, 0x1D, 0x17, 0x12,
|
||||
0x00, 0x3C, 0x3C, 0x3C, 0x3C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
#endif // FONT5X7_H
|
||||
Reference in New Issue
Block a user