维库电子市场网
登录 免费注册 首页 | 行业黑名单 | 委托交易 | 帮助 | English
 
IC供应
IC求购
非IC供应
非IC求购
电子资讯
技术资料
商人论坛
 
技术文章 PDF资料 IC价格 引脚说明 电路图 IC替换 IC厂商 电子辞典
作者 主题 内容
采购元器件好去处--维库电子市场网推荐
技术交流 | 电路欣赏 | 工控天地 | 数字广电 | 通信技术 | 电源技术 | 测控之家 | EMC技术 | ARM技术 | EDA技术 | PCB技术 | 嵌入式系统
驱动编程 | 集成电路 | 器件替换 | 模拟技术 | 新手园地 | 单 片 机 | DSP技术 | MCU技术 | IC 设计 | IC 产业 | CAN-bus/DeviceNe

2行7位半汉字LCD模块WINAVR演示程序(菜鸟作)

作者:hotpower 栏目:单片机
2行7位半汉字LCD模块WINAVR演示程序(菜鸟作)
/*------------------------------------------------------------
    HS12232-9带汉字库的2行7位半汉字LCD模块WINAVR演示程序
HotPower@126.com                    2005.1.15
-------------------------------------------------------------*/

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/wdt.h>
#include <avr/ina90.h>
#include <avr/eeprom.h>
//#include <stdio.h>
#include <avr/delay.h>


#define  FREQ 8  //Meaga8L,8MHZ
#define  CS   PB2//LCD片选(串行) 0:禁止 1:允许
#define  SID  PB3//LCD输入串行数据(串行)
#define  CLK  PB5//LCD输入串行脉冲(串行)

#define  SS   PB2//LCD片选(串行) 0:禁止 1:允许
#define  MOSI PB3//LCD输入串行数据(串行)
#define  SCK  PB5//LCD输入串行脉冲(串行)

void PortIoInit(void)
{
  DDRB  = 0;//设置B口全为输入
  DDRC  = 0;//设置C口全为输入
  DDRD  = 0;//设置D口全为输入
  PORTB = 0xff;//设置B口全部上拉
  PORTC = 0xff;//设置C口全部上拉
  PORTD = 0xff;//设置D口全部上拉
}

void SPI_MasterInit(void)
{
/* 设置MOSI 和SCK 及SS 为输出,其他为输入 */
  DDRB = (1 << MOSI) | (1 << SCK) | (1 << SS);
  PORTB = (1 << MOSI) | (1 << SCK) | (1 << SS);
//  PORTB = 0xff;
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式0*/
//  SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0);//不支持!!!
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式1*/
//  SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPHA) | (1 << SPR0);//支持!!!
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式2*/
//  SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << SPR0);//不支持!!!
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式3*/
  SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << CPHA) | (1 << SPR0);//支持!!!
}

void SPI_MasterTransmit(unsigned CHAR cData)
{
/* 启动数据传输 */
  SPDR = cData;
/* 等待传输结束 */
  while(!(SPSR & (1 << SPIF)));
}

void DelayMs(unsigned int t)
{
unsigned int i;
  for(i = 0; i < t; i++)
    _delay_loop_2(250 * FREQ);
}

/*--------------------------------------------------------
    发送8位LCD控制命令
--------------------------------------------------------*/
void LcdSendCommand(unsigned CHAR cCommand)
{
/*--------------------------------------------------------
    发送同步脉冲11111 WR(0) RS(0) 0发送顺序从左至右)
--------------------------------------------------------*/
  PORTB |= (1 << SS);//SS=1,启动SPI
  SPI_MasterTransmit(0xf8);//发送LCD控制命令
  SPI_MasterTransmit(cCommand & 0xf0);//发送高4位LCD控制命令
  SPI_MasterTransmit(cCommand << 4);//发送低4位LCD控制命令
  PORTB &= ~(1 << SS);//SS=0,关闭SPI
  if (cCommand == 0x01) _delay_loop_2(1600 * FREQ);//1.6mS
  else _delay_loop_2(72 * FREQ);//ST7920要求等待72uS
}

/*--------------------------------------------------------
    发送8位LCD显示数据
--------------------------------------------------------*/
void LcdSendData(unsigned CHAR cData)
{
/*--------------------------------------------------------
    发送同步脉冲11111 WR(0) RS(0) 0发送顺序从左至右)
--------------------------------------------------------*/
  PORTB |= (1 << SS);//SS=1,启动SPI
  SPI_MasterTransmit(0xfa);//发送LCD显示数据
  SPI_MasterTransmit(cData & 0xf0);//发送高4位LCD显示数据
  SPI_MasterTransmit(cData << 4);//发送低4位LCD显示数据
  PORTB &= ~(1 << SS);//SS=0,关闭SPI
  _delay_loop_2(72 * FREQ);//ST7920要求等待延时72uS
}


/*---------------------------------------------------
    LCD初始化设置
----------------------------------------------------*/
void LcdInit(void)
{
/*---------------------------------------------------
    LCD模块上电等待延时
----------------------------------------------------*/
  DelayMs(1000);//上电等待延时1000Ms
  SPI_MasterInit();//SPI初始化
  LcdSendCommand(0b00100000);//发送4位控制命令
//  LcdSendCommand(0b00110000);//发送8位控制命令//与8位4位无关!!!
  LcdSendCommand(0b00000010);//发送位址归位命令,设定DDRAM位址计数器为0
  LcdSendCommand(0b00000100);//发送进入点命令
  LcdSendCommand(0b00001100);//发送开显示关光标命令
  LcdSendCommand(0b00000001);//发送清除显示命令
  LcdSendCommand(0b10000000);//发送设定DDRAM地址0x00命令
}

unsigned CHAR SetLCDDISPLAYPos(unsigned CHAR row, unsigned CHAR col)
{
  if ((row < 2) && (col < 8))//汉字字符为2行7.5列(汉字必须偶数对齐)
  {
    LcdSendCommand(0x80 + row * 16 + col);//发送设定DDRAM地址row * 16 + col命令
    return 1;//成功返回
  }
  else  
    return 0;//失败返回
}


void LCDDISPLAY(unsigned CHAR row, unsigned CHAR col, unsigned CHAR * string)
{
  if (SetLCDDISPLAYPos(row, col))
  {
    LcdSendData(*string);
  }
}


void LCDDISPLAYString(unsigned CHAR * string)
{
  while(*string) LcdSendData(*string ++);
}


//main程序
void main(void)
{
unsigned CHAR i = 0;
  PortIoInit();
  LcdInit();
// sei();
  for(;;)
  {
    DelayMs(1000);//上电等待延时1000Ms
    if ((i ++ & 0x01) == 0) LcdSendCommand(0b00000001);//发送清除显示命令
    else  
    {
      SetLCDDISPLAYPos(0, 1);//汉字定位到上行左端
      LCDDISPLAYString("汉字显示演示");
      SetLCDDISPLAYPos(1,0);//字符定位到下行左端
      LCDDISPLAYString("123456789ABCDEF");//必须换行
      SetLCDDISPLAYPos(1,3);//字符定位到下行左端
      LCDDISPLAYString("汉字");
    }
    DelayMs(1000);//上电等待延时1000Ms
    DelayMs(1000);//上电等待延时1000Ms
    DelayMs(1000);//上电等待延时1000Ms
    DelayMs(1000);//上电等待延时1000Ms
  }    
}



2楼: >>参与讨论
hotpower
HS12232-9带汉字库LCD模块WINAVR C++演示程序
/*------------------------------------------------------------
    HS12232-9带汉字库的2行7位半汉字LCD模块WINAVR C++演示程序
HotPower@126.com                    2005.1.16
-------------------------------------------------------------*/

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/wdt.h>
#include <avr/ina90.h>
#include <avr/eeprom.h>
//#include <stdio.h>
#include <avr/delay.h>
#include <avr/io.h>
#include <avr/delay.h>

#define  FREQ 8  //Meaga8L,8MHZ

#define  SS   PB2//LCD片选(串行) 0:禁止 1:允许
#define  MOSI PB3//LCD输入串行数据(串行)
#define  SCK  PB5//LCD输入串行脉冲(串行)

class LcdSpiObj {
public:
  LcdSpiObj(void);
public:
  void LcdSpiModeSetup(void);
  void LcdSpiSend(unsigned CHAR);
  void LcdSpiDelayMs(unsigned int);
  void LcdInit(void);
  void LcdSendCommand(unsigned CHAR);
  void LcdSendData(unsigned CHAR);
  unsigned CHAR SetLCDDISPLAYPos(unsigned CHAR, unsigned CHAR);
  void LCDDISPLAY(unsigned CHAR, unsigned CHAR, const CHAR *);
  void LCDDISPLAYString(const CHAR *);
};


LcdSpiObj::LcdSpiObj(void) {
  LcdSpiModeSetup();
}

void LcdSpiObj::LcdSpiModeSetup(void)
{
/* 设置MOSI 和SCK 及SS 为输出,其他为输入 */
  DDRB = (1 << MOSI) | (1 << SCK) | (1 << SS);
  PORTB = (1 << MOSI) | (1 << SCK) | (1 << SS);
//  PORTB = 0xff;
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式0*/
//  SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0);//不支持!!!
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式1*/
//  SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPHA) | (1 << SPR0);//支持!!!
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式2*/
//  SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << SPR0);//不支持!!!
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式3*/
  SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << CPHA) | (1 << SPR0);//支持!!!
}

void LcdSpiObj::LcdSpiSend(unsigned CHAR cData)
{
/* 启动数据传输 */
  SPDR = cData;
/* 等待传输结束 */
  while(!(SPSR & (1 << SPIF)));
}

void LcdSpiObj::LcdSpiDelayMs(unsigned int t)
{
unsigned int i;
  for(i = 0; i < t; i++)
    _delay_loop_2(250 * FREQ);
}


/*--------------------------------------------------------
    发送8位LCD控制命令
--------------------------------------------------------*/
void LcdSpiObj::LcdSendCommand(unsigned CHAR cCommand)
{
/*--------------------------------------------------------
    发送同步脉冲11111 WR(0) RS(0) 0发送顺序从左至右)
--------------------------------------------------------*/
  PORTB |= (1 << SS);//SS=1,启动SPI
  LcdSpiSend(0xf8);//发送LCD控制命令
  LcdSpiSend(cCommand & 0xf0);//发送高4位LCD控制命令
  LcdSpiSend(cCommand << 4);//发送低4位LCD控制命令
  PORTB &= ~(1 << SS);//SS=0,关闭SPI
  if (cCommand == 0x01) _delay_loop_2(1600 * FREQ);//1.6mS
  else _delay_loop_2(72 * FREQ);//ST7920要求等待72uS
}

/*--------------------------------------------------------
    发送8位LCD显示数据
--------------------------------------------------------*/
void LcdSpiObj::LcdSendData(unsigned CHAR cData)
{
/*--------------------------------------------------------
    发送同步脉冲11111 WR(0) RS(0) 0发送顺序从左至右)
--------------------------------------------------------*/
  PORTB |= (1 << SS);//SS=1,启动SPI
  LcdSpiSend(0xfa);//发送LCD显示数据
  LcdSpiSend(cData & 0xf0);//发送高4位LCD显示数据
  LcdSpiSend(cData << 4);//发送低4位LCD显示数据
  PORTB &= ~(1 << SS);//SS=0,关闭SPI
  _delay_loop_2(72 * FREQ);//ST7920要求等待延时72uS
}


/*---------------------------------------------------
    LCD初始化设置
----------------------------------------------------*/
void LcdSpiObj::LcdInit(void)
{
/*---------------------------------------------------
    LCD模块上电等待延时
----------------------------------------------------*/
  LcdSpiDelayMs(1000);//上电等待延时1000Ms
//  LcdSpiModeSetup();//SPI初始化
  LcdSendCommand(0b00100000);//发送4位控制命令
//  LcdSendCommand(0b00110000);//发送8位控制命令//与8位4位无关!!!
  LcdSendCommand(0b00000010);//发送位址归位命令,设定DDRAM位址计数器为0
  LcdSendCommand(0b00000100);//发送进入点命令
  LcdSendCommand(0b00001100);//发送开显示关光标命令
  LcdSendCommand(0b00000001);//发送清除显示命令
  LcdSendCommand(0b10000000);//发送设定DDRAM地址0x00命令
}

unsigned CHAR LcdSpiObj::SetLCDDISPLAYPos(unsigned CHAR row, unsigned CHAR col)
{
  if ((row < 2) && (col < 8))//汉字字符为2行7.5列(汉字必须偶数对齐)
  {
    LcdSendCommand(0x80 + row * 16 + col);//发送设定DDRAM地址row * 16 + col命令
    return 1;
  }
  else
    return 0;
}


void LcdSpiObj::LCDDISPLAY(unsigned CHAR row, unsigned CHAR col, const CHAR * string)
{
  if (SetLCDDISPLAYPos(row, col))
  {
    LcdSendData(*string);
  }
}


void LcdSpiObj::LCDDISPLAYString(const CHAR * string)
{
  while(*string) LcdSendData(*string ++);
}



LcdSpiObj LcdSpi;

//main程序
int main(void)
{
unsigned CHAR i = 0;
  LcdSpi.LcdInit();
// sei();
  for(;;)
  {
    LcdSpi.LcdSpiDelayMs(1000);//上电等待延时1000Ms
    if ((i ++ & 0x01) == 0) LcdSpi.LcdSendCommand(0b00000001);//发送清除显示命令
    else
    {
      LcdSpi.SetLCDDISPLAYPos(0, 1);//汉字定位到上行左端
      LcdSpi.LCDDISPLAYString("汉字显示演示");
      LcdSpi.SetLCDDISPLAYPos(1,0);//字符定位到下行左端
      LcdSpi.LCDDISPLAYString("123456789ABCDEF");//必须换行
      LcdSpi.SetLCDDISPLAYPos(1,3);//字符定位到下行左端
      LcdSpi.LCDDISPLAYString("汉字");
    }
    LcdSpi.LcdSpiDelayMs(1000);//上电等待延时1000Ms
    LcdSpi.LcdSpiDelayMs(1000);//上电等待延时1000Ms
    LcdSpi.LcdSpiDelayMs(1000);//上电等待延时1000Ms
    LcdSpi.LcdSpiDelayMs(1000);//上电等待延时1000Ms
  }    
}



3楼: >>参与讨论
hotpower
刚用新下载的AVR Studio 4.11,C++可以源码调试
刚试了一下,C++可以进行源码调试(有些函数不太行)...

比较了WINAVR的C和C++生成的长度,C++还是比C的要长些...

我将LCDTEST.C改为LCDTEST.CPP编译后长度比为485:665.

C++多用了180个字节...

看来只好先打消用C++的念头吧,玩玩了了心愿... 

http://61.144.28.248/ouravr/es_avr_serial_software.html

4楼: >>参与讨论
hotpower
修改2楼的bug及展示C++函数重载之风采...
/*------------------------------------------------------------
    HS12232-9带汉字库的2行7位半汉字LCD模块WINAVR C++演示程序
HotPower@126.com                    2005.1.17
-------------------------------------------------------------*/

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/wdt.h>
#include <avr/ina90.h>
#include <avr/eeprom.h>
//#include <stdio.h>
#include <avr/delay.h>
#include <avr/io.h>
#include <avr/delay.h>
#include <string.h>
#include <stdlib.h>

#define  FREQ 8  //Meaga8L,8MHZ

#define  SS   PB2//LCD片选(串行) 0:禁止 1:允许
#define  MOSI PB3//LCD输入串行数据(串行)
#define  SCK  PB5//LCD输入串行脉冲(串行)

class LcdSpiObj {
private:
  unsigned CHAR LcdRow,LcdCol;
  void LcdSpiModeSetup(void);
public:
  LcdSpiObj(void);//LcdSpiObj的构造函数
  void LcdSpiSend(unsigned CHAR);
  void LcdSpiDelayMs(unsigned int);
  void LcdInit(void);
  void LcdSendCommand(unsigned CHAR);
  void LcdSendData(unsigned CHAR);
  unsigned CHAR SetLcdDisplayPos(unsigned CHAR, unsigned CHAR);
  void GetLcdDisplayPos(unsigned CHAR &, unsigned CHAR &);
  void LcdDisplayPos(unsigned CHAR, unsigned CHAR, const CHAR *);
  void LcdDisplayString(const CHAR *);
  void LcdDisplayNumber(CHAR);
  void LcdDisplayNumber(int);
};


LcdSpiObj::LcdSpiObj(void)
{
  LcdRow = 0;
  LcdCol = 0;
  LcdSpiModeSetup();
}

void LcdSpiObj::LcdSpiModeSetup(void)
{
/* 设置MOSI 和SCK 及SS 为输出,其他为输入 */
  DDRB = (1 << MOSI) | (1 << SCK) | (1 << SS);
  PORTB = (1 << MOSI) | (1 << SCK) | (1 << SS);
//  PORTB = 0xff;
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式0*/
//  SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0);//不支持!!!
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式1*/
//  SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPHA) | (1 << SPR0);//支持!!!
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式2*/
//  SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << SPR0);//不支持!!!
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式3*/
  SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << CPHA) | (1 << SPR0);//支持!!!
}

void LcdSpiObj::LcdSpiSend(unsigned CHAR cData)
{
/* 启动数据传输 */
  SPDR = cData;
/* 等待传输结束 */
  while(!(SPSR & (1 << SPIF)));
}

void LcdSpiObj::LcdSpiDelayMs(unsigned int t)
{
unsigned int i;
  for(i = 0; i < t; i++)
    _delay_loop_2(250 * FREQ);
}


/*--------------------------------------------------------
    发送8位LCD控制命令
--------------------------------------------------------*/
void LcdSpiObj::LcdSendCommand(unsigned CHAR cCommand)
{
/*--------------------------------------------------------
    发送同步脉冲11111 WR(0) RS(0) 0发送顺序从左至右)
--------------------------------------------------------*/
  PORTB |= (1 << SS);//SS=1,启动SPI
  LcdSpiSend(0xf8);//发送LCD控制命令
  LcdSpiSend(cCommand & 0xf0);//发送高4位LCD控制命令
  LcdSpiSend(cCommand << 4);//发送低4位LCD控制命令
  PORTB &= ~(1 << SS);//SS=0,关闭SPI
  if (cCommand == 0x01) _delay_loop_2(1600 * FREQ);//1.6mS
  else _delay_loop_2(72 * FREQ);//ST7920要求等待72uS
}

/*--------------------------------------------------------
    发送8位LCD显示数据
--------------------------------------------------------*/
void LcdSpiObj::LcdSendData(unsigned CHAR cData)
{
/*--------------------------------------------------------
    发送同步脉冲11111 WR(0) RS(0) 0发送顺序从左至右)
--------------------------------------------------------*/
  PORTB |= (1 << SS);//SS=1,启动SPI
  LcdSpiSend(0xfa);//发送LCD显示数据
  LcdSpiSend(cData & 0xf0);//发送高4位LCD显示数据
  LcdSpiSend(cData << 4);//发送低4位LCD显示数据
  PORTB &= ~(1 << SS);//SS=0,关闭SPI
  _delay_loop_2(72 * FREQ);//ST7920要求等待延时72uS
}


/*---------------------------------------------------
    LCD初始化设置
----------------------------------------------------*/
void LcdSpiObj::LcdInit(void)
{
/*---------------------------------------------------
    LCD模块上电等待延时
----------------------------------------------------*/
  LcdSpiDelayMs(1000);//上电等待延时1000Ms
  LcdSpiModeSetup();//SPI初始化
  LcdSendCommand(0b00100000);//发送4位控制命令
//  LcdSendCommand(0b00110000);//发送8位控制命令//与8位4位无关!!!
  LcdSendCommand(0b00000010);//发送位址归位命令,设定DDRAM位址计数器为0
  LcdSendCommand(0b00000100);//发送进入点命令
  LcdSendCommand(0b00001100);//发送开显示关光标命令
  LcdSendCommand(0b00000001);//发送清除显示命令
  LcdSendCommand(0b10000000);//发送设定DDRAM地址0x00命令
}

unsigned CHAR LcdSpiObj::SetLcdDisplayPos(unsigned CHAR row, unsigned CHAR col)
{
  if ((row < 2) && (col < 8)) {//汉字字符为2行7.5列(汉字必须偶数对齐)
    LcdSendCommand(0x80 + row * 16 + col);//发送设定DDRAM地址row * 16 + col命令
    LcdRow = row;
    LcdCol = col << 1;
    return 1;
  }
  else
    return 0;
}

void LcdSpiObj::GetLcdDisplayPos(unsigned CHAR &row, unsigned CHAR &col)
{
  row = LcdRow;
  col = LcdCol;
}


void LcdSpiObj::LcdDisplayPos(unsigned CHAR row, unsigned CHAR col, const CHAR * string)
{
  if (SetLcdDisplayPos(row, col)) LcdDisplayString(string);
}


void LcdSpiObj::LcdDisplayString(const CHAR * string)
{
  while(*string) {
    LcdSendData(*string ++);
    LcdCol ++;
  }
}

//注意下列2个函数(函数重载)
void LcdSpiObj::LcdDisplayNumber(CHAR Val)
{
CHAR str[4];
  itoa((int)Val, (CHAR *)str, 10);
  LcdDisplayString((CHAR *)str);
}

void LcdSpiObj::LcdDisplayNumber(int Val)
{
CHAR str[6];
  itoa(Val, (CHAR *)str, 10);
  LcdDisplayString((CHAR *)str);
}


LcdSpiObj LcdSpi;

//main程序
int main(void)
{
unsigned int i = 0;
unsigned CHAR row, col;
  LcdSpi.LcdInit();
  LcdSpi.SetLcdDisplayPos(0, 1);//汉字定位到上行左端
  LcdSpi.LcdDisplayString("汉字显示演示");
// sei();
  for(;;) {
    LcdSpi.LcdSpiDelayMs(1000);//上电等待延时1000Ms
    LcdSpi.SetLcdDisplayPos(1,0);//字符定位到下行左端
    LcdSpi.LcdDisplayString("123456789ABCDEF");//必须换行
    Lc
5楼: >>参与讨论
victorymay
hello
楼主能否将"12232"与MEGA8的硬件接口电路贴出,我手边刚好也有"12232"一块

或发送*.sch文件 to mueua@21cn.com


6楼: >>参与讨论
hotpower
继续重载,所有LCD显示函数都使用一个函数名LCDDISPLAY()
/*------------------------------------------------------------
    HS12232-9带汉字库的2行7位半汉字LCD模块WINAVR C++演示程序
HotPower@126.com                    2005.1.17
-------------------------------------------------------------*/

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/wdt.h>
#include <avr/ina90.h>
#include <avr/eeprom.h>
//#include <stdio.h>
#include <avr/delay.h>
#include <avr/io.h>
#include <avr/delay.h>
#include <string.h>
#include <stdlib.h>

#define  FREQ 8  //Meaga8L,8MHZ

#define  SS   PB2//LCD片选(串行) 0:禁止 1:允许
#define  MOSI PB3//LCD输入串行数据(串行)
#define  SCK  PB5//LCD输入串行脉冲(串行)

class LcdSpiObj {
private:
  unsigned CHAR LcdRow,LcdCol;
  void LcdSpiModeSetup(void);
public:
  LcdSpiObj(void);//LcdSpiObj的构造函数
  void LcdSpiSend(unsigned CHAR);
  void LcdSpiDelayMs(unsigned int);
  void LcdInit(void);
  void LcdSendCommand(unsigned CHAR);
  void LcdSendData(unsigned CHAR);
  unsigned CHAR SetLCDDISPLAYPos(unsigned CHAR, unsigned CHAR);
  void GetLCDDISPLAYPos(unsigned CHAR &, unsigned CHAR &);

  void LCDDISPLAY(unsigned CHAR, unsigned CHAR, const CHAR *);
  void LCDDISPLAY(const CHAR *);
  void LCDDISPLAY(CHAR);
  void LCDDISPLAY(int);
};


LcdSpiObj::LcdSpiObj(void)
{
  LcdRow = 0;
  LcdCol = 0;
  LcdSpiModeSetup();
}

void LcdSpiObj::LcdSpiModeSetup(void)
{
/* 设置MOSI 和SCK 及SS 为输出,其他为输入 */
  DDRB = (1 << MOSI) | (1 << SCK) | (1 << SS);
  PORTB = (1 << MOSI) | (1 << SCK) | (1 << SS);
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式0*/
//  SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0);//不支持!!!
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式1*/
//  SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPHA) | (1 << SPR0);//支持!!!
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式2*/
//  SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << SPR0);//不支持!!!
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式3*/
  SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << CPHA) | (1 << SPR0);//支持!!!
}

void LcdSpiObj::LcdSpiSend(unsigned CHAR cData)
{
/* 启动数据传输 */
  SPDR = cData;
/* 等待传输结束 */
  while(!(SPSR & (1 << SPIF)));
}

void LcdSpiObj::LcdSpiDelayMs(unsigned int t)
{
unsigned int i;
  for(i = 0; i < t; i++)
    _delay_loop_2(250 * FREQ);
}


/*--------------------------------------------------------
    发送8位LCD控制命令
--------------------------------------------------------*/
void LcdSpiObj::LcdSendCommand(unsigned CHAR cCommand)
{
/*--------------------------------------------------------
    发送同步脉冲11111 WR(0) RS(0) 0发送顺序从左至右)
--------------------------------------------------------*/
  PORTB |= (1 << SS);//SS=1,启动SPI
  LcdSpiSend(0xf8);//发送LCD控制命令
  LcdSpiSend(cCommand & 0xf0);//发送高4位LCD控制命令
  LcdSpiSend(cCommand << 4);//发送低4位LCD控制命令
  PORTB &= ~(1 << SS);//SS=0,关闭SPI
  if (cCommand == 0x01) _delay_loop_2(1600 * FREQ);//1.6mS
  else _delay_loop_2(72 * FREQ);//ST7920要求等待72uS
}

/*--------------------------------------------------------
    发送8位LCD显示数据
--------------------------------------------------------*/
void LcdSpiObj::LcdSendData(unsigned CHAR cData)
{
/*--------------------------------------------------------
    发送同步脉冲11111 WR(0) RS(0) 0发送顺序从左至右)
--------------------------------------------------------*/
  PORTB |= (1 << SS);//SS=1,启动SPI
  LcdSpiSend(0xfa);//发送LCD显示数据
  LcdSpiSend(cData & 0xf0);//发送高4位LCD显示数据
  LcdSpiSend(cData << 4);//发送低4位LCD显示数据
  PORTB &= ~(1 << SS);//SS=0,关闭SPI
  _delay_loop_2(72 * FREQ);//ST7920要求等待延时72uS
}


/*---------------------------------------------------
    LCD初始化设置
----------------------------------------------------*/
void LcdSpiObj::LcdInit(void)
{
/*---------------------------------------------------
    LCD模块上电等待延时
----------------------------------------------------*/
  LcdSpiDelayMs(1000);//上电等待延时1000Ms
  LcdSpiModeSetup();//SPI初始化
  LcdSendCommand(0b00100000);//发送4位控制命令
//  LcdSendCommand(0b00110000);//发送8位控制命令//与8位4位无关!!!
  LcdSendCommand(0b00000010);//发送位址归位命令,设定DDRAM位址计数器为0
  LcdSendCommand(0b00000100);//发送进入点命令
  LcdSendCommand(0b00001100);//发送开显示关光标命令
  LcdSendCommand(0b00000001);//发送清除显示命令
  LcdSendCommand(0b10000000);//发送设定DDRAM地址0x00命令
}

unsigned CHAR LcdSpiObj::SetLCDDISPLAYPos(unsigned CHAR row, unsigned CHAR col)
{
  row --;
  col --;
  if ((row < 2) && (col < 8)) {//汉字字符为2行7.5列(汉字必须偶数对齐)
    LcdSendCommand(0x80 + row * 16 + col);//发送设定DDRAM地址row * 16 + col命令
    LcdRow = row;
    LcdCol = col << 1;
    return 1;
  }
  else
    return 0;
}

void LcdSpiObj::GetLCDDISPLAYPos(unsigned CHAR &row, unsigned CHAR &col)
{
  row = LcdRow + 1;
  col = LcdCol + 1;
}


void LcdSpiObj::LCDDISPLAY(unsigned CHAR row, unsigned CHAR col, const CHAR * string)
{
  if (SetLCDDISPLAYPos(row, col)) LCDDISPLAY(string);
}


void LcdSpiObj::LCDDISPLAY(const CHAR * string)
{
  while(*string) {
    LcdSendData(*string ++);
    LcdCol ++;
  }
}

void LcdSpiObj::LCDDISPLAY(CHAR Val)
{
CHAR str[4];
  itoa((int)Val, (CHAR *)str, 10);
  LCDDISPLAY((CHAR *)str);
}

void LcdSpiObj::LCDDISPLAY(int Val)
{
CHAR str[6];
  itoa(Val, (CHAR *)str, 10);
  LCDDISPLAY((CHAR *)str);
}

/*----------------------------------------------------------
  申请全局类对象LcdSpi.它封装了HS12232-9 LCD模块的基本函数组合
----------------------------------------------------------*/
LcdSpiObj LcdSpi;


//main程序
int main(void)
{
int i = 0;
unsigned CHAR row, col;
  LcdSpi.LcdInit();//LCD初始化
  LcdSpi.SetLCDDISPLAYPos(1, 2);//定位到第1行第2个汉字列上
  LcdSpi.LCDDISPLAY("汉字显示演示");//在当前位置显示汉字串
// sei();
  for(;;) {//死循环
/*--------------------------------------------------------------------
 &n
7楼: >>参与讨论
hotpower
victorymay: 线路接的是M8L标准的SPI接口
一共用了3线(SS也可以不要,直接接高电平)
#define  SS   PB2//LCD片选(串行) 0:禁止 1:允许
#define  MOSI PB3//LCD输入串行数据(串行)
#define  SCK  PB5//LCD输入串行脉冲(串行)



8楼: >>参与讨论
hotpower
适当声明为内联函数可以优化
适当声明为内联函数可以优化,但有些反而增大代码程度.
比较郁闷...


楼上.text=1004   .data=34
本例.text= 744   .data=34



inline LcdSpiObj::LcdSpiObj(void)
{
  LcdRow = 0;
  LcdCol = 0;
  LcdSpiModeSetup();
}

inline void LcdSpiObj::LcdSpiModeSetup(void)
{
/* 设置MOSI 和SCK 及SS 为输出,其他为输入 */
  DDRB = (1 << MOSI) | (1 << SCK) | (1 << SS);
  PORTB = (1 << MOSI) | (1 << SCK) | (1 << SS);
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式0*/
//  SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0);//不支持!!!
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式1*/
//  SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPHA) | (1 << SPR0);//支持!!!
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式2*/
//  SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << SPR0);//不支持!!!
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式3*/
  SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << CPHA) | (1 << SPR0);//支持!!!
}

inline void LcdSpiObj::LcdSpiSend(unsigned CHAR cData)
{
/* 启动数据传输 */
  SPDR = cData;
/* 等待传输结束 */
  while(!(SPSR & (1 << SPIF)));
}

inline void LcdSpiObj::LcdSpiDelayMs(unsigned int t)
{
unsigned int i;
  for(i = 0; i < t; i++)
    _delay_loop_2(250 * FREQ);
}


/*--------------------------------------------------------
    发送8位LCD控制命令
--------------------------------------------------------*/
void LcdSpiObj::LcdSendCommand(unsigned CHAR cCommand))//内联反而增大代码长度
{
/*--------------------------------------------------------
    发送同步脉冲11111 WR(0) RS(0) 0发送顺序从左至右)
--------------------------------------------------------*/
  PORTB |= (1 << SS);//SS=1,启动SPI
  LcdSpiSend(0xf8);//发送LCD控制命令
  LcdSpiSend(cCommand & 0xf0);//发送高4位LCD控制命令
  LcdSpiSend(cCommand << 4);//发送低4位LCD控制命令
  PORTB &= ~(1 << SS);//SS=0,关闭SPI
  if (cCommand == 0x01) _delay_loop_2(1600 * FREQ);//1.6mS
  else _delay_loop_2(72 * FREQ);//ST7920要求等待72uS
}

/*--------------------------------------------------------
    发送8位LCD显示数据
--------------------------------------------------------*/
inline void LcdSpiObj::LcdSendData(unsigned CHAR cData)
{
/*--------------------------------------------------------
    发送同步脉冲11111 WR(0) RS(0) 0发送顺序从左至右)
--------------------------------------------------------*/
  PORTB |= (1 << SS);//SS=1,启动SPI
  LcdSpiSend(0xfa);//发送LCD显示数据
  LcdSpiSend(cData & 0xf0);//发送高4位LCD显示数据
  LcdSpiSend(cData << 4);//发送低4位LCD显示数据
  PORTB &= ~(1 << SS);//SS=0,关闭SPI
  _delay_loop_2(72 * FREQ);//ST7920要求等待延时72uS
}


/*---------------------------------------------------
    LCD初始化设置
----------------------------------------------------*/
inline void LcdSpiObj::LcdInit(void)
{
/*---------------------------------------------------
    LCD模块上电等待延时
----------------------------------------------------*/
  LcdSpiDelayMs(1000);//上电等待延时1000Ms
  LcdSpiModeSetup();//SPI初始化
  LcdSendCommand(0b00100000);//发送4位控制命令
//  LcdSendCommand(0b00110000);//发送8位控制命令//与8位4位无关!!!
  LcdSendCommand(0b00000010);//发送位址归位命令,设定DDRAM位址计数器为0
  LcdSendCommand(0b00000100);//发送进入点命令
  LcdSendCommand(0b00001100);//发送开显示关光标命令
  LcdSendCommand(0b00000001);//发送清除显示命令
  LcdSendCommand(0b10000000);//发送设定DDRAM地址0x00命令
}

inline unsigned CHAR LcdSpiObj::SetLCDDISPLAYPos(unsigned CHAR row, unsigned CHAR col)
{
  row --;
  col --;
  if ((row < 2) && (col < 8)) {//汉字字符为2行7.5列(汉字必须偶数对齐)
    LcdSendCommand(0x80 + row * 16 + col);//发送设定DDRAM地址row * 16 + col命令
   LcdRow = row;
   LcdCol = col << 1;
   return 1;
  }
  else
    return 0;
}

inline void LcdSpiObj::GetLCDDISPLAYPos(unsigned CHAR &row, unsigned CHAR &col)
{
  row = LcdRow + 1;
  col = LcdCol + 1;
}


inline void LcdSpiObj::LCDDISPLAY(unsigned CHAR row, unsigned CHAR col, const CHAR * string)
{
  if (SetLCDDISPLAYPos(row, col)) LCDDISPLAY(string);
}


void LcdSpiObj::LCDDISPLAY(const CHAR * string)//内联反而增大代码长度
{
  while(*string) {
    LcdSendData(*string ++);
   LcdCol ++;
  }
}

inline void LcdSpiObj::LCDDISPLAY(CHAR Val)
{
CHAR str[4];
  itoa((int)Val, (CHAR *)str, 10);
  LCDDISPLAY((CHAR *)str);
}

inline void LcdSpiObj::LCDDISPLAY(int Val)
{
CHAR str[6];
  itoa(Val, (CHAR *)str, 10);
  LCDDISPLAY((CHAR *)str);
}


9楼: >>参与讨论
jacksmart
强人,学习!
 
10楼: >>参与讨论
rongxiang
能不能提供一个C51的HS12232-9带汉字库LCD模块演示程序-谢了
 
11楼: >>参与讨论
hotpower
这里有一个商家提供我注解的51asm源程序
;This program is for 12232F,12864-12,12864M Serial TEST.html">TEST
;    RS--------P3.0
;    R/W-------P3.1
;    E---------P3.2
;    DB0~7-----P1

CS    EQU    P3.0;片选(串行) 0:禁止 1:允许
SID    EQU    P3.1;输入串行数据(串行)
CLK    EQU    P3.2;输入串行脉冲(串行)
PSB    EQU    P3.3;控制界面 0:串行 1:并行8/4 位(HS12232-9无用)

    ORG    0000H
    AJMP    START
;    ORG    0003H
;    LCALL     PAUSE
    ORG    0100h
START:
;    MOV  IE,#81H            ;EXT. INT0 PERMIT
;    MOV  IP,#01H            ;INT0 IS FIRST INT. LEVEL
;    MOV  TCON,#00H           ;TIMER/COUNTER CONTROLER INIT.
    MOV   SP, #67H
    CLR   PSB;选择串行工作模式
    LCALL DELAY;延时150mS
    LCALL DELAY;延时150mS
    LCALL SETUP;LCD初始化设置
    LCALL DEF_CHAR;自定义字符显示

/*---------------------------------------------------
    显示4行CGRAM1字符
----------------------------------------------------*/
    MOV  A,#80H
    LCALL WRITE_COM;发送设定DDRAM地址0x00命令
/*---------------------------------------------------
    显示第一行CGRAM1字符
----------------------------------------------------*/
    MOV  R3,#8
TEST11:    
    MOV  DPTR,#CGRAM1    ;CGRAM TEST
    LCALL WRITE_CGRAM
    DJNZ R3,TEST11
    MOV  A,#90H
    LCALL WRITE_COM;发送设定DDRAM地址0x10命令
/*---------------------------------------------------
    显示第二行CGRAM1字符
----------------------------------------------------*/
    MOV  R3,#8
TEST12:    
    MOV  DPTR,#CGRAM1
    LCALL WRITE_CGRAM
    DJNZ  R3,TEST12
    MOV  A,#88H
    LCALL WRITE_COM;发送设定DDRAM地址0x08命令
/*---------------------------------------------------
    显示第三行CGRAM1字符
----------------------------------------------------*/
    MOV  R3,#8
TEST13:
     MOV  DPTR,#CGRAM1
    LCALL WRITE_CGRAM
    DJNZ  R3,TEST13
    MOV  A,#98H
    LCALL WRITE_COM;发送设定DDRAM地址0x18命令
/*---------------------------------------------------
    显示第四行CGRAM1字符
----------------------------------------------------*/
    MOV  R3,#8
TEST14:    
    MOV  DPTR,#CGRAM1
    LCALL WRITE_CGRAM
    DJNZ  R3,TEST14
/*---------------------------------------------------
    CGRAM1字符显示等待延时5秒
----------------------------------------------------*/
    LCALL DELAY;延时150mS
    LCALL DELAY;延时150mS
    LCALL DELAY;延时150mS
    LCALL DELAY;延时150mS
    LCALL DELAY;延时150mS

/*---------------------------------------------------
    显示4行CGRAM2字符
----------------------------------------------------*/
    MOV  A,#80H
    LCALL WRITE_COM;发送设定DDRAM地址0x00命令
/*---------------------------------------------------
    显示第一行CGRAM2字符
----------------------------------------------------*/
    MOV  R3,#8
TEST21:
    MOV  DPTR,#CGRAM2
    LCALL WRITE_CGRAM
    DJNZ R3,TEST21
    MOV  A,#90H
    LCALL WRITE_COM;发送设定DDRAM地址0x10命令
/*---------------------------------------------------
    显示第二行CGRAM2字符
----------------------------------------------------*/
    MOV  R3,#8
TEST22:
    MOV  DPTR,#CGRAM2
    LCALL WRITE_CGRAM
    DJNZ  R3,TEST22
    MOV  A,#88H
    LCALL WRITE_COM;发送设定DDRAM地址0x08命令
/*---------------------------------------------------
    显示第三行CGRAM2字符
----------------------------------------------------*/
    MOV  R3,#8
TEST23:
      MOV  DPTR,#CGRAM2
    LCALL WRITE_CGRAM
    DJNZ R3,TEST23
    MOV  A,#98H
    LCALL WRITE_COM;发送设定DDRAM地址0x18命令
/*---------------------------------------------------
    显示第四行CGRAM2字符
----------------------------------------------------*/
    MOV  R3,#8
TEST24:    
    MOV  DPTR,#CGRAM2
    LCALL WRITE_CGRAM
    DJNZ R3,TEST24
/*---------------------------------------------------
    CGRAM2字符显示等待延时
----------------------------------------------------*/
    LCALL DELAY;延时150mS
    LCALL DELAY;延时150mS
    LCALL DELAY;延时150mS
    LCALL DELAY;延时150mS
    LCALL DELAY;延时150mS

/*---------------------------------------------------
    显示4行CGRAM3字符
----------------------------------------------------*/
    MOV  A,#80H
    LCALL WRITE_COM;发送设定DDRAM地址0x00命令
/*---------------------------------------------------
    显示第一行CGRAM3字符
----------------------------------------------------*/
    MOV  R3,#8
TEST31:    
    MOV  DPTR,#CGRAM3
    LCALL WRITE_CGRAM
    DJNZ R3,TEST31
    MOV  A,#90H
    LCALL WRITE_COM;发送设定DDRAM地址0x10命令
/*---------------------------------------------------
    显示第二行CGRAM3字符
----------------------------------------------------*/
    MOV  R3,#8
TEST32:    
    MOV  
12楼: >>参与讨论
hotpower
HS12232-9并非遵守完整的SPI协议
HS12232-9并非遵守完整的SPI协议,片选先CS(SS)可以直接接高电平,这样实际只需2线(时钟SCK和数据MOSI).

串行接法的缺点是不能读出LCD信息,不过也不是最重要的,重要的是连线最少才是真...

13楼: >>参与讨论
st_z
兄台确实很强
佩服!

14楼: >>参与讨论
hotpower
12232-9/12864通用程序
只需改写SetLcdDisplayPos()函数即可实现12232-9/12864通用.
注意12232-9 J2的跳线和12864PSB接地将硬件设置为串行方式.

inline unsigned CHAR LcdSpiObj::SetLcdDisplayPos(unsigned CHAR row, unsigned CHAR col)
{
  row --;
  col --;
  if ((row < 4) && (col < 8)) {//汉字字符为4行8列(汉字必须偶数对齐)
    LcdSendCommand(0x80 + (row & 1) * 16 + (row >> 1) * 8 + col
    LcdRow = row;
    LcdCol = col << 1;
    return 1;
  }
  else
    return 0;
}



//main程序
int main(void)
{
  LcdSpi.SetLcdDisplayPos(4, 1);//定位到第4行第1个汉字列上
  LcdSpi.LcdDisplay("04汉字显示演示04");//在当前位置显示汉字串
//.............................................
  return 0;//正常返回操作系统(实际不可能,MCU一般也不需要)
}


参与讨论
昵称:
讨论内容:
 
 
相关帖子
用AVR910-2313的硬件稍加改动,作了个delta-sigma AD,但不准
谁能告诉我以下mega169的价格吗?
时钟芯片DS1387
关于USART数据空中断
为什么我的mega48一进入休眠状态就醒不了了呢?
免费注册为维库电子开发网会员,参与电子工程师社区讨论,点此进入


Copyright © 1998-2006 www.dzsc.com 浙ICP证030469号