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

📄 display.c

📁 这项工程将让您把自己的MP3播放器平台
💻 C
📖 第 1 页 / 共 2 页
字号:
//++
//display.c - MP3 LCD/VFD Display functions
//
// Copyright (C) 2005 by Spare Time Gizmos.  All rights reserved.
//
// This file is part of the Spare Time Gizmos' MP3 Player firmware.
//
// This firmware 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 2 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, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA  02111-1307  USA.
//
//DESCRIPTION:
//   This module provides a simple interface to a generic display module, which
// may be either a Hitachi 44780 style generic text LCD, or a parallel ASCII
// vacuum flourescent display.  These displays maintain a cursor and current
// cursor location, but in general they (especially the LCDs) do not implement
// any terminal emulations, not even basic things like carriage return, line
// feed, tab, etc.  Thus you may call DisplayChar() several times in a row and
// assume that the characters are displayed right to left, but if you want to
// move to the next line you need to use one of the cursor position functions
// to move the cursor there.  A line feed or CRLF won't do it.
//
//   Needless to say, the LCD doesn't implement scrolling either.  Your only
// option is to erase the entire display and repaint.  Also note that this
// code does not enforce any display size limits, so it's up to the application
// code not to exceed the display width and height.  The DISPLAY_WIDTH and
// DISPLAY_HEIGHT pre-processor constants are just the thing you need for this.
//
//REVISION HISTORY:
// dd-mmm-yy    who     description
// 18-May-05	RLA	New file.
// 13-Jul-05	RLA	Add a small delay to WaitBusy() for VFDs...
// 20-Jul-05	RLA	Add the copyright sign to the LCD's CGRAM ...
// 12-Oct-05	RLA	For VFDs, home cursor THEN clear screen
// 15-Oct-05	RLA	Remove DISPLAY_TYPE and add LCD/VFD conditionals
// 20-Oct-05	RLA	Fix a timing bug in the VFD DisplayWrite()
//			
//--

// Include files...
#include <stdio.h>		// needed so DBGOUT(()) can find printf!
#include <stdarg.h>		// va_alist(), va_end(), etc...
#include "standard.h"		// standard types - BYTE, WORD, BOOL, etc
#include "reg66x.h"		// declarations for Philips 89C66x processors
#include "player.h"		// project wide (hardware configuration) declarations
#include "debug.h"		// debugging stuff and ResetWDT()
#include "post.h"		// POST codes for Fail()
#include "timer.h"		// DELAYUS() macro and DelayMS() function
#include "display.h"		// declarations for this module

//   This array of eight bytes defines a custom character (a copyright symbol)
// for the Hitachi 44780 LCD controller.  The VFD character set already contains
// a copyright sign, so this is unnecessary there...
#ifdef LCD
PRIVATE CODE const BYTE m_abCopyrightSymbol[8] = {
  0x0E, 0x11, 0x17, 0x19, 0x17, 0x11, 0x0E, 0x00
};
#endif

// Local storage...
PRIVATE XDATA char m_acDisplayBuffer[DISPLAY_WIDTH+1];


//++
//   This routine will write one byte to an LCD display.  For an LCD display,
// bRS selects the control register (bRS=1) or the data register (bRS=0).
// bData gives the actual 8 bit data to be sent to the display.  Note that
// this routine does NOT check the busy flag before sending the data
// - that's the responsibility of the caller!
//
//   VFD displays are similar, however in this case there is only a data port
// and no register select flag is used.  Also, VFD displays use the opposite
// polarity for the ENABLE signal (active low for VFDs rather than active high
// for LCDs)...
//--
#ifdef LCD
PRIVATE void DisplayWrite (BYTE bRS, BYTE bData)
{
  DISPLAY_RW = 0;  DISPLAY_RS = (bRS != 0);  DISPLAY_DATA = bData;
  DISPLAY_ENABLE = 1;  DELAYUS(2);  DISPLAY_ENABLE = 0;
}
#endif
#ifdef VFD
PRIVATE void DisplayWrite (BYTE bData)
{
  INT_OFF;
  DISPLAY_RW = 1;  DISPLAY_ENABLE = 0;  DISPLAY_DATA = bData;
  DISPLAY_RW = 0;  DISPLAY_RW = 1;
  DISPLAY_ENABLE = 1;  DISPLAY_RW = 0;
  INT_ON;
  //DISPLAY_RW = 0;  DISPLAY_DATA = bData;
  //DISPLAY_ENABLE = 0;  DELAYUS(2);  DISPLAY_ENABLE = 1;
}
#endif


//++
//   This routine will monitor the display's BUSY flag and (contrary to
// what the name might lead you to believe :-) it will wait for the display
// to NOT be busy.
//
//   LCD displays implement the BUSY flag as the MSB of the status register,
// which must be explicitly read by setting the RW bit, clearing the register
// select, and then enabling the display.
//
//   VFD displays have a completely separate BUSY flag which is connected to
// it's own port pin.  We can simply test this pin without any other effort.
//
//   Note that both versions implement a timeout which will eventually POST
// if the BUSY flag never clears...
//--
PRIVATE void WaitBusy (void)
{
  WORD wTimeout = 0;
#ifdef LCD
  //  Set the RW bit and clear RS to read the status register, then set the data
  // port to all 1s so that it can be used as an input.
  DISPLAY_RW = 1;  DISPLAY_RS = 0;  DISPLAY_DATA = 0xFF;  DISPLAY_ENABLE = 1;
  while (TRUE) {
    DELAYUS(1);
    if ((DISPLAY_DATA & 0x80) == 0) break;
    if (++wTimeout == 0) POST(PC_DISPLAY, FALSE);
  }
  // Disable the display and return...
  DISPLAY_ENABLE = 0;
#endif
#ifdef VFD
  // VFDs have an explicit status line that makes things much easier...
  while (TRUE) {
    //   I had a lot of trouble with glitches on the DISPLAY_BUSY signal,
    // especially with a faster 89C66x clock (the faster CPU clock doesn't
    // cause the glitches - it just makes it easier for the software to find
    // them!)  The only fix is to sample DISPLAY_BUSY and, if we find it
    // cleared, wait a few microseconds and then sample again to be sure we
    // get the same result...
    if (!DISPLAY_BUSY) {
      DELAYUS(2);  if (!DISPLAY_BUSY) return;
    }
    if (++wTimeout == 0) POST(PC_DISPLAY, FALSE);
  }    
#endif
}


//++
//   This routine will intitialize the display and clear the screen.  Normally
// it's called only once, during startup, but it could be called again if
// necessary.  Note that it contains several programmed delays to wait for the
// LCD to initialize, so it isn't especially fast!
//
//   Although we never explicitly read back from the display, we do explicitly
// check the display's BUSY flag for both LCD and VFD displays.  If no display
// is connected (or if it's broken somehow) then we will eventually time out and
// POST() via the WaitBusy() routine...
//--
PUBLIC void InitializeDisplay (void)
{
#ifdef LCD
  BYTE i;
  //   LCD displays are notorious for being difficult to initialize, particularly
  // when the power supply startup is noisy or slow and glitches the display's
  // microprocessor.  The solution is to follow the data book initialization
  // procedure explicity, which is exactly what we do here (in this case it's the
  // Optrex data book we're following)...
  //
  //   Also note that LCDs have no hardware reset, so the DISPLAY_RESET signal
  // does nothing.  And finally, for LCD dispays the ENABLE signal is active
  // high, and so we initialize it to low...
  DISPLAY_ENABLE = 0;  DelayMS(15);
  //   At this point it's not safe to depend on the display's BUSY flag, and
  // we must make do with programmed delays instead...
  DisplayWrite(CONTROL_REGISTER, LCD_FUNCTION_SET|LCD_8BIT);		     	DelayMS(5);
  DisplayWrite(CONTROL_REGISTER, LCD_FUNCTION_SET|LCD_8BIT);		     	DELAYUS(160);
  // Now we can start using the BUSY flag...
  DisplayWrite(CONTROL_REGISTER, LCD_FUNCTION_SET|LCD_8BIT);		     	WaitBusy();
#if (DISPLAY_HEIGHT == 1)
  DisplayWrite(CONTROL_REGISTER, LCD_FUNCTION_SET|LCD_8BIT);		   	WaitBusy();
#else
  DisplayWrite(CONTROL_REGISTER, LCD_FUNCTION_SET|LCD_8BIT|LCD_TWO_LINES);   	WaitBusy();
#endif
  DisplayWrite(CONTROL_REGISTER, LCD_DISPLAY_CONTROL|LCD_DISPLAY_OFF);	     	WaitBusy();
  DisplayWrite(CONTROL_REGISTER, LCD_CLEAR_DISPLAY);			     	WaitBusy();
  DisplayWrite(CONTROL_REGISTER, LCD_CURSOR_MODE_SET);			     	WaitBusy();
  DisplayWrite(CONTROL_REGISTER, LCD_ENTRY_MODE_SET|LCD_INCREMENT_CURSOR);	WaitBusy();
  DisplayWrite(CONTROL_REGISTER, LCD_DISPLAY_CONTROL|LCD_DISPLAY_ON);		WaitBusy();
  // Load the character generate RAM on the 44780...
  DisplayWrite(CONTROL_REGISTER, LCD_LOAD_CGRAM);  WaitBusy();
  for (i = 0;  i < sizeof(m_abCopyrightSymbol);  ++i) {
    //   Note that the actual character generator data is written to the LCD's
    // _data_ port, not the control port!
    DisplayWrite(DATA_REGISTER, m_abCopyrightSymbol[i]);  WaitBusy();
  }  
#endif
#ifdef VFD
  //   VFD displays have a hardware RESET pin, and also have no especially nasty
  // startup conditions, so our life is much easier.  One gotcha, however, is that
  // VFD displays use an active low ENABLE signal, so we initialize it to HIGH.
  DISPLAY_ENABLE = 1; 
#ifdef PCBV1
  DISPLAY_RESET = 0;  DelayMS(20);  DISPLAY_RESET = 1;
#endif
  DelayMS(20);

⌨️ 快捷键说明

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