⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lcd-color.cpp

📁 LCD using AVR controller
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*	LCD-color.cpp
*
*	Class for controlling Spark Fun's 130x130 color LCD.
*	The LCD requires 9-bit serial communication, which this
*	code does via the SPI feature.
*
*	Revisions:
*		07-13-06	included in LCDSample project
*		07-10-06	version 1 in master library
*
*	Written by Cathy Saxton
*	robotics@idleloop.com
*/

#include <stdio.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "Util.h"
#include "LCD-color.h"
#include "Fonts.h"
#include "Timer.h"

/* set up defines for using SPI registers */
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) \
	|| defined(__AVR_ATmega32__) || defined(__AVR_ATmega128__)
#define regSPCR	SPCR
#define regSPSR	SPSR
#define regSPDR	SPDR
#define bitSPE	SPE
#define bitSPIF	SPIF
#elif (defined(__AVR_ATmega644__))
#define regSPCR	SPCR0
#define regSPSR	SPSR0
#define regSPDR	SPDR0
#define bitSPE	SPE0
#define bitSPIF	SPIF0
#else
#warning "unrecognized microcontroller (add/verify it)"
#endif

extern TIMER g_timer;

/* horiz: 0-129 (inclusive); vert: 2-131 */
/* Hungarian naming: xl and yl are x and y coordinates on LCD
   (handling offset for visible pixels) */
static const uint xlMin = 0;
static const uint ylMin = 2;
static const uint xlMax = xlMin + dxLCDScreen;
static const uint ylMax = ylMin + dyLCDScreen;
static const uint xlMost = xlMin + dxLCDScreen - 1;
static const uint ylMost = ylMin + dyLCDScreen - 1;

static const uint dxLeading = 1;	// spacing between chars
static const uint dyLeading = 1;	// spacing between lines of text
static const uint dxMargin = 3;		// margin to leave at left when drawing text
static const uint dyMargin = 2;		// margin to leave at top when drawing text


enum	// LCD Communication Type
{
	lctCmd = 0,		// command
	lctData = 1,	// data
};

/* Epson S1D15G10 Command Set */
#define DISON       0xaf
#define DISOFF      0xae
#define DISNOR      0xa6
#define DISINV      0xa7
#define COMSCN      0xbb
#define DISCTL      0xca
#define SLPIN       0x95
#define SLPOUT      0x94
#define PASET       0x75
#define CASET       0x15
#define DATCTL      0xbc
#define RGBSET8     0xce
#define RAMWR       0x5c
#define RAMRD       0x5d
#define PTLIN       0xa8
#define PTLOUT      0xa9
#define RMWIN       0xe0
#define RMWOUT      0xee
#define ASCSET      0xaa
#define SCSTART     0xab
#define OSCON       0xd1
#define OSCOFF      0xd2
#define PWRCTR      0x20
#define VOLCTR      0x81
#define VOLUP       0xd6
#define VOLDOWN     0xd7
#define TMPGRD      0x82
#define EPCTIN      0xcd
#define EPCOUT      0xcc
#define EPMWR       0xfc
#define EPMRD       0xfd
#define EPSRRD1     0x7c
#define EPSRRD2     0x7d
#define NOP         0x25


bool LCD::s_fInit = fFalse;
OUT *LCD::s_poutE;
OUT *LCD::s_poutSCK;
OUT *LCD::s_poutMOSI;
OUT *LCD::s_poutReset;

LCD::LCD(OUT *poutE, OUT *poutMOSI, OUT *poutSCK, OUT *poutReset,
		 const FONT *pfont, uchar clrBack, uchar clrFore)
		 : m_pfont(pfont),
		   m_clrBack(clrBack),
		   m_clrFore(clrFore),
		   m_x(0),
		   m_y(0)
{
	if (!s_fInit)
	{
		s_poutE = poutE;
		s_poutSCK = poutSCK;
		s_poutMOSI = poutMOSI;
		s_poutReset = poutReset;
		poutE->SetHigh();	// signal is !ChipSelect; this disables it
		poutSCK->SetLow();	// get ready for first send
		Init();
	}

	SetPos(0, 1);	// start at beginning of line 1
}

void LCD::Init() const
{
	s_fInit = fTrue;

	/* SPI setup:
	   SPI Control Register (SPCR): (0101 0001)
			bit 7	SPIE (interrupt enable)	0 = not enabled
			bit 6	SPE (enable)		1 = enable
			bit 5	DORD (data order)	0 = MSB transmitted first
			bit 4	MSTR (master sel.)	1 = master
			bit 3	CPOL (clk polarity)	0 = idle low (leading edge is rising)
			bit 2	CPHA (clock phase)	0 = sample data on leading edge of pulse
			bit 1-0	SPR1/0 (clock rate)	00 = fOSC/4
	   But, we need to disable for starters... every command needs 9 bits,
	   so we'll send one manually, the use SPI for the next 8.
	*/
	regSPCR = 0x10;	// 0001 0000


	/* comms with LCD: longest write requirement is 90 ns
	   8 MHz uC executes one instruction every 125 ns */

	/* give LCD a little time to react to power on */
	g_timer.WaitMs(20);

	/* send reset */
	s_poutReset->SetLow();
	/* reset pulse wants to be low for 350 ns (min) */
	asm("nop");
	asm("nop");
	asm("nop");
#ifdef CLOCK_16M
	asm("nop");
	asm("nop");
	asm("nop");
#endif
	s_poutReset->SetHigh();
	g_timer.WaitMs(2);	// wait for reset to complete

	WriteCommand(lctCmd, DISCTL);	// Display Control
	WriteCommand(lctData, 0x00);	// default
	WriteCommand(lctData, 0x20);	// (32 + 1) * 4 = 132 lines (of which 130 are visible)
	WriteCommand(lctData, 0x0a);	// default

	WriteCommand(lctCmd, COMSCN);	// Common Scan
	WriteCommand(lctData, 0x01);	// COM1-80: 1->80; COM81-160: 160<-81 (otherwise bottom of screen is upside down)

	WriteCommand(lctCmd, OSCON);	// Oscillation On
	WriteCommand(lctCmd, SLPOUT);	// Sleep Out (exit sleep mode)

	WriteCommand(lctCmd, VOLCTR);	// Electronic Volume Control (brightness/contrast)
	WriteCommand(lctData, 28);
	WriteCommand(lctData, 3);

	WriteCommand(lctCmd, TMPGRD);
	WriteCommand(lctData, 0);		// default

	WriteCommand(lctCmd, PWRCTR);	// Power Control Set
	/* 0x0b = ref V / V reg + primary booster
	   0x0f = all on (0x0b + secondary booster)
	   (0x03, 0x07 don't work)
	   */
//	WriteCommand(lctData, 0x0b);
	WriteCommand(lctData, 0x0f);

	WriteCommand(lctCmd, DISINV);	// Inverse Display
	WriteCommand(lctCmd, PTLOUT);	// Partial Out (no partial display)
#if 0	// unused feature
	WriteCommand(lctCmd, ASCSET);	// Area Scroll Set
	WriteCommand(lctCmd, SCSTART);	// Scroll Start Address Set
#endif

	WriteCommand(lctCmd, DATCTL);	// Data Control
	WriteCommand(lctData, 0x00);	// normal orientation; scan across cols, then rows
	WriteCommand(lctData, 0x00);	// RGB arrangement (RGB all rows/cols)
//	WriteCommand(lctData, 0x04);	// RGB arrangement (RGB row 1, BGR row 2)
	WriteCommand(lctData, 0x01);	// 8-color display
//	WriteCommand(lctData, 0x02);	// 16-color display

	/* if 256-color mode, bytes represent RRRGGGBB; the following
	   maps to 4-bit color for each value in range (0-7 R/G, 0-3 B) */
	WriteCommand(lctCmd, RGBSET8);	// 256-color position set
	WriteCommand(lctData, 0x00);	// 000 RED
	WriteCommand(lctData, 0x02);	// 001  
	WriteCommand(lctData, 0x04);	// 010
	WriteCommand(lctData, 0x06);	// 011
	WriteCommand(lctData, 0x08);	// 100
	WriteCommand(lctData, 0x0a);	// 101
	WriteCommand(lctData, 0x0c);	// 110
	WriteCommand(lctData, 0x0f);	// 111
	WriteCommand(lctData, 0x00);	// 000 GREEN
	WriteCommand(lctData, 0x02);	// 001  
	WriteCommand(lctData, 0x04);	// 010
	WriteCommand(lctData, 0x06);	// 011
	WriteCommand(lctData, 0x08);	// 100
	WriteCommand(lctData, 0x0a);	// 101
	WriteCommand(lctData, 0x0c);	// 110
	WriteCommand(lctData, 0x0f);	// 111
	WriteCommand(lctData, 0x00);	//  00 BLUE
	WriteCommand(lctData, 0x06);	//  01
	WriteCommand(lctData, 0x09);	//  10
	WriteCommand(lctData, 0x0f);	//  11

	/* clear screen */
	FillRect(0, 0, dxLCDScreen, dyLCDScreen, m_clrBack);

	g_timer.WaitMs(100);
	WriteCommand(lctCmd, DISON);	// Display On
}

/* prints given string on the specified line; unused portion of
   line will be padded with background color by default; use a
   1-based value for a specific line, or 0 for the current line;
   line is updated after outputting text */
void LCD::Print(const char *psz, uchar line, bool fPad)
{
	const char *pch;
	uchar dy;

	if (m_pfont == NULL)
		return;

	SetPos(0, line);
	pch = psz;
	while (*pch != 0)
		WriteCh(*pch++);
	dy = m_pfont->DyFont() + dyLeading;

	if (fPad && m_clrBack != clrTransparent)	// blank rest of line
	{
		FillRect(0, m_y, dxMargin, dy, m_clrBack);
		FillRect(m_x, m_y, dxLCDScreen - m_x, dy, m_clrBack);
	}

	/* update default output position */
	m_y += dy;
	m_x = dxMargin;
}

/* sets current text output location to the specified position
   (ich, 0-based) on the specified line; note that for proportional
   fonts, horizontal position is an approximation (based on the
   width of a space); using line=0 will leave line unchanged */
void LCD::SetPos(uchar ich, uchar line)
{
	uchar dx;
	uchar f;

	if (m_pfont == NULL)
		return;

	if (line != 0)
		m_y = dyMargin + (m_pfont->DyFont() + dyLeading) * (line - 1);

	m_x = dxMargin;
	if (ich > 0)
	{
		/* get width of space */
		m_pfont->PbForCh(' ', &f, &dx);
		m_x += ich * (dx + dxLeading);
	}
}

/* writes a character at the current location, updates current location */
void LCD::WriteCh(char ch)
{
	uchar dx, dy;
	uint cpx;
	uchar f;
	uchar grf;
	const uchar *pb;

	if (m_pfont == NULL)
		return;

	dy = m_pfont->DyFont();
	pb = m_pfont->PbForCh(ch, &f, &dx);

	cpx = CpxSetAndValidateLCDRect(m_x, m_y, dx, dy);
	if (cpx != (uint)dx * dy)		// not enough room
		return;

	memcpy_P(&grf, pb, sizeof(uchar));

	if (m_clrBack == clrTransparent)
	{
		uchar x, y;

		/* just set desired bits manually */
		for (y = m_y; y < m_y + dy; ++y)
		{
			for (x = m_x; x < m_x + dx; ++x)
			{
				if (grf & f)
					ColorPixel(x, y, m_clrFore);
				if ((f >>= 1) == 0)
				{
					memcpy_P(&grf, ++pb, sizeof(uchar));
					f = 0x80;
				}
			}
		}
		/* update current position */
		m_x += dx + dxLeading;
	}
	else
	{
		/* area set above; just fill in the pixels */
		while (cpx-- > 0)
		{
			WriteCommand(lctData, (grf & f) ? m_clrFore : m_clrBack);
			if ((f >>= 1) == 0)
			{
				memcpy_P(&grf, ++pb, sizeof(uchar));
				f = 0x80;
			}
		}
		/* fill in background for leading below text */
		FillRect(m_x, m_y + dy, dx + dxLeading, dyLeading, m_clrBack);

		/* update current position */
		m_x += dx;
		/* fill in background for leading after character */
		FillRect(m_x, m_y, dxLeading, dy, m_clrBack);
		m_x += dxLeading;
	}
}

/* set the color of given pixel; note that pixels off screen will be ignored */
void LCD::ColorPixel(uchar x, uchar y, uchar clr) const

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -