带国标中文字库图形点阵液晶显示模块st7920
http://www.tinsharp.com/product/mannul/st7920c20c.pdfhttp://www.qingyun-it.com/products/yejing/readme/zk/LCMZKuser.pdf
http://www.xie-gang.com/12864.htm
http://www.nsbc.com/digitalspirit/jswlcd/lcd_price.htm
-----此内容被hotpower于2004-12-17,07:38:41编辑过 我这次一定用WINAVR搞个非典的...就是这几天大雪封山村里没货...
T26L,M8L等都没有...羡慕某些城市的人呀...守着金山... 我用过的,从51上移植过来的,可以显示的!传上来给大家看看!
点击此处下载armok0118262.txt 太好了,可惜不是串行的...
谢谢mymach!!!!!!!!!!!!!!!!!!!!!!!!
这次我硬件设计的是2线串行通信方式,想用AVR的SPI口...
-----此内容被hotpower于2004-12-17,14:02:55编辑过 不知道批量是什么价格?5k量吧
现在一直在找一种液晶,本来考虑阿莫的3310,但怕货源不稳!
这FYD12864如果价格合适,倒可以考虑的
hotpower能相告吗? 不是这产品本身,是你的进货渠道那里稳不稳啊? 哈哈,谢谢阿莫啦! 我手上有一款串行的ST7920模块,可惜没有时间弄! 我刚选定HS12232-9...不知是哪个厂家的...
要忙了... 贵啊,呵呵
如果是12864不带字库的话,我的一个同学应该已经搞定了。
带字库应该也不难吧? 谢谢阿莫!
我已让人画原理图和PCB了,再过几天...
HS12232-9四位和八位的应用较多,二线的好象很少,但M8L的IO确实太少了...
一直未搜到二线的C语言应用程序,看来只有自己作了... 找到一个二线51ASM,我给加了注解,今天看是否能在AVR上运行...
点击此处下载armok0127622.txt 那款FYD12864-0402B就是我们成都产的,我跟那个销售商认识,我曾经买过一块,用了90圆。资料上介绍可以支持8/4线并行、2线或3线等多种接口方式,内含国标一、二级字库。应该是很不错的一款液晶显示器。 站长:
C的2线例程我一直未找见,这个也是销售商"给的面子"才搞到手的...主要是想看下具体
的操作.
本来我还为如何读发愁呢(因为会影响下载线,所以硬件要加工一下),看到该例程放弃了
读操作,心里就安稳多了...
用AVR"打死我也不会用汇编",但学习例程也是不错的... 12864 keil的,串行方式 编写时已经考虑到往avr上的移植了,spi可以用avr硬件的,也可以用io模拟,甚至可以用mega48的串口做spi主机
,经过我的测试串行方式,在cs无效时,7920还是可以接受数据,导致显示被误改,如果spi上接了其它器件,小心使用。
sbit ST7920CS=P3^3;
void write7920cmd(unsigned char cmd)
{
unsigned char i=0;
ST7920CS=1;
Spi(0xf8);
Spi(cmd&0xf0);
Spi(cmd<<4);
ST7920CS=0;
Delay10us(10);
}
void write7920data(unsigned char dat)
{
ST7920CS=1;
Spi(0xfa);
Spi(dat&0xf0);
Spi(dat<<4);
ST7920CS=0;
Delay10us(10);
}
void init7920(void)
{
write7920cmd(0x20);//4bit 基本指令
write7920cmd(0x20);//4bit 基本指令
write7920cmd(0x0c);//开显示
write7920cmd(0x01);//清屏
write7920cmd(0x06);
}
void DispSetCursor(unsigned char LineNum, unsigned char ColumnNum)
{
unsigned char i=0x00;
switch(LineNum&0x0f) //确定行号
{
case 0x00:
i=0x80;
break;
case 0x01:
i=0x90;
break;
case 0x02:
i=0x88;
break;
case 0x03:
i=0x98;
break;
default :
break;
}
i = (ColumnNum&0x0f)|i; //确定列号
write7920cmd(i);
} 汉字显示参考代码
unsigned char code mainmenu[]="1:当前时间2:tcp/ip参数设置3:AD采样按 1,2,3选择操作";
void dis_mainmenu(void)
{
unsigned char i;
DispSetCursor(0,0); //
for (i=0;i<10;i++) //
{
write7920data(mainmenu); //1:当前时间
}
DispSetCursor(1,0); //
for (;i<26;i++) //
{
write7920data(mainmenu); //2:tcp/ip参数设置
}
DispSetCursor(2,0); //
for (;i<34;i++) //
{
write7920data(mainmenu); //3:AD采样
}
DispSetCursor(3,0); //
for (;i<50;i++) //
{
write7920data(mainmenu); //按 1,2,3选择操作
}
} 谢谢mucode...
我也将51asm移植到WinAvr,但由于买的是5V的HS12232-9,但手头只有3.3V的M8L系统,所以驱动不了,不知对否???
山区确实山路崎岖,3.3V的HS12232-9必须一周后才能到货...
只好明天上班用5V系统了...
以下是我移植的,请mucode同志个指教一番...主要是在时序方面...
#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>
#defineFREQ 8//Meaga8L,8MHz
#defineCS PB2//LCD片选(串行) 0:禁止 1:允许
#defineSIDPB3//LCD输入串行数据(串行)
#defineCLKPB5//LCD输入串行脉冲(串行)
#defineSS PB2//LCD片选(串行) 0:禁止 1:允许
#defineMOSI PB3//LCD输入串行数据(串行)
#defineSCKPB5//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 为输出,其他为输入 */
DDRB = (1 << MOSI) | (1 << SCK);
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式3*/
SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << CPHA) | (1 << SPR0);
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式2*/
//SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (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)
{
_delay_loop_2(72 * FREQ);//st7920要求等待72uS
/*--------------------------------------------------------
发送同步脉冲11111 WR(0) RS(0) 0发送顺序从左至右)
--------------------------------------------------------*/
PORTB &= ~(1 << SS);//SS=0,启动SPI
SPI_MasterTransmit(0xf8);//发送LCD控制命令
SPI_MasterTransmit(cCommand & 0xf0);//发送高4位LCD控制命令
SPI_MasterTransmit(cCommand << 4);//发送低4位LCD控制命令
PORTB |= (1 << SS);//SS=1,关闭SPI
}
/*--------------------------------------------------------
发送8位LCD显示数据
--------------------------------------------------------*/
void LcdSendData(unsigned char cData)
{
_delay_loop_2(72 * FREQ);//st7920要求等待延时72uS
/*--------------------------------------------------------
发送同步脉冲11111 WR(0) RS(0) 0发送顺序从左至右)
--------------------------------------------------------*/
PORTB &= ~(1 << SS);//SS=0,启动SPI
SPI_MasterTransmit(0xfa);//发送LCD显示数据
SPI_MasterTransmit(cData & 0xf0);//发送高4位LCD显示数据
SPI_MasterTransmit(cData << 4);//发送低4位LCD显示数据
PORTB |= (1 << SS);//SS=1,关闭SPI
}
/*---------------------------------------------------
LCD初始化设置
----------------------------------------------------*/
void LcdInit(void)
{
/*---------------------------------------------------
LCD模块上电等待延时
----------------------------------------------------*/
DelayMs(1000);//上电等待延时1000Ms
SPI_MasterInit();//SPI初始化
LcdSendCommand(0b00100000);//发送4位控制命令
LcdSendCommand(0b00000010);//发送位址归位命令,设定DDRAM位址计数器为0
LcdSendCommand(0b00000100);//发送进入点命令
LcdSendCommand(0b00001100);//发送开显示关光标命令
LcdSendCommand(0b00000001);//发送清除显示命令
LcdSendCommand(0b10000000);//发送设定DDRAM地址0x00命令
}
unsigned char SetLcdDisplayCharPos(unsigned char row, unsigned char col)
{
if ((row < 2) && (col < 16))//英文字符为2行16列
{
LcdSendCommand(0x80 + row * 16 + col);//发送设定DDRAM地址row * 16 + col命令
return 1;
}
else
return 0;
}
void LcdDisplayChar(unsigned char row, unsigned char col, unsigned char * string)
{
if (SetLcdDisplayCharPos(row, col))
{
LcdSendData(*string);
}
}
unsigned char SetLcdDisplayChinsePos(unsigned char row, unsigned char col)
{
if ((row < 2) && (col < 8))//汉字字符为2行8列(偶数对齐)
{
LcdSendCommand(0x80 + row * 16 + col * 2);//发送设定DDRAM地址row * 16 + col * 2命令
return 1;
}
else
return 0;
}
void LcdDisplayChinse(unsigned char row, unsigned char col, unsigned char * string)
{
if (SetLcdDisplayChinsePos(row, col))
{
LcdSendData(*string);
LcdSendData(*(string + 1));
}
}
void LcdDisplayString(unsigned char * string)
{
while(*string) LcdSendData(*string ++);
}
//main程序
void main(void)
{
PortIoInit();
LcdInit();
// sei();
SetLcdDisplayChinsePos(0, 0);//汉字定位到上行左端
LcdDisplayString("汉字显示演示程序");
SetLcdDisplayCharPos(1,0);//字符定位到下行左端
LcdDisplayString("0123456789ABCDEF");
for(;;)
{
}
} 用串行方式的最大缺点:无法读取显示ram
复杂的图形操作可能就不好做了
另外我用的这个12864,和一个spi的ad挂在一起,用两个io分别使能,结果ad控制正常,st7920却不受cs控制,始终接受数据,导致控制ad时显示乱码。现在pcb不能改,只好想办法破坏时序,避免显示出错。 我也原打算用SPI再连接其他SPI器件,但SS需要再译码,就放弃了...
我刚在5V系统上调试未通过,可能对AVR的SPI不太熟悉吧,可用模拟SPI也未通过...
不知为何???
void SPI_MasterInit(void)
{
/* 设置MOSI 和SCK 为输出,其他为输入 */
DDRB = (1 << MOSI) | (1 << SCK);
PORTB = 0xff;
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式3*/
//SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << CPHA) | (1 << SPR0);
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式2*/
//SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << SPR0);
}
void SPI_MasterTransmit(unsigned char cData)
{
/* 启动数据传输 */
//SPDR = cData;
/* 等待传输结束 */
//while(!(SPSR & (1 << SPIF)));
for (unsigned char i = 8; i > 0; i --)
{
if (cData & 0x80) PORTB |= (1 << MOSI);
else PORTB &= ~(1 << MOSI);
PORTB &= ~(1 << SCK);
cData <<= 1;
PORTB |= (1 << SCK);
}
} 原理图可以上传的,至于实物照片我没有数码相机,所以就无法实现了 就3根线.
SS----!CS
MODI-- SID
SCK -- SCLK
我试了SPI的各种组合,也没成功...郁闷呀(肯定犯了低级错误,但是...不会LCD不好吧...) 郁闷之中...
mymach能否帮我一把???在您的系统中运行我在【21楼】的程序???
先谢谢了... 我正好写过一个,不过是4位的。
//********************************************
//7920中文LCD屏,带中文字库
//联接: LCD MEGA128
// RS ----- PORTC.0
// RD ----- PORTC.1
// EN ----- PORTC.2
// DB4 ----- PORTC.4
// DB5 ----- PORTC.5
// DB6 ----- PORTC.6
// DB7 ----- PORTC.7
//********************************************
#define LCD_RS PORTC.0
#define LCD_RD PORTC.1
#define LCD_EN PORTC.2
#define LCD_DB PORTC
//********************************************
//将数据输出到LCD接口,LCD数据口宽度为4bit
//rs: 1 操作指令寄存器,0 操作数据寄存器
//rd: 1 从LCD读出数据, 0 向LCD写数据
//db: 要写入的数据,仅底4位有效
//********************************************
void lcd_setport(char rs,char rd,char db)
{
//unsigned char temp;
db=db<<4;
LCD_RS=rs;
LCD_RD=rd;
delay_us(20);
LCD_EN=1;
delay_us(10);
LCD_DB=LCD_DB&0x0F;
LCD_DB=LCD_DB|db;
//LCD_DB=db;
delay_us(10);
LCD_EN=0;
delay_us(20);
}
//********************************************
//LCD功能设定,LCD数据口宽度为4bit
//re: 1扩展指令, 0 基本指令
//********************************************
void lcd_function_set(char re)
{
char db;
db=db|(re<<2);
lcd_setport(0,0,0x02);
lcd_setport(0,0,db);
}
//********************************************
// LCD软件复位
//********************************************
void lcd_reset(void)
{
#asm("cli")
lcd_setport(0,0,0x03);
delay_ms(10);
lcd_setport(0,0,0x03);
delay_us(200);
lcd_setport(0,0,0x03);
delay_us(20);
lcd_setport(0,0,0x03);
delay_us(20);
lcd_function_set(0); //使用LCD基本指令
#asm("sei")
}
//**********************************************
//LCD开关设定
//display: 1 显示开, 0 显示关
//cursor:1 光标开, 0 光标关
//blink: 1 光标处字符闪动开, 光标处字符闪动关
//**********************************************
void lcd_on_off(char display,char cursor,char blink)
{
char db;
db=0x08|(display<<2)|(cursor<<1)|blink;
lcd_setport(0,0,0x00);
lcd_setport(0,0,db);
}
//**********************************************
//LCD 清屏
//**********************************************
void lcd_clear(void)
{
lcd_setport(0,0,0x00);
lcd_setport(0,0,0x01);
delay_ms(7);
}
//**********************************************
//LCD显示回原点,设DDRAM地址为0,DDRAM内容不变
//**********************************************
void lcd_return_home(void)
{
lcd_setport(0,0,0x00);
lcd_setport(0,0,0x02);
}
//**********************************************
//输入方式设定,设定光标移动方向并指定整体是否移动
//id :1 增量方式, 0 减量方式
//s:1 写入后整体移动,0 不移动
//**********************************************
void lcd_entry_mode(char id,char s)
{
char db;
db=0x04|(id<<1)|s;
lcd_setport(0,0,0x00);
lcd_setport(0,0,db);
}
//**********************************************
//移动光标或整体
//s_c: 1 整体显示移位,0 光标移动
//r_l: 1 左移, 0 右移
//**********************************************
void lcd_cour_disp_shift(char s_c,char r_l)
{
char db;
db=db|(s_c<<3)|(r_l<<2);
lcd_setport(0,0,0x01);
lcd_setport(0,0,db);
}
//**********************************************
//读取当前显示位置
//**********************************************
char lcd_read_address(void)
{
char address,address_l;
LCD_EN=0;
LCD_RS=0;
delay_us(5);
LCD_RD=1;
delay_us(5);
LCD_EN=1;
DDRC=0x07;
delay_us(5);
address=PINC&0x70;
LCD_EN=0;
delay_us(5);
LCD_EN=1;
delay_us(5);
address_l=PINC&0xF0;
address_l= address_l>>4;
address=address|address_l|0x80;
LCD_EN=0;
LCD_RD=0;
PORTC&=0x08;
DDRC|=0xF7;
return address;
}
//**********************************************
//设定CGRAM地址
//**********************************************
void lcd_set_cgram_address(char address)
{
char db;
db=0x04|(address>>4);
lcd_setport(0,0,db);
db=address;
lcd_setport(0,0,db);
}
//**********************************************
//设定DDRAM地址
//*********************************************
void lcd_set_ddram_address(char address)
{
char db;
db=(0x08|(address>>4))&0x0B;
lcd_setport(0,0,db);
db=address;
lcd_setport(0,0,db);
}
//**********************************************
//写数据到CGRAM 或DDRAM
//**********************************************
void lcd_write_ram(char data)
{
char db;
db=data>>4;
lcd_setport(1,0,db);
lcd_setport(1,0,data);
}
//**********************************************
//LCD初始化
//**********************************************
void lcd_inital(void)
{
//lcd_reset();
#asm("cli")
lcd_setport(0,0,0x03);
delay_ms(10);
lcd_setport(0,0,0x03);
delay_us(200);
lcd_setport(0,0,0x03);
delay_us(20);
lcd_setport(0,0,0x03);
delay_us(20);
// lcd_function_set(0); //使用LCD基本指令
lcd_setport(0,0,0x02);
lcd_setport(0,0,0x00);
// lcd_setport(0,0,0x02);
// lcd_on_off(1,1,0);
delay_us(10);
lcd_setport(0,0,0x00);
lcd_setport(0,0,0x0E);
// lcd_clear();
delay_us(10);
lcd_setport(0,0,0x00);
lcd_setport(0,0,0x01);
delay_us(10);
//lcd_entry_mode(1,0);
lcd_setport(0,0,0x00);
lcd_setport(0,0,0x06);
#asm("sei")
delay_ms(5);
}
//**********************************************
//设定显示位置
// x 列位置,范围1-8
// y 行位置,范围1-4
//**********************************************
void lcd_gotoxy(char x,char y)
{
char address;
switch ( y )
{
case 1:
address=0x80+x-1;
break;
case 2:
address=0x90+x-1;
break;
case 3:
address=0x88+x-1;
break;
case 4:
address=0x98+x-1;
break;
default: break;
}
lcd_set_ddram_address(address);
}
//**********************************************
//显示一个字符
//**********************************************
void lcd_putc(unsigned char c)
{
lcd_write_ram(c);
}
//**********************************************
//显示一个字符串
//**********************************************
voidlcd_putsf(charflash *str)
{
char address;
for(;;)
{
if((*str)==0)
break;
else
{
address=lcd_read_address();
if(address==0x87)
{
lcd_putc(*str);
str++;
if(*str==0)
break;
lcd_putc(*str);
str++;
if(*str==0)
break;
lcd_gotoxy(1,2);
}
if(address==0x97)
{
lcd_putc(*str);
str++;
if(*str==0)
break;
lcd_putc(*str);
str++;
if(*str==0)
break;
lcd_gotoxy(1,3);
}
if(address==0x8F)
{
lcd_putc(*str);
str++;
if(*str==0)
break;
lcd_putc(*str);
str++;
if(*str==0)
break;
lcd_gotoxy(1,4);
}
lcd_putc(*str);
str++;
}
}
}
//**********************************************
//在指定行显示一个字符串,
//字符串长度小于16个字符或8个汉字
//**********************************************
void lcd_putsf_line(charflash *str,char line)
{
char i;
lcd_gotoxy(1,line);
for(i=0;i<=15;i++)
{
if(*str==0)
break;
else
{
lcd_putc(*str);
str++;
}
}
lcd_on_off(1,0,0);
}
//**********************************************
//整屏显示一个字符串,
//字符串长度小于64个字符或32个汉字
//**********************************************
void lcd_put_page(charflash *str)
{
lcd_clear();
lcd_gotoxy(1,1);
lcd_putsf(str);
} 谢谢Paul!!!
我真可以好好参考一下里面的时序...
您的网名与21IC的张明峰的别名Paul一样...很高兴有您的帮助...谢谢!!! 这点东西还要谢吗?有用就好。如果你有改进再贡献出来,对我也有好处的,予人方便==予己方便嘛。 刚发现【12楼】的PDF上的引脚说明好象与板子上标的不符。。。
不知哪个正确???
郁闷之中。。。 晕!!!!!!!!!!!!!!!!!!!!!!!!!!太RZ了...
竟然SS没设置输出方式!!!!!!!!!!!!!!!!!!!!
错误程序
void SPI_MasterInit(void)
{
/* 设置MOSI 和SCK 为输出,其他为输入 */
DDRB = (1 << MOSI) | (1 << SCK);//??????????????????
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式3*/
SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << CPHA) | (1 << SPR0);
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式2*/
//SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << SPR0);
}
改错程序
void SPI_MasterInit(void)
{
/* 设置MOSI 和SCK 及SS为输出,其他为输入 */
DDRB = (1 << MOSI) | (1 << SCK) | (1 << SS);//!!!
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式3*/
SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << CPHA) | (1 << SPR0);
/* 使能SPI 主机模式,设置时钟速率为fck/16 ,SPI方式2*/
//SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << SPR0);
} 我用过一个ST7920的是四行的。
用的是CodeVision的编译器。
今天没带来,下次将源码贴上。希望对大家能有用。
我个人认为还是自己写一下液晶函数。比较好,不同型号的液晶之间还是有许多不同的,不好一言概之。 //彻底搞定,这里给个完整的HS12232-9的LCDTEST.C演示程序(M8L)
/*------------------------------------------------------------
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>
#defineFREQ 8//Meaga8L,8MHz
#defineCS PB2//LCD片选(串行) 0:禁止 1:允许
#defineSIDPB3//LCD输入串行数据(串行)
#defineCLKPB5//LCD输入串行脉冲(串行)
#defineSS PB2//LCD片选(串行) 0:禁止 1:允许
#defineMOSI PB3//LCD输入串行数据(串行)
#defineSCKPB5//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
}
} 郁闷是推销商也不懂...连J2必须跳线也不告诉我...让我一直找不到J2(焊点太小,老花眼看不见)...
自己真是个菜鸟呀...幸亏将它放了几天...等脑袋清醒了几秒钟就搞定了...
所以,郁闷时最好先灌几天水再下地... 有240*128的吗? 准备下周买个12864-12四行汉字的玩玩...还是玩SPI...
我比较喜欢串行接口,讨厌并行接口...见线多就眼晕... 恭喜hotpower了,这一段时间公司比较忙,刚刚看到贴子,所以没有在我系统上运行,./emotion/em009.gif ,不过你的程序可以作为我的参考了,哈哈!只是移植到ICC上! 有没有用过LM16032是TOPWAY的效果很好,背光很亮,就是没有中文的资料. avr/ina90.h是什么?系统里好像没有呢。 WINAVR20040720用
#include <avr/ina90.h>
WINAVR20050214用
#include <compat/ina90.h> 阿莫:
我手头正好有个MEGA128 驱动256*64(ST7920)的GCC程序.
我整理了一下,大家看看
原理图:
http://cache.amobbs.com/bbs_upload782111/files_4/armok0187406.GIF
实物图片:
http://cache.amobbs.com/bbs_upload782111/files_4/armok0187407.gif
GCC源程序:
点击此处下载armok0187408.rar
-----此内容被wzhscj于2005-11-18,23:34:08编辑过 to; hotpower 菜农
郁闷啊! 我用的是LM3033-128x64 LCD原来是用并口驱动一点问题都没有,现在响应你的号召改成串口并用spi驱动,一个星期都搞不定。硬件我查了N遍都没问题,确定是程序问题
程序是参考你的。
//CVAVR 1.24.8d por
#include <mega16.h>
#include <delay.h>
#include <spi.h>
#define SS PORTB.4//RS
#define MOSI PORTB.5//RW
#define SCKPORTB.7//SCLK
char QQ[]="OK";
void lcd_write_com(char com)
{
SS=1;
spi(0xf8);
spi(com & 0xf0);
spi(com<<4);
SS=0;
if(com==0x01) delay_ms(2);
delay_us(72);
}
void lcd_write_data(char data)
{
SS=1;
spi(0xfa);
spi(data & 0xf0);
spi(data<<4);
SS=0;
delay_us(72);
}
void lcd_init(void)
{
delay_ms(1000);
lcd_write_com(0x20); //发送4位控制命令
lcd_write_com(0x02); //发送位址归位命令,设定DDRAM位址计数器为0
lcd_write_com(0x04); //发送进入点命令
lcd_write_com(0x0c); //发送开显示关光标命令
lcd_write_com(0x01); //发送清除显示命令
lcd_write_com(0x80); //发送设定DDRAM地址0x00命令
}
char lcd_gotoxy(char x, char y)
{
if ((x < 2) && (y < 8))//汉字字符为2行7.5列(汉字必须偶数对齐)
{
lcd_write_com(0x80 + x * 16 + y);//发送设定DDRAM地址row * 16 + col命令
return 1;//成功返回
}
else
return 0;//失败返回
}
void lcd_xy_string(char x, char y, char *string)
{
if (lcd_gotoxy(x, y))
{
lcd_write_data(*string);
}
}
void lcd_string(char *string)
{
while(*string)
lcd_write_data(*string ++);
}
void main(void)
{
PORTB=0x00;
DDRB=0xB0;
SPCR=0x5D;
SPSR=0x00;
lcd_init();
delay_ms(1000);
lcd_write_com(0x01);
lcd_gotoxy(0,1);
lcd_string(QQ);
while (1)
{
};
}
请帮忙看看错在那里啊! 难道要我换回并口的,那就对不起<hotpower 菜农>大哥了。
-----此内容被huangdongle于2006-03-25,19:22:27编辑过
-----此内容被huangdongle于2006-03-25,19:25:43编辑过
-----此内容被huangdongle于2006-03-25,19:27:01编辑过 惭愧啊!原来犯了低级错误,接错脚了,现在可以了。./emotion/em148.gif
谢谢<hotpower 菜农>的例程! 哈哈...最近农忙~~~
这个例程我已经用过12232,12864,19264.
并且在51,avr,arm上都是用SPI/SSP...非常好用~~~ 哎呀,太感谢hotpower同志了。。。。。人民不会忘记你滴。。。。。。。 哈哈~~~19232也很简单.以下是我将AVR移植到ARM的例程.
主要是LcdDisplayBuffer()函数的差异,它是操作显示刷新的唯一函数,这样不会出现乱码.
哈哈,再移植回AVR也很方便...我从AVR移植到ARM也就10分钟吧~~~
//__inline
void LcdObj::LcdSpiInit(void)
{
/* 设置MOSI 和SCK 及SS 为输出,其他为输入 */
LCDPORT->IODIR |= (1 << LCDCS);
LCDPORT->IOCLR = (1 << LCDCS);
/*
LCDPORT->IODIR |= (1 << LCDSCK)| (1 << LCDSID);//设置输出方式
LCDPORT->IOSET = (1 << LCDSCK) | (1 << LCDSID);
*/
POWER->P_CONP |= (1 << PCSPI0);
PINSEL->PIN_SEL0 |= ((P0_4_SCK0 << P0_4_PINSEL) | (P0_6_MOSI0 << P0_6_PINSEL));
//SPI->SPI_SPCCR = 0x168; // 设置SPI时钟分频
SPI->SPI_SPCCR = 0x52; // 设置SPI时钟分频
SPI->SPI_SPCR=
(1 << CPHA) | // CPHA = 1, 数据在SCK 的第一个时钟沿采样
(1 << CPOL) | // CPOL = 1, SCK 为低有效
(1 << MSTR) | // MSTR = 1, SPI 处于主模式
(0 << LSBF) | // LSBF = 0, SPI 数据传输MSB (位7)在先
(0 << SPIE); // SPIE = 0, SPI 中断被禁止
}
//__inline
void LcdObj::LcdInit(void)
{
/*---------------------------------------------------
LCD模块上电等待延时
----------------------------------------------------*/
LcdClearBuffer();
LcdSendCommand(0x20);//发送4位控制命令
//LcdSendCommand(0x30);//发送8位控制命令//与8位4位无关!!!
LcdSendCommand(0x02);//发送位址归位命令,设定DDRAM位址计数器为0
LcdSendCommand(0x04);//发送进入点命令
LcdSendCommand(0x0c);//发送开显示关光标命令
LcdSendCommand(0x01);//发送清除显示命令
LcdSendCommand(0x80);//发送设定DDRAM地址0x00命令
}
//__inline
void LcdObj::LcdSend(char cData)
{
/*
unsigned int i;
_delay_loop_(1);
for (i = 0; i < 8; i ++) {
_delay_loop_(1);
LCDPORT->IOCLR = (1 << LCDSCK);
_delay_loop_(1);
if (cData & 0x80) {//MSB最高位为1时
LCDPORT->IOSET = (1 << LCDSID);
}
else {
LCDPORT->IOCLR = (1 << LCDSID);
}
_delay_loop_(1);
cData <<= 1;
LCDPORT->IOSET = (1 << LCDSCK);
_delay_loop_(1);
}
*/
//
SPI->SPI_SPDR = cData; //发送数据(相当于51的SBUF = DATA)
while(!(SPI->SPI_SPSR & (1 << SPIF))); // 等待SPIF置位,即等待数据发送完毕
//
}
/*--------------------------------------------------------
发送8位LCD控制命令
--------------------------------------------------------*/
//__inline
void LcdObj::LcdSendCommand(char cCommand)
{
/*--------------------------------------------------------
发送同步脉冲11111 WR(0) RS(0) 0发送顺序从左至右)
--------------------------------------------------------*/
LCDPORT->IOSET = (1 << LCDCS);//SS=1,启动SPI
LcdSend(0xf8);//发送LCD控制命令
LcdSend(cCommand & 0xf0);//发送高4位LCD控制命令
LcdSend(cCommand << 4);//发送低4位LCD控制命令
LCDPORT->IOCLR = (1 << LCDCS);//SS=0,关闭SPI
if (cCommand == 0x01) _delay_loop_(160);//1.6mS
else _delay_loop_(72);//st7920要求等待72uS
}
/*--------------------------------------------------------
发送8位LCD显示数据
--------------------------------------------------------*/
//__inline
void LcdObj::LcdSendData(char cData)
{
/*--------------------------------------------------------
发送同步脉冲11111 WR(0) RS(0) 0发送顺序从左至右)
--------------------------------------------------------*/
LCDPORT->IOSET = (1 << LCDCS);//SS=1,启动SPI
LcdSend(0xfa);//发送LCD显示数据
LcdSend(cData & 0xf0);//发送高4位LCD显示数据
LcdSend(cData << 4);//发送低4位LCD显示数据
LCDPORT->IOCLR = (1 << LCDCS);//SS=0,关闭SPI
_delay_loop_(72);//st7920要求等待延时72uS
}
//__inline
void LcdObj::SetLcdDisplayPos(unsigned char row, unsigned char col)
{
row &= 0x01;//2行汉字
if (col > 24) col = 0;//每行12个汉字24个字符
LcdRow = row;
LcdCol = col;
LcdRowWriteEnable = 1;//允许此行刷新汉字显示
}
//__inline
void LcdObj::LcdClearBuffer(void)
{
unsigned char i, j;
for (i = 0;i < 2;i ++) {
for (j = 0;j < 24; j ++) {
LcdBuffer = ' ';
}
LcdRowWriteEnable = 1;//允许此行刷新汉字显示
}
LcdRow = 0;
LcdCol = 0;
}
//__inline
void LcdObj::LcdDisplayBuffer(void)
{
unsigned char i, j;
for (i = 0; i < 2; i ++) {//2行汉字
if (LcdRowWriteEnable) {//允许此行刷新汉字显示
LcdSendCommand(0x80 + (i & 1) * 16 + (i >> 1) * 8);//移动光标
for (j = 0; j < 16; j ++) {//每行8个汉字16个字符
LcdSendData(LcdBuffer);//刷新显示字符
}
LcdSendCommand(0x80 + (i & 1) * 16 + ((i + 2) >> 1) * 8);//移动光标
for (j = 16; j < 24; j ++) {//每行4个汉字8个字符
LcdSendData(LcdBuffer);//刷新显示字符
}
LcdRowWriteEnable = 0;//过后不允许此行刷新汉字显示
}
}
}
//__inline
void LcdObj::LcdDisplay(const char * string)
{
while(*string) {
LcdBuffer = *string ++;
}
}
//__inline//(不敢加inline)
//__forceinline
void LcdObj::LcdDisplay(unsigned int Val, unsigned char size1, signed char size0)
{
char str, *ptr;
unsigned char i;
ptr = str + 5;
if (size0 > 0) {//有小数
for (i = 0; i < 3; i ++) {
*ptr -- = (Val % 10) + '0';
Val /= 10;
}
ptr = 0;
*ptr -- = '.';
}
else {
*ptr -- = 0;
}
for (i = 0; i < size1; i ++) {
if (i && (Val == 0)) {
if (size0 < 0) {
*ptr -- = '0';
}
else {
*ptr -- = ' ';
}
}
else *ptr -- = (Val % 10) + '0';
Val /= 10;
}
LcdDisplay(ptr + 1);
}
void LcdObj::LcdDisplay(unsigned int worknum)
{
char str;
sprintf(str, "%02d-%02d %02d:%02d %02d:%02d:%02d", Rtc.WorkMonth, Rtc.WorkDom, Rtc.WorkHour, Rtc.WorkMin, Rtc.WorkHour, Rtc.WorkMin, Rtc.WorkSec);
LcdDisplay(str);
} hotpower 菜农请问一下你用ARM控制这个的时候使用ARTX了么?
我想在操作系统下使用,SPI工作于中断方式
可是这个72us的延时很恼火~~~
不知道该如何处理为好 从开始搞ARM就用了ARTX.
至于SPI实在没意思~~~
这个思路在51/AVR/ARM/DSP上用软硬件不同方式都运行的相当稳定可靠~~~更没有"花屏"的现象~~~
McBSP模块配置为LCD12864的SPI接口 wogudan及楼上各位:
大家好!我是成都飞宇达公司的,如果需要FYD12864-0402B液晶模块,请和联系。
价格绝对优惠,如果有5K的量,可以作到60.00元/块。
我的联系方式:123@cdfyd.com 028-81704326 13880508896 www.cdfyd.com "经过我的测试串行方式,在cs无效时,7920还是可以接受数据,导致显示被误改,如果spi上接了其它器件,小心使用。"
我也发现手头上的这片LCD有同样的问题了,请问有人有解决方法吗?不想改PCB了。
按数据手册CS=0时是不可能被干扰的,是不是硬件bug? 这个程序不能显示变量的值呢?比如定义一个变量a,设a的值是98,应该怎样写语句来让它显示出来,谢谢各位,我是菜鸟,按照hotpower大侠的东西试过了,显示汉字很正常,就是不知道怎样显示变量的值。 我来上传个给你吧 mega16的AD转换+串行驱动12864显示电压值
说明:1、我AD使用外部TL431的5V基准
2、使用的是IO口驱动
3、编译器ICCAVR
点击此处下载ourdev_206112.rar(文件大小:66K) 不错的资料,顶 牛帖,,赶紧MARK下 mark下远古贴 串行做了个,系统老是液晶容易出现乱码
很郁闷 找不到原因 maqrk 凡老帖出来 罪过
12232一直用STM32调不出来
页:
[1]