?? lcd-color.cpp
字號:
{
/* note: this could call FillRect to save some code space, but
this is a bit faster (less error-checking needed), and this
function is called a lot... */
if (x >= dxLCDScreen || y >= dyLCDScreen) // completely off-screen
return;
/* convert to LCD coordinates (so the variables really should
be xl/yl from here down...) */
x += xlMin;
y += ylMin;
WriteCommand(lctCmd, PASET); // Page Address Set
WriteCommand(lctData, y);
WriteCommand(lctData, y);
WriteCommand(lctCmd, CASET); // Column Address Set
WriteCommand(lctData, x);
WriteCommand(lctData, x);
WriteCommand(lctCmd, RAMWR); // Memory Write
WriteCommand(lctData, clr);
}
/* draw a solid/filled rectangle with its upper left corner at (x, y),
with the given width, height, and color */
void LCD::FillRect(uchar x, uchar y, uchar dx, uchar dy, uchar clr) const
{
uint cpx;
cpx = CpxSetAndValidateLCDRect(x, y, dx, dy);
while (cpx-- > 0)
WriteCommand(lctData, clr);
}
/* outline a rectangle with its upper left corner at (x, y),
with the given width, height, and color */
void LCD::FrameRect(uchar x, uchar y, uchar dx, uchar dy, uchar clr) const
{
FillRect(x, y, dx, 1, clr); // top
FillRect(x, y + dy -1, dx, 1, clr); // bottom
FillRect(x, y, 1, dy, clr); // left
FillRect(x + dx - 1, y, 1, dy, clr);// right
}
/* helper for DrawLine */
inline void Swap(uchar *px, uchar *py)
{
uchar t;
t = *px; *px = *py; *py = t;
}
/* draw a line from (x1, y1) to (x2, y2) */
void LCD::DrawLine(uchar x1, uchar y1, uchar x2, uchar y2, uchar clr) const
{
uchar dx, dy;
char dyStep;
bool fMirror;
int calc;
/* handle simple horizontal / vertical lines */
if (x1 == x2)
{
if (y1 > y2) // swap values
Swap(&y1, &y2);
FillRect(x1, y1, 1, y2 - y1, clr);
return;
}
if (y1 == y2)
{
if (x1 > x2) // swap values
Swap(&x1, &x2);
FillRect(x1, y1, x2 - x1, 1, clr);
return;
}
/* set up parameters */
dx = Abs((int)x2 - (int)x1);
dy = Abs((int)y2 - (int)y1);
/* make sure we travel along longer side; if necessary,
we'll flip X and Y (here and below when drawing),
effectively mirroring along the line y=x */
if ((fMirror = dy > dx) != fFalse)
{
/* swap X-Y */
Swap(&x1, &y1);
Swap(&x2, &y2);
Swap(&dx, &dy);
}
/* start at the leftmost point */
if (x1 > x2)
{
/* swap points */
Swap(&x1, &x2);
Swap(&y1, &y2);
}
/* rising or falling? */
dyStep = y1 < y2 ? 1 : -1;
/*
normalized system: line at (0,0) positive slope to (r, s) [geometry coordinates]
y = mx + b m = s / r, b = 0 => ry = sx
for each point x along line, y will stay the same as prev or change to y + 1
ry = sx or r (y + 1) = sx
choose left-side value that is closest to sx; change y if
r (y + 1) - sx < sx - ry
which simplifies to
r - 2 (sx - ry) < 0
the inequality will hold if we divide by two (accounting for integer math),
so we can use:
r/2 - sx + ry < 0
at start, x = y = 0, left side is just r/2
each iteration, x increases, which subtracts another s (from right side)
when y increases, that adds another r (to right side)
*/
/* draw the line */
calc = dx >> 1;
while (x1 <= x2)
{
if (fMirror)
ColorPixel(y1, x1, clr);
else
ColorPixel(x1, y1, clr);
/* move to next x value */
++x1;
calc -= dy;
/* see if should change y value */
if (calc < 0)
{
y1 += dyStep;
calc += dx;
}
}
}
/* calculates 1/8 circle and reflects/rotates to draw full circle */
void LCD::FrameCircle(uchar xCenter, uchar yCenter, uchar r, uchar clr) const
{
uchar x, y;
int calc;
/* we'll draw pixels starting at (r, 0) and going counter-clockwise
(viewed in geometric space, not screen coordinates), rotating
and reflecting to fill in 8 sections at once, so we're done
when x == y (1/8 of circle calculated).
as we traverse that arc, we'll always move either up or up-left,
figure out which one is closer to the correct location;
change x if:
r^2 - left pixel x^2+y^2 < right pixel x^2+y^2 - r^2
r^2 - ((x - 1)^2 + y^2) < x^2 + y^2 - r^2
r2 - (x2 - 2*x + 1 + y2) < x2 + y2 - r2
r2 - x2 - y2 + 2x - 1 < x2 + y2 - r2
2r2 - 2x2 - 2y2 + 2x < 1
r2 - x2 - y2 + x < 1/2
(only int < 1/2 is 0 or negative)
r2 - x2 - y2 + x <= 0
at beginning, x = r, y = 0, so left side is just x
when increment y, y^2 term increases by 2y-1 (so term decreases)
when decrement x, x^2 term decreases by 2x+1 (so term increases)
*/
x = r;
y = 0;
calc = x;
while (x >= y)
{
/* set pixel at current locations */
/* (negative values will become large pos numbers and get rejected) */
ColorPixel(xCenter + x, yCenter + y, clr);
ColorPixel(xCenter + x, yCenter - y, clr);
ColorPixel(xCenter - x, yCenter + y, clr);
ColorPixel(xCenter - x, yCenter - y, clr);
ColorPixel(xCenter + y, yCenter + x, clr);
ColorPixel(xCenter + y, yCenter - x, clr);
ColorPixel(xCenter - y, yCenter + x, clr);
ColorPixel(xCenter - y, yCenter - x, clr);
/* should next pixel be up or up-left? */
++y; // move up
calc -= 2 * y - 1;
if (calc <= 0) // move left?
{
--x;
calc += 2 * x + 1;
}
}
}
/* calculates 1/8 circle and reflects/rotates to draw full circle;
see FrameCircle for calc explanation */
void LCD::FillCircle(uchar xCenter, uchar yCenter, uchar r, uchar clr) const
{
uchar x, y;
int calc;
uchar xT, d;
x = r;
y = 0;
calc = x;
while (x >= y)
{
/* if circle extends off left side, need to handle it here (no
negatives, so those values become large pos values and get
rejected by FillRect) */
if (x <= xCenter)
{
xT = xCenter - x;
d = 2 * x;
}
else
{
xT = 0;
/* 2x - (x - xCenter) = x + xCenter */
d = x + xCenter;
}
FillRect(xT, yCenter + y, d, 1, clr);
FillRect(xT, yCenter - y, d, 1, clr);
if (y <= xCenter)
{
xT = xCenter - y;
d = 2 * y;
}
else
{
xT = 0;
/* 2y - (y - xCenter) = y + xCenter */
d = y + xCenter;
}
FillRect(xT, yCenter + x, d, 1, clr);
FillRect(xT, yCenter - x, d, 1, clr);
/* should next pixel be up or up-left? */
++y; // move up
calc -= 2 * y - 1;
if (calc <= 0) // move left?
{
--x;
calc += 2 * x + 1;
}
}
}
/* draw the specified bitmap (located in flash memory) at the given
coordinates (upper left corner); the first two bytes of the memory
specify the width and height, with remaining bytes as 8-bit color
values; will not draw anything if not enough room for full image */
void LCD::ShowBitmap(const uchar *pab, uchar x, uchar y) const
{
uchar dz[2], clr;
uint cpx;
memcpy_P(dz, pab, 2 * sizeof(uchar));
pab += 2;
cpx = CpxSetAndValidateLCDRect(x, y, dz[0], dz[1]);
if (cpx != (uint)dz[0] * dz[1])
return;
while (cpx-- > 0)
{
memcpy_P(&clr, pab++, sizeof(uchar));
WriteCommand(lctData, clr);
}
}
/*
* LCD setup
*/
/* sets "volume" for the LCD, which is essentially a brightness
level for the LED backlight;
ratio: 0-7, "resistance ratio of built-in voltage regulating resistor"
this is a coarse setting
volume: 0-63, "electronic volume value"
this will fine-tune the brightness
technique -- find a ratio value that works well, then tune volume */
void LCD::SetVolume(uchar ratio, uchar volume) const
{
WriteCommand(lctCmd, VOLCTR); // Electronic Volume Control (LCD brightness)
WriteCommand(lctData, volume & 0x3f);
WriteCommand(lctData, ratio & 0x03);
}
void LCD::IncVolumn() const
{
WriteCommand(lctCmd, VOLUP); // Increment Electronic Control
}
void LCD::DecVolumn() const
{
WriteCommand(lctCmd, VOLDOWN); // Decrement Electronic Control
}
/*
* helper functions
*/
/* send an instruction to the LCD */
void LCD::WriteCommand(uchar lct, uchar ch) const
{
/* enable chip */
s_poutE->SetLow();
/* send first bit manually */
/* set data bit for command or data */
if (lct == lctCmd)
s_poutMOSI->SetLow();
else
s_poutMOSI->SetHigh();
/* pulse clock */
s_poutSCK->SetHigh();
asm("nop"); // just to be sure...
s_poutSCK->SetLow();
/* enable SPI for remaining 8 bits */
SetBit(regSPCR, bitSPE);
regSPDR = ch;
/* wait for transmission to complete */
while (bit_is_clear(regSPSR, bitSPIF))
;
ClearBit(regSPCR, bitSPE); // disable it so we can send manually...
/* signal done with this transmit */
s_poutE->SetHigh();
}
/* ensures that rectangle is fully on screen and sets LCD for drawing there;
returns number of pixels available to fill */
uint LCD::CpxSetAndValidateLCDRect(uchar x, uchar y, uchar dx, uchar dy) const
{
uchar xlFirst, ylFirst, xlLast, ylLast; // LCD coordinates
/* check upper left corner */
/* (x and y aren't too low since unsigned can't be < 0!) */
if (x >= dxLCDScreen || y >= dyLCDScreen) // completely off-screen
return 0;
/* check lower right corner */
if (x + dx > dxLCDScreen)
dx = dxLCDScreen - x;
if (y + dy > dyLCDScreen)
dy = dyLCDScreen - y;
/* convert to LCD coordinates */
xlLast = (xlFirst = xlMin + x) + dx - 1;
ylLast = (ylFirst = ylMin + y) + dy - 1;
/* note: for PASET/CASET, docs say that start must be < end,
but <= appears to be OK; end is a "last" not "lim" value */
WriteCommand(lctCmd, PASET); // Page Address Set
WriteCommand(lctData, ylFirst); // start page (line)
WriteCommand(lctData, ylLast); // end page
WriteCommand(lctCmd, CASET); // Column Address Set
WriteCommand(lctData, xlFirst); // start address
WriteCommand(lctData, xlLast); // end address
WriteCommand(lctCmd, RAMWR); // Memory Write
return (uint)dx * dy;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -