问题1:12864在显示图片和显示字符状态下地址编码是不同的
绘图模式下的坐标分布,每个坐标对应一个16位数据,数据为水平分布,左侧位MSB,所以每行就是16*8=128,纵向为32+32=64
//
80,80+0 81,80+0 82,80+0 83,80+0 84,80+0 85,80+0 86,80+0 87,80+0
上 …
半 .
屏 …
80,80+31 81,80+31 80,80+31 83,80+31 84,80+31 85,80+31 86,80+31 87,80+31
//
88,80+0 89,80+0 8A,80+0 8B,80+0 8C,80+0 8D,80+0 8E,80+0 8F,80+0
下 …
半 .
屏 …
88,80+31 89,80+31 8A,80+31 8B,80+31 8C,80+31 8D,80+31 8E,80+31 8F,80+31
/
字符显示地址分布
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F
问题2:并行状态下的数据和指令写入,必须进行E信号线的由高到低的跳变
void LCD_Write_com(uint8_t com)
{
// Delay_ms(5);
LCD_ReadyWait();
// Delay_ms(10);
GPIO_WriteBit(GPIOB,RS,Bit_RESET); //指令 RS=0
GPIO_WriteBit(GPIOB,RW,Bit_RESET); //写 R/W=0
GPIO_WriteBit(GPIOB,E,Bit_RESET); //使能 E=高电平
write_LCD12864(com); //写命令
GPIO_WriteBit(GPIOB,E,Bit_SET); //使能 E=高电平
Delay_ms(5);
GPIO_WriteBit(GPIOB,E,Bit_RESET); //不使能
}
void LCD_Write_data(uint8_t data)
{
Delay_ms(10);
GPIO_WriteBit(GPIOB,RS,Bit_SET); //数据 RS=1
GPIO_WriteBit(GPIOB,RW,Bit_RESET); //写 R/W=0
GPIO_WriteBit(GPIOB,E,Bit_RESET); //使能 E=高电平
write_LCD12864(data); //写数据
GPIO_WriteBit(GPIOB,E,Bit_SET); //使能 E=高电平
Delay_ms(5);
GPIO_WriteBit(GPIOB,E,Bit_RESET); //不使能
}
问题3:串行状态下的时序
看懂这个图就能很了解串行的数据传输,,写的2条控制字都可以正常使用,读的状态字可能是能力不足,没有实现,有能力的可以自己尝试下怎么回事。不过没有这2个读的命令也能实现图片和字符的显示
问题4:绘图模式下的bmp图像
可以通过Pctolcd2002生成,在绘制bmp图像时要设置128*64,生成二进制数组时要选择逐行式和顺向取模;阳码,阴码都可以
上源码
最后加一句,并行使用的线特别多,并且传输速度很慢,说实话我不知道为什么比串行的图片刷新速度还慢,很慢,如果是一开始没有显示就稍微等待一会儿;优先使用串行吧
#include "12864.h"
#include "Delay.h"
/*
并行接线
VSS:GND
VDD:+5V
VO:空接
NC:空接
vout:空接
led+:+5v
led-:gnd
==================
B9:并行数据/指令选择RS
B8:并行读写选择R/W
B7:并行使能E
PA0:DB0
PA1:DB1
PA2:DB2
PA3:DB3
PA4:DB4
PA5:DB5
PA6:DB6
PA7:DB7
B10:并行串行选择PSB
B11:复位
*/
/*
绘图模式下的坐标分布,每个坐标对应一个16位数据,数据为水平分布,左侧位MSB,所以每行就是16*8=128,纵向为32+32=64
======================================================
80,80+0 81,80+0 82,80+0 83,80+0 84,80+0 85,80+0 86,80+0 87,80+0
上 ...
半 .
屏 ...
80,80+31 81,80+31 80,80+31 83,80+31 84,80+31 85,80+31 86,80+31 87,80+31
=====================================================
88,80+0 89,80+0 8A,80+0 8B,80+0 8C,80+0 8D,80+0 8E,80+0 8F,80+0
下 ...
半 .
屏 ...
88,80+31 89,80+31 8A,80+31 8B,80+31 8C,80+31 8D,80+31 8E,80+31 8F,80+31
=====================================================
字符显示地址分布
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F
*/
#ifdef Parallel
void GPIO_12864_Init ( void )
{
RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOB,ENABLE ) ;
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;
GPIO_InitStructure.GPIO_Pin = RS|RW|E|PSB|RST;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ;
GPIO_Init ( GPIOB,&GPIO_InitStructure) ;
GPIO_SetBits(GPIOB,RST);
GPIO_SetBits(GPIOB,PSB);
}
void LED12864_DB_out(void)
{
RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOA,ENABLE ) ;
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = LCD_DATA;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void LED12864_DB_in(void)
{
RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOA,ENABLE ) ;
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = LCD_DATA;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void write_LCD12864(uint8_t data)
{
GPIOA->ODR &= (~(0x00FF));
GPIOA->ODR |= data;
}
uint8_t read_LCD12864(void)
{
uint8_t value;
value= (GPIO_ReadInputData(GPIOA) & 0X00FF );
return value;
}
uint8_t LCD_ReadyWait(void)
{
uint16_t state;
uint8_t j = 0 ;
Delay_ms(10);
GPIO_WriteBit(GPIOB,RS,Bit_RESET); //指令 RS=0
GPIO_WriteBit(GPIOB,RW,Bit_SET); //读数据 R/W=1
do
{
if ( j == 255 )
break;
GPIO_WriteBit(GPIOB,E,Bit_SET); //使能 E=1
LED12864_DB_in(); //配置数据口为上拉输入模式
state =read_LCD12864(); //查忙标志位,等待标志位为0,表示写入完毕;为1,表示忙状态
LED12864_DB_out(); //配置数据口为输 出模式
GPIO_WriteBit(GPIOA,E,Bit_RESET); //不使能 E=0
j++;
} while( state & 0x80);
if( j==255 )
return 0 ;
else
return 1 ;
}
void LCD_Write_com(uint8_t com)
{
// Delay_ms(5);
LCD_ReadyWait();
// Delay_ms(10);
GPIO_WriteBit(GPIOB,RS,Bit_RESET); //指令 RS=0
GPIO_WriteBit(GPIOB,RW,Bit_RESET); //写 R/W=0
GPIO_WriteBit(GPIOB,E,Bit_RESET); //使能 E=高电平
write_LCD12864(com); //写命令
GPIO_WriteBit(GPIOB,E,Bit_SET); //使能 E=高电平
Delay_ms(5);
GPIO_WriteBit(GPIOB,E,Bit_RESET); //不使能
}
void LCD_Write_data(uint8_t data)
{
Delay_ms(10);
GPIO_WriteBit(GPIOB,RS,Bit_SET); //数据 RS=1
GPIO_WriteBit(GPIOB,RW,Bit_RESET); //写 R/W=0
GPIO_WriteBit(GPIOB,E,Bit_RESET); //使能 E=高电平
write_LCD12864(data); //写数据
GPIO_WriteBit(GPIOB,E,Bit_SET); //使能 E=高电平
Delay_ms(5);
GPIO_WriteBit(GPIOB,E,Bit_RESET); //不使能
}
void LCD_clear(void)
{
LCD_Write_com(0x01); //写清屏指令0x01
Delay_ms(10);
}
void display_DDRAM(uint8_t x,uint8_t y,char *s)
{
switch(y)
{
case 0:
LCD_Write_com(0x80+x); //第一行
break;
case 1:
LCD_Write_com(0x90+x); //第二行
break;
case 2:
LCD_Write_com(0x88+x); //第三行
break;
case 3:
LCD_Write_com(0x98+x); //第四行
break;
}
while(*s>0)
{
LCD_Write_data(*s++);
Delay_ms(10);
}
}
void display_CGRAM(uint8_t x,uint8_t y,uint8_t addr,unsigned char *s)
{
unsigned char i,*address;
address = s;
LCD_Write_com(0x40+addr); //写CGRAM首行地址,创建第几个自编字符就写第几个自编字符的地址
for(i = 0;i<32;i++)
{
LCD_Write_data(*address++);
}
switch(y)
{
case 0:
LCD_Write_com(0x80+x); //第一行
break;
case 1:
LCD_Write_com(0x90+x); //第二行
break;
case 2:
LCD_Write_com(0x88+x); //第三行
break;
case 3:
LCD_Write_com(0x98+x); //第四行
break;
}
LCD_Write_data(0x00); //写自定义字符编码的高字节
switch(addr)
{
case 0x00:
LCD_Write_data(0x00); //写第一个自定义字符编码的低字节
break;
case 0x10:
LCD_Write_data(0x02); //写第二个自定义字符编码的低字节
break;
case 0x20:
LCD_Write_data(0x04); //写第三个自定义字符编码的低字节
break;
case 0x30:
LCD_Write_data(0x06); //写第四个自定义字符编码的低字节
break;
}
}
void Lcd_12864_Init(void)
{
GPIO_WriteBit(GPIOB,RST,Bit_SET); //复位置高
Delay_ms(10);
GPIO_WriteBit(GPIOB,RST,Bit_RESET); //复位
Delay_ms(10);
GPIO_WriteBit(GPIOB,RST,Bit_SET); //复位结束
Delay_ms(10);
GPIO_WriteBit(GPIOB,PSB,Bit_SET); //选择并行
LCD_Write_com(0x30); //设置为基本指令集动作
// Delay_ms(10);
// LCD_Write_com(0x08); //设置显示、光标、闪烁全关。
//
// LCD_Write_com(0x01); //清屏,并且DDRAM数据指针清零
// LCD_Write_com(0x06); //进入模式设置
LCD_Write_com(0x0c); //开显示
LCD_Write_com(0x01); //清屏,并且DDRAM数据指针清零
Delay_ms(10);
}
void Draw_PM(const uint8_t *ptr)
{
uint8_t i,j,k;
LCD_Write_com(0x36); //打开扩展指令集
i=0x80;
for(j=0;j<32;j++)
{
LCD_Write_com(i++);
LCD_Write_com(0x80);
for(k=0;k<16;k++)
{LCD_Write_data(*ptr++);}
}
i = 0x80;
for(j=0;j<32;j++)
{
LCD_Write_com(i++);
LCD_Write_com(0x88);
for(k=0;k<16;k++)
{LCD_Write_data(*ptr++);}
}
LCD_Write_com(0x36); //打开绘图显示
LCD_Write_com(0x30); //回到基本指令集
}
//绘图模式下的清屏
void DRAW_clear ( void )
{
uint8_t i,j;
LCD_Write_com(0x36); //打开扩展指令集
for ( j = 0 ; j < 32; j++ )
{
LCD_Write_com(0x80+j); //先设行地址
LCD_Write_com(0x80); //再设置列地址
for ( i = 0 ; i < 32 ; i++ )
LCD_Write_data(0x00);
}
}
//绘图模式下点亮某一位置
/*
x:0x80~0x8F
y:0X80+0~0X80+32
show:
*/
void DRAW_show ( uint8_t x, uint8_t y,uint8_t* show )
{
LCD_Write_com(0x36); //打开扩展指令集
LCD_Write_com(y);
LCD_Write_com(x);
LCD_Write_data(show[0]);
LCD_Write_data(show[1]);
}
#else
/****************************串行***********************************/
//================================================================
void GPIO_12864_Init(void)
{
RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOB,ENABLE ) ;
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;
GPIO_InitStructure.GPIO_Pin = CS|SID|CLK|PSB|RST;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ;
GPIO_Init ( GPIOB,&GPIO_InitStructure) ;
/* 控制引脚初始状态全部输出低电平 */
GPIO_SetBits(GPIOB,RST);
GPIO_ResetBits(GPIOB,PSB); //选择串行
GPIO_ResetBits(GPIOB,CS|SID|CLK); //初始化3条传输线
}
void write_LCD12864(uint8_t data)
{
uint8_t i;
for(i = 0; i< 8; i++)
{
GPIO_WriteBit(GPIOB,CLK,Bit_RESET); //不使能
if((data <<i)&0x80)
{
GPIO_WriteBit(GPIOB,SID,Bit_SET); //写1
}
else
{
GPIO_WriteBit(GPIOB,SID,Bit_RESET); //写0
}
Delay_us(3); //延时使数据写入
GPIO_WriteBit(GPIOB,CLK,Bit_SET); //使能
Delay_us(3);
}
}
uint8_t read_LCD12864(void)
{
uint8_t value = 0;
uint8_t i = 0 ;
for ( i = 0 ; i < 8 ; i++ )
{
GPIO_WriteBit(GPIOB,CLK,Bit_SET); //使能
Delay_us(3);
if ( GPIO_ReadInputDataBit(GPIOB,SID) == 1 )
value++;
value = value << 1;
GPIO_WriteBit(GPIOB,CLK,Bit_RESET); //不使能
Delay_us(3);
GPIO_WriteBit(GPIOB,CLK,Bit_RESET); //不使能
Delay_us(3);
}
return value;
}
//这个函数好像没作用,但是不影响显示
uint8_t LCD_ReadyWait(void)
{
uint8_t H_STA;
uint8_t L_STA;
uint8_t STA;
uint8_t j = 0;
GPIO_WriteBit(GPIOB,CS,Bit_SET); //使能
Delay_ms(1);
do
{
if ( j == 255 )
break;
write_LCD12864(r_sta); // 读状态
H_STA = read_LCD12864();
L_STA = read_LCD12864();
STA = ((H_STA & 0XF0) | (L_STA & 0X0F));
j++;
}while (!(STA & 0X80));
if( j==255 )
return 0 ;
else
return 1 ;
}
void LCD_Write_com(uint8_t com)
{
GPIO_WriteBit(GPIOB,CS,Bit_SET); //使能
Delay_ms(1);
write_LCD12864(w_cmd); // 写命令
write_LCD12864(0xf0 & com); // 写高4位指令
write_LCD12864(com << 4); // 写低4位指令
GPIO_WriteBit(GPIOB,CS,Bit_RESET); //不使能
// LCD_ReadyWait( ) ;
}
void LCD_Write_data(uint8_t data)
{
GPIO_WriteBit(GPIOB,CS,Bit_SET); //使能
Delay_ms(1);
write_LCD12864(w_da); // 写数据
write_LCD12864(0xf0 & data); // 写高4位数据
write_LCD12864(data << 4); // 写低4位数据
GPIO_WriteBit(GPIOB,CS,Bit_RESET); //不使能
// LCD_ReadyWait( ) ;
}
void Lcd_12864_Init(void)
{
GPIO_WriteBit(GPIOB,RST,Bit_SET); //复位置高
Delay_ms(10);
GPIO_WriteBit(GPIOB,RST,Bit_RESET); //复位
Delay_ms(10);
GPIO_WriteBit(GPIOB,RST,Bit_SET); //复位结束
Delay_ms(10);
GPIO_WriteBit(GPIOB,PSB,Bit_RESET); //选择并行
LCD_Write_com(0x30); //设置为基本指令集动作
// Delay_ms(10);
// LCD_Write_com(0x08); //设置显示、光标、闪烁全关。
//
// LCD_Write_com(0x01); //清屏,并且DDRAM数据指针清零
// LCD_Write_com(0x06); //进入模式设置
LCD_Write_com(0x0c); //开显示
LCD_Write_com(0x01); //清屏,并且DDRAM数据指针清零
Delay_ms(10);
}
/*
x:0-7
y:0-3
*/
void display_DDRAM(uint8_t x,uint8_t y,char*s)
{
uint8_t cmd_add;
switch ( y )
{
case 0 :
{
cmd_add = 0x80 +x;
break ;
}
case 1 :
{
cmd_add = 0x90 +x;
break ;
}
case 2 :
{
cmd_add = 0x88 +x;
break ;
}
case 3 :
{
cmd_add = 0x98 +x;
break ;
}
default :break;
}
LCD_Write_com( cmd_add );
while(*s>0)
{
LCD_Write_data(*s); //写数据
s++;
}
}
//绘图模式下的清屏
void DRAW_clear ( void )
{
uint8_t i,j;
LCD_Write_com(0x36); //打开扩展指令集
for ( j = 0 ; j < 32; j++ )
{
LCD_Write_com(0x80+j); //先设行地址
LCD_Write_com(0x80); //再设置列地址
for ( i = 0 ; i < 32 ; i++ )
LCD_Write_data(0x00);
}
}
void Draw_PM(const uint8_t *ptr)
{
uint8_t i,j,k;
LCD_Write_com(0x36); //打开扩展指令集
i=0x80;
for(j=0;j<32;j++)
{
LCD_Write_com(i++);
LCD_Write_com(0x80);
for(k=0;k<16;k++)
{LCD_Write_data(*ptr++);}
}
i = 0x80;
for(j=0;j<32;j++)
{
LCD_Write_com(i++);
LCD_Write_com(0x88);
for(k=0;k<16;k++)
{LCD_Write_data(*ptr++);}
}
LCD_Write_com(0x36); //打开绘图显示
LCD_Write_com(0x30); //回到基本指令集
}
#endif
#ifndef __12864_H
#define __12864_H
#include "stm32f10x.h" // Device header
#include "stdio.h"
//#define Parallel 1 //并行串行区分
/***************************************************************************************
* LED12864模块
* 管脚号 管脚名称 LEVER 管脚功能描述
* 1 VSS 0 电源地
* 2 VDD +5.0V 电源电压
* 3 V0 液晶显示器驱动电压 //发现这个引脚好像空接,对比度最好
* 4 D/I(RS) H/L D/I=“H” 表示DB7∽DB0为数据
* D/I=“L” 表示DB7∽DB0为指令
* 5 R/W(SID) H/L R/W=“H”,E=“H”数据被读到DB7∽DB0
* R/W=“L”,E=“L”数据被写到DB7∽DB0
* 6 E(CLK) H/L R/W=“L”,E信号下降沿锁存DB7∽DB0
* R/W=“H”,E=“H”DDRAM数据读到DB7∽DB0
* 7 DB0 H/L 数据线
* 8 DB1 H/L 数据线
* 9 DB2 H/L 数据线
* 10 DB3 H/L 数据线
* 11 DB4 H/L 数据线
* 12 DB5 H/L 数据线
* 13 DB6 H/L 数据线
* 14 DB7 H/L 数据线
* 15 PSB(CS1) H/L 并/串行接口选择:H-并行 L-串行
* 16 NC(CS2) 空脚
* 17 RST H/L 复位信号,低电平复位
* 18 VOUT LCD驱动输出电压
* 19 LED+ + LED背光板电源
* 20 LED- - LED背光板电源
*********************************************************************************************/
#ifdef Parallel
#define RS GPIO_Pin_9 //数据/命令选择
#define RW GPIO_Pin_8 //读/写选择
#define E GPIO_Pin_7 //使能信号
#define PSB GPIO_Pin_10 //并行串行选择
#define RST GPIO_Pin_11 //复位引脚
#define LCD_DATA GPIO_Pin_0|GPIO_Pin_1| GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7 //数据线
#else
#define CS GPIO_Pin_9 //串行的片选线
#define SID GPIO_Pin_8 //串行数据线
#define CLK GPIO_Pin_7 //串行时钟线
#define PSB GPIO_Pin_10 //并行串行选择
#define RST GPIO_Pin_11 //复位引脚
#define w_cmd 0xF8
#define w_da 0xFA
#define r_sta 0xFC
#define r_da 0xFE
#endif
void GPIO_12864_Init ( void ) ;
void Lcd_12864_Init(void) ;
void display_DDRAM(uint8_t x,uint8_t y,char *s);
void display_CGRAM(uint8_t x,uint8_t y,uint8_t addr,unsigned char *s) ;
void LCD_Write_com(uint8_t com);
void LCD_Write_data(uint8_t data) ;
void Draw_PM(const uint8_t *ptr) ;
void DRAW_clear ( void ) ;
void DRAW_show ( uint8_t x, uint8_t y,uint8_t* show );
#endif