ODR//unsignedchartable1[]={"65"};unsignedchartable2[]={"大学"};unsignedchartable3[]={"学院"};unsignedchart" />
#include "stm32f10x.h"
#define read_busybit() GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_7 )
#define DATAOUT GPIOC->ODR//
unsigned char table1[]={"65"};
unsigned char table2[]={"大学"} ;
unsigned char table3[]={"学院"} ;
unsigned char table4[]={"电子信息"} ;
unsigned char table5[]={"姓名"} ;
unsigned char hy5;
unsigned char k=0;
void delay(unsigned int x)
{
while(x--);
}
// 外设时钟使能
/*************************************************************************/
void RCC_Configuration(void) //在208页这里是引脚时钟配置
{
/* 使能外设时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 |
RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC |
RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
}
/****************************************************************************** *
全部用到1602的引脚将在在配置
******************************************************************************* /
void GPIO_Configuration(void) // 1602引脚配置
GPIO_InitTypeDef GPIO_InitStructure;
/* LD1 & LD2 & LD3 & LD4 configration */
GPIO_InitStructure.GPIO_Pin
=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GP IO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//矩阵键盘引脚输出配置
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure );
//矩阵键盘引脚输入配置
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_13|GPIO_Pin_11|GPIO_Pin_7|GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
void key()//按键检测
{
unsigned char ii,jj;
unsigned int key[10][10];
u16 ling[]={GPIO_Pin_7,GPIO_Pin_6,GPIO_Pin_11,GPIO_Pin_13};
u16 heng[]={GPIO_Pin_0,GPIO_Pin_1,GPIO_Pin_2,GPIO_Pin_9};
GPIO_SetBits(GPIOB,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_9);
for (ii=0;ii<4;ii++)
{
GPIO_ResetBits(GPIOB,heng[ii]);
for(jj=0;jj<4;jj++)
{
delay(50000);
delay(50000);
//delay(50000);
if(GPIO_ReadInputDataBit(GPIOB,ling[jj])==0)
{
while(GPIO_ReadInputDataBit(GPIOB,ling[jj]==0));
key[ii][jj]=1;
}
else
{
key[ii][jj]=0;
//delay(50000);
}
}
GPIO_SetBits(GPIOB,heng[ii]);
}
if((key[0][0]==1)&&(GPIO_ReadInputDataBit(GPIOB,ling[0])==1)){hy5=1;} //**** if((key[0][1]==1)&&(GPIO_ReadInputDataBit(GPIOB,ling[0])==1)){hy5=2;}
if((key[0][2]==1)&&(GPIO_ReadInputDataBit(GPIOB,ling[0])==1)){hy5=3;}
if((key[0][3]==1)&&(GPIO_ReadInputDataBit(GPIOB,ling[0])==1)){hy5=4;}
if((key[1][0]==1)&&(GPIO_ReadInputDataBit(GPIOB,ling[1])==1)){hy5=5;} //***
if((key[1][1]==1)&&(GPIO_ReadInputDataBit(GPIOB,ling[1])==1)){hy5=6;}
if((key[1][2]==1)&&(GPIO_ReadInputDataBit(GPIOB,ling[1])==1)){hy5=7;}
if((key[1][3]==1)&&(GPIO_ReadInputDataBit(GPIOB,ling[1])==1)){hy5=8;}
if((key[2][0]==1)&&(GPIO_ReadInputDataBit(GPIOB,ling[2])==1)){hy5=9;} //***** if((key[2][1]==1)&&(GPIO_ReadInputDataBit(GPIOB,ling[2])==1)){hy5=10;}
if((key[2][2]==1)&&(GPIO_ReadInputDataBit(GPIOB,ling[2])==1)){hy5=11;}
if((key[2][3]==1)&&(GPIO_ReadInputDataBit(GPIOB,ling[2])==1)){hy5=12;}
if((key[3][0]==1)&&(GPIO_ReadInputDataBit(GPIOB,ling[3])==1)){hy5=13;} //***** if((key[3][1]==1)&&(GPIO_ReadInputDataBit(GPIOB,ling[3])==1)){hy5=14;}
if((key[3][2]==1)&&(GPIO_ReadInputDataBit(GPIOB,ling[3])==1)){hy5=15;}
if((key[3][3]==1)&&(GPIO_ReadInputDataBit(GPIOB,ling[3])==1)){hy5=16;}
// hy2=9;
// return hy2;
//
}
void LCD_DataIo_In(void)//数据线输入1602 输入引脚配置
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPI O_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE, &GPIO_InitStructure);
}
void LCD_DataIo_Out(void)//数据线输出1602引脚输出配置
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPI O_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE, &GPIO_InitStructure);
}
void hy()
{
GPIO_ResetBits(GPIOE,GPIO_Pin_7);
GPIO_ResetBits(GPIOE,GPIO_Pin_6);
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
GPIO_ResetBits(GPIOE,GPIO_Pin_4);
GPIO_ResetBits(GPIOE,GPIO_Pin_3);
GPIO_ResetBits(GPIOE,GPIO_Pin_2);
GPIO_ResetBits(GPIOE,GPIO_Pin_1);
GPIO_ResetBits(GPIOE,GPIO_Pin_0);
}
void GPIO_Cofiguration_12864(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4 |GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5 ;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOD,&GPIO_InitStructure);
}
void LCD_12864_in(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4 |GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure);
}
void LCD_12864_out(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4 |GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure);
}
void readbusy_12864()
{
LCD_12864_in();
GPIO_ResetBits(GPIOD,GPIO_Pin_1); // rs
GPIO_SetBits(GPIOD,GPIO_Pin_2); // rw
GPIO_SetBits(GPIOD,GPIO_Pin_3); //en
while(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_7));
GPIO_ResetBits(GPIOD,GPIO_Pin_3);
LCD_12864_out();
}
void hy2()
{
GPIO_ResetBits(GPIOC,GPIO_Pin_0);
GPIO_ResetBits(GPIOC,GPIO_Pin_1);
GPIO_ResetBits(GPIOC,GPIO_Pin_2);
GPIO_ResetBits(GPIOC,GPIO_Pin_3);
GPIO_ResetBits(GPIOC,GPIO_Pin_4);
GPIO_ResetBits(GPIOC,GPIO_Pin_5);
GPIO_ResetBits(GPIOC,GPIO_Pin_6);
GPIO_ResetBits(GPIOC,GPIO_Pin_7);
}
/****************************************************************************** *
******************************************************************************* /
void NVIC_Configuration(void)
{
}
/****************************************************************************** *
初始化时钟晶振72MHZ
******************************************************************************* /
void SysClock_Init(void) //上半部分在196页
{
ErrorStatus HSEStartUpStatus;
RCC_DeInit();
RCC_HSEConfig(RCC_HSE_ON); //这个函数表示选择外部晶振作为时钟源
HSEStartUpStatus = RCC_WaitForHSEStartUp(); //
if(HSEStartUpStatus == SUCCESS){ //等待外部晶振起振
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);//开打预取指缓存使能
FLASH_SetLatency(FLASH_Latency_2); //2延时周期。设一个flash的等待状态。时钟过快要在这里等待
RCC_HCLKConfig(RCC_SYSCLK_Div1); //设置主时钟。设置AHB时钟(HCLK)AHB时钟=系统时钟
RCC_PCLK2Config(RCC_HCLK_Div1); // 设置高速的AHB时钟(PCLK2),APB2时钟=HCLK (RCC_HCLK_Div1)
RCC_PCLK1Config(RCC_HCLK_Div2); //设置低速的AHB时钟(PCLK1),AHB1时钟=HCLK/2
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);//PLL的输入时钟=HSE时钟频率(RCC_PLLSource_HSE_Div1),PLL输入时钟X9(RCC_PLLMul_9)//这里如果晶振是8MHZ时,RCC_PLLMul_9表示通过锁相环倍频9倍,此时晶振变为8MHZ*9=72MHZ,就变为72MHZ。此时主时钟就是72MHZ (RCC_HCLKConfig(RCC_SYSCLK_Div1); )
//此时上面的RCC_PCLK2Config(RCC_HCLK_Div1) 也为72MHZ,还有上面的RCC_PCLK1Config(RCC_HCLK_Div2);时钟就变为76MHZ/2=36MHZ
RCC_PLLCmd(ENABLE);// 使能或者失能PLL 在这里是使能
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){
//RCC_FLAG_PLLRDY是PLL就绪
;
}
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);//选择PLL做为系统时钟(RCC_SYSCLKSource_PLLCLK)
while(RCC_GetSYSCLKSource() != 0x08){ //RCC_GetSYSCLKSource功能是返回用作系统时钟的时钟源,0x08表示PLL作为系统时钟
// ;
}
}
}
/******************************************
*
*
*
****************************************/
/****************************************************
读忙函数
****************************************************/
//unsigned char readbusy() //读忙函数
void readbusy()
{
//unsigned char result;
LCD_DataIo_In();
//GPIO_SetBits(GPIOE,GPIO_Pin_7);
GPIO_ResetBits(GPIOA,GPIO_Pin_1); //rs=0
GPIO_SetBits(GPIOA,GPIO_Pin_2); //rw=1
GPIO_SetBits(GPIOA,GPIO_Pin_3); //en=1
//delay(5000);
while(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_7 ));
//result=read_busybit();
GPIO_ResetBits(GPIOA,GPIO_Pin_3); //en=0
//return result;
LCD_DataIo_Out();
}
void write_12864_cmd(unsigned char a11) //写指令
{
//while(readbusy()) ;
readbusy_12864() ;
hy2();
GPIO_ResetBits(GPIOD,GPIO_Pin_1); //rs=0
GPIO_ResetBits(GPIOD,GPIO_Pin_2); //rw=0
GPIO_ResetBits(GPIOD,GPIO_Pin_3);
//GPIO_ResetBits(GPIOA,GPIO_Pin_3);
delay(5000 );
DATAOUT=a11;
GPIO_SetBits(GPIOD,GPIO_Pin_3);//1
delay(5000 );
GPIO_ResetBits(GPIOD,GPIO_Pin_3); //0
}
void write_12864_data(unsigned char data11) //写数据{
//unsigned int j=256;
// while((readbusy())&&(j--));
// while(readbusy());
readbusy_12864();
hy2();
delay(5000 );
GPIO_ResetBits(GPIOD,GPIO_Pin_3);
GPIO_SetBits(GPIOD,GPIO_Pin_1) ; //rs=1
GPIO_ResetBits(GPIOD,GPIO_Pin_2);//rw=0
delay(5000 );
DATAOUT=data11;
GPIO_SetBits(GPIOD,GPIO_Pin_3);//1
delay(5000 );
GPIO_ResetBits(GPIOD,GPIO_Pin_3); //0
}
void init_12864()
{
//
GPIO_ResetBits(GPIOD,GPIO_Pin_5);//这是12864的复位键
//delay(5000 );
GPIO_SetBits(GPIOD,GPIO_Pin_4);
GPIO_SetBits(GPIOD,GPIO_Pin_5);
write_12864_cmd(0x30);
delay(5000 );
write_12864_cmd(0x30);
delay(5000 );
write_12864_cmd(0x30);
delay(5000 );
write_12864_cmd(0x06);
delay(5000 );
write_12864_cmd(0x01);
delay(5000 );
write_12864_cmd(0x0c);
delay(5000 );
//write_12864_cmd(0x02);
}
void weizhi_12864(unsigned char a1,unsigned char a2) {
unsigned char x;
if(a1==1)
{
a1=0x80;
}
else if(a1==2)
{
a1=0x90;
}
else if(a1==3)
{
a1=0x88;
}
else if(a1==4)
{
a1=0x98;
}
x=a1+a2;
write_12864_cmd(x) ;
}
void writeby(unsigned char a1,unsigned char a2)
{
readbusy();
hy();
GPIO_ResetBits(GPIOA,GPIO_Pin_1); //rs =0
GPIO_ResetBits(GPIOA,GPIO_Pin_2);
GPIO_ResetBits(GPIOA,GPIO_Pin_3);
if(a2==0)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_1); //rs =0
GPIO_ResetBits(GPIOA,GPIO_Pin_2); //rw=0
}
if(a2==1)
{
GPIO_SetBits(GPIOA,GPIO_Pin_1); //rs=1
GPIO_ResetBits(GPIOA,GPIO_Pin_2); //rw=0 }
if(a1&0x80)
{
GPIO_SetBits(GPIOE,GPIO_Pin_7) ;
}
else
{
GPIO_ResetBits(GPIOE,GPIO_Pin_7);
}
if(a1&0x40)
{
GPIO_SetBits(GPIOE,GPIO_Pin_6) ; //等于1的意思}
else
{
GPIO_ResetBits(GPIOE,GPIO_Pin_6);
}
if(a1&0x20)
{
GPIO_SetBits(GPIOE,GPIO_Pin_5) ;
}
else
{
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
}
if(a1&0x10)
{
GPIO_SetBits(GPIOE,GPIO_Pin_4) ;
}
else
{
GPIO_ResetBits(GPIOE,GPIO_Pin_4);
}
GPIO_SetBits(GPIOA,GPIO_Pin_3);
delay(5000 );
GPIO_ResetBits(GPIOA,GPIO_Pin_3);
hy();
if((a1<<4)&0x80)
{
GPIO_SetBits(GPIOE,GPIO_Pin_7) ;
}
else
{
GPIO_ResetBits(GPIOE,GPIO_Pin_7);
}
if((a1<<4)&0x40)
{
GPIO_SetBits(GPIOE,GPIO_Pin_6) ; //等于1的意思}
else
{
GPIO_ResetBits(GPIOE,GPIO_Pin_6);
}
if((a1<<4)&0x20)
{
GPIO_SetBits(GPIOE,GPIO_Pin_5) ;
}
else
{
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
}
if((a1<<4)&0x10)
{
GPIO_SetBits(GPIOE,GPIO_Pin_4) ;
}
else
{
GPIO_ResetBits(GPIOE,GPIO_Pin_4);
}
GPIO_SetBits(GPIOA,GPIO_Pin_3);
delay(5000 );
GPIO_ResetBits(GPIOA,GPIO_Pin_3);
}
/********************************************************
1602的定义
********************************************************/ void init()
{
writeby(0x28,0);
writeby(0x28,0);
writeby(0x28,0);
writeby(0x01,0);
writeby(0x02,0);
writeby(0x0C,0);
writeby(0x06,0);
}
/******************************************************* MAIN 函数
*******************************************************/ int main(void)
{
// unsigned char pp=0;
SysClock_Init(); // 初始化系统时钟72MHZ
RCC_Configuration(); // 使能外设GPIO_Configuration(); // 配置引脚GPIO_Cofiguration_12864();
init();
delay(20000 );
writeby(0xc0,0);
delay(20000 );
writeby(0x30+1,1);
delay(40000);
k=0;
while(table1[k]!=0)
{
writeby(table1[k],1);
//Delay(2);
delay(5000 );
k++;
}
delay(10000 );
init_12864();
delay(20000 );
weizhi_12864(1,0);
delay(10000 );
k=0;
while(table2[k]!='\0')
{
write_12864_data(table2[k]);
delay(5000 );
k++;
}
delay(10000 );
weizhi_12864(2,0);
delay(10000 );
k=0;
while(table3[k]!='\0')
{
write_12864_data(table3[k]);
delay(5000 );
k++;
}
delay(10000 );
weizhi_12864(3,0);
delay(10000 );
k=0;
while(table4[k]!='\0')
{
write_12864_data(table4[k]);
delay(5000 );
k++;
}
delay(10000 );
weizhi_12864(4,0);
delay(10000 );
k=0;
while(table5[k]!='\0')
{
write_12864_data(table5[k]);
delay(5000 );
k++;
}
while(1)
{
//key();
key();//按键检测
//下面是lcd12864显示程序
writeby(0x80,0);
writeby(0x30+hy5/10,1);
writeby(0x30+hy5%10,1);
delay(60000);
delay(60000);
delay(60000);
}
}
本例程为通过用A T89C52芯片操作LCD12864显示的程序,使用的晶振为12M。 /********************************************************** 程序说明:LCD12864显示主程序 程序调试员:莫剑辉 调试时间:2010-6-7 **********************************************************/ #include ;实验目的:熟悉12864LCD的使用 ;12864LCD带中文字库 ;编程让12864LCD显示公司名称“深圳乾龙盛电子”,公司电话“0975”,公司传真“6”;硬件设置: ;关断所有拨码开关。 #include<> ;__CONFIG _DEBUG_OFF&_CP_ALL&_WRT_HALF&_CPD_ON&_LVP_OFF&_BODEN_OFF&_PWRTE_ON&_WDT_OFF&_H S_OSC ;芯片配置字,看门狗关,上电延时开,掉电检测关,低压编程关,加密,4M晶体HS振荡 #define RS PORTA,5 ;命令/数据选择 #DEFINE RW PORTA,4 ;读/写选择 #DEFINE E PORTA,3 ;使能信号 #DEFINE PSB PORTA,2 ;并口/串口选择(H/L) #DEFINE RST PORTA,0 ;复位信号 ;----------------------------------------------- LCD_X EQU 30H ;页地址 LCD_Y EQU 31H ;Y地址 COUNT EQU 32H ;循环计数用 COUNT1 EQU 33H ;循环计数用 COUNT2 EQU 34H ;循环计数用 POINT EQU 35H ;查表偏移地址 POINT1 EQU 36H ;查表偏移地址 POINT2 EQU 37H ;查表偏移地址 TEMP EQU 38H ;临时寄存器 TEMP1 EQU 39H ;临时寄存器 ;----------------------------------------------- ORG 0000H ;复位地址 NOP ;ICD需要的空指令 GOTO MAIN ;跳转到主程序 ;**********************主程序************************ MAIN BANKSEL TRISA CLRF TRISA ;A口输出 CLRF TRISD ;D口输出 BANKSEL ADCON1 MOVLW 06H MOVWF ADCON1 ;A口全为数字口 CLRF STATUS 51单片机综合学习 12864液晶原理分析1 辛勤学习了好几天,终于对12864液晶有了些初步了解~没有视频教程学起来真有些累,基本上内部程序写入顺序都是根据程序自我变动,然后逆向反推出原理…… 芯片:YM12864R P-1 控制芯片:ST7920A带中文字库 初步小结: 1、控制芯片不同,寄存器定义会不同 2、显示方式有并行和串行,程序不同 3、含字库芯片显示字符时不必对字符取模了 4、对芯片的结构地址一定要理解清楚 5、显示汉字时液晶芯片写入数据的顺序(即显示的顺序)要清楚 6、显示图片时液晶芯片写入数据的顺序(即显示的顺序)要清楚 7、显示汉字时的二级单元(一级为八位数据写入单元)要清楚 8、显示图片时的二级单元(一级为八位数据写入单元)要清楚 12864点阵液晶显示模块(LCM)就是由128*64个液晶显示点组成的一个128列*64行的阵列。每个显示点对应一位二进制数,1表示亮,0表示灭。存储这些点阵信息的RAM称为显示数据存储器。要显示某个图形或汉字就是将相应的点阵信息写入 到相应的存储单元中。图形或汉字的点阵信息由自己设计,问题的关键就是显示点在液晶屏上的位置(行和列)与其在存储器中的地址之间的关系。由于多数液晶显示模块的驱动电路是由一片行驱动器和两片列驱动器构成,所以12864液晶屏实际上是由左右两块独立的64*64液晶屏拼接而成,每半屏有一个512*8 bits显示数据RAM。左右半屏驱动电路及存储器分别由片选信号CS1和CS2选择。显示点在64*64液晶屏上的位置由行号(line,0~63)与列号(column,0~63)确定。512*8 bits RAM中某个存储单元的地址由页地址(Xpage,0~7)和列地址(Yaddress,0~63)确定。每个存储单元存储8个液晶点的显示信息。 方法一、 ORG 0000H LJMP MAIN ORG 0100H MAIN: MOV P1,#0F0H //P1口设初值F0,矩阵按键高四位置1,低四位置0, JNB P1.4,Y0 //用JNB检测按键端口,P1.4口低电平跳转 Y0 JNB P1.5,Y1 JNB P1.6,Y2 JNB P1.7,Y3 SJMP MAIN Y0: MOV 30H,#00H MOV P1,#0EFH JNB P1.4,X0 MOV P1,#0DFH JNB P1.4,X1 MOV P1,#0BFH JNB P1.4,X2 MOV P1,#07FH JNB P1.4,X3 Y1: MOV 30H,#01H MOV P1,#0EFH JNB P1.0,X0 MOV P1,#0DFH JNB P1.1,X1 MOV P1,#0BFH JNB P1.2,X2 MOV P1,#7FH JNB P1.3,X3 Y2: MOV 30H,#02H MOV P1,#0EFH JNB P1.0,X0 MOV P1,#0DFH JNB P1.1,X1 MOV P1,#0BFH JNB P1.2,X2 MOV P1,#7FH JNB P1.3,X3 Y3: MOV 30H,#03H MOV P1,#0EFH MOV P1,#0DFH JNB P1.1,X1 MOV P1,#0BFH JNB P1.2,X2 MOV P1,#7FH JNB P1.3,X3 X0: MOV 31H,#00H ACALL DELAY MOV P1,#0F0H LJMP JISUAN X1: MOV 31H,#01H ACALL DELAY MOV P1,#0F0H LJMP JISUAN X2: MOV 31H,#02H ACALL DELAY MOV P1,#0F0H LJMP JISUAN X3: MOV 31H,#03H ACALL DELAY MOV P1,#0F0H LJMP JISUAN JISUAN: MOV A,31H MOV B,#04H MUL AB ADD A,30H MOV DPTR,#TAB MOVC A,@A+DPTR MOV P0,A CC: MOV A,P1 ANL A,#0F0H XRL A,#0F0H JNZ CC LCALL MAIN DELAY: MOV R4,#0C5H D1: MOV R5,#43H D0: MOV R6,#10H 在我们常用的人机交互显示界面中,除了数码管,LED,以及我们之前已经提到的LCD1602之外,还有一种液晶屏用的比较多。相信接触过单片机的朋友都知道了,那就是12864液晶。顾名思义,12864表示其横向可以显示128个点,纵向可以显示64个点。我们常用的12864液晶模块中有带字库的,也有不带字库的,其控制芯片也有很多种,如KS0108 T6963,ST7920等等。在这里我们以ST7920为主控芯片的12864液晶屏来学习如何去驱动它。(液晶屏采用金鹏的OCMJ4X8C) 关于这个液晶屏的更多信息,请参考它的DATASHEET,附件中有下载。 我们先来了解一下它的并行连接情况。 下面是电路连接图 从上面的图可以看出,液晶模块和单片机的连接除了P0口的8位并行数据线之外,还有RS,RW,E等几根线。其中R/S是指令和数据寄存器的选择控制线(串行模式下为片选),R/W 是读写控制线(串行模式下是数据线),E是使能线(串行模式下为时钟线)。 通过这几根控制线和数据线,再结合它的时序图,我们就可以编写出相应的驱动程序啦。 看看并行模式下的写时序图: 根据这个时序图,我们就可以写出写数据或者写命令到LCD12864液晶的子程序。 读时序图如下: 根据这个时序图我们就可以从LCD12864液晶模块内部RAM中读出相应的数据,我们的忙检测函数就是根据这个时序图写出来的。以及后面章节中讲的画点函数等都要用到读时序。有了这两个时序图,然后我们再看看OCMJ4X8C的相关指令集,就可以编写出驱动程序了。这里要注意的是指令集分为基本指令集和扩充指令集,其中扩充指令集主要是与绘图相关,在此后的章节中会有相应的介绍。 下面让我们根据这些编写出它的驱动程序吧。 我的硬件测试条件为:STC89C516(11.0592MHz) + OCMJ4X8C 实际显示效果图片如下: 程序部分如下,请结合液晶模块的DATASHEET看程序,这样能够更加快速的弄懂程序的流程。大致有如下几个函数:写数据,写指令,忙检测,初始化,指定地址显示字符串等等。[p][/p] #include "reg52.h" #include "intrins.h" sbit io_LCD12864_RS = P1^0 ; /****************************** 2012年5月19日 调试成功 编辑环境:ICCAVR 功能:用LCD12864显示汉字 ********************************/ #include 本例程为通过用AT89C52芯片操作LCD12864显示的程序,使用的晶振为12M。 /********************************************************** 程序说明:LCD12864显示主程序 程序调试员:莫剑辉 调试时间:2010-6-7 **********************************************************/ #include 键盘是单片机常用输入设备,在按键数量较多时,为了节省I/O口等单片机资源,一般采取扫描的方式来识别到底是哪一个键被按下。即通过确定被按下的键处在哪一行哪一列来确定该键的位置,获取键值以启动相应的功能程序。 4*4矩阵键盘的结构如图1(实物参考见万用板矩阵键盘制作技巧)。在本例中,矩阵键盘的四列依次接到单片机的P1.0~P1.3,四行依次接到单片机的P1.4~P1.7;同时,将列线上拉,通过10K电阻接电源。 查找哪个按键被按下的方法为:一个一个地查找。 先第一行输出0,检查列线是否非全高; 否则第二行输出0,检查列线是否非全高; 否则第三行输出0,检查列线是否非全高; 如果某行输出0时,查到列线非全高,则该行有按键按下; 根据第几行线输出0与第几列线读入为0,即可判断在具体什么位置的按键按下。 下面是具体程序: void Check_Key(void) { unsigned char row,col,tmp1,tmp2; tmp1 = 0x10; //tmp1用来设置P1口的输出,取反后使 P1.4~P1.7中有一个为0 for(row=0;row<4;row++) // 行检测 { P1 = 0x0f; // 先将p1.4~P1.7置高 P1 =~tmp1; // 使P1.4~p1.7中有一个为0 tmp1*=2; // tmp1左移一位 if ((P1 & 0x0f) < 0x0f) // 检测P1.0~P1.3中是否有一位为0,只要有,则说明此行有键按下,进入列检测 { tmp2 = 0x01; // tmp2用于检测出哪一列为0 for(col =0;col<4;col++) // 列检测 { if((P1 & tmp2)==0x00) // 该列如果为低电平则可以判定为该列 { key_val =key_Map[ row*4 +col ]; // 获取键值,识别按键;key_Map为按键的定义表 return; // 退出循环 } tmp2*=2; // tmp2左移一位 } } } } //结束 这是一种比较经典的矩阵键盘识别方法,实现起来较为简单,程序短小精炼。 看到工具箱旁边那个LCD12864很久没用了(当初买回来用的时候只是简单地测试了一下),于是萌生了重新写一次接口程序的想法(而且这次要给它加个图片显示的功能),好,说做就做,就用Atmega16和ICCAVR来做吧,最近这MCU和平台用得比较熟练。 马上从书堆里把当初打印出来的中文datasheet给翻了出来,依葫芦画瓢地写了个初始化程序。好,OK。编译通过。于是又写了一个可以自定义从XY坐标值开始输出显示的函数,再次编译,也通过,OK。于是呼马上写了四行简单的字符烧到单片机上试了一下,嘿嘿,一次通过。如下图: 后来在进一步测试的时候也出了点小问题。就是我是使用USBISP烧写器把程序烧写进AVR的(此时实验板由USBISP烧写器供电),想要实现从第一行的第一个字符开始连续显示"0123456789"。刚烧写完程序后能看到LCD12864上正常显示"0123456789",但是把烧写器从实验板上断开连接,单独用USB给实验板供电的时候,LCD的第一行只是显示"123456789",第一个字符消失了……,左思右想地弄了一个多小时后,终于把问题给解决了,就是把初始化程序的延时适当增加了些,真是奇怪。刚开始一直想不通为什么在烧写器供电的情况下就正常显示,而换到USB供电后就出了问题。后来再想想,估计是跟供电有关。在使用USBISP烧写器供电的时候,LCD的背光灯明显比用USB供电的时候来得亮,而且对比度也高很多,看来是因为换到USB供电后,供电不怎么充足,以至于LCD在上电初始化的时候花上了更多的时间去初始化(因为供电低了,功率小了,跑起来有点力不从心,用的时间就久了嘛……我是觉得可以这样去理解的 接下来呢,就到了有点难度的画图了。当初刚买到12864的时候只是简单测试了字符显示功能,除了因为画图还不需要用到,另外一个原因就是那datasheet上关于画图那部分的内容不怎么看得懂…。现在重新拿起来看,依然一头雾水……。马上上网百度了一下“12864 7920 显示图片”,看到了不少的例子程序,可是……就是没看到有关于这部分功能实现的详细思路和讲解……下载下来的那些程序,基本上没注释,不是说晦涩难懂,但是至少看起来一团糟,让人家不想继续看下去……于是还是硬着头皮去啃那datasheet。上面对于画图这部分的内容是这样讲解的: 基于STM32--LCD12864驱动程序 STM32 LCD12864驱动程序(头文件)(2012-05-29 21:25:08)转载▼ 标签:杂谈 #ifndef LCD12864_H #define LCD12864_H #define LCD_CONTROL GPIOD //默认LCD12864的控制口在PD口 #define LCD_DATAPORT GPIOD //默认LCD12864的数据口在PD口 #define LCD_RESET_Pin GPIO_Pin_12 //默认LCD12864的复位引脚连接到PD.12 也可不用 #define LCD_RS_Pin GPIO_Pin_13 //默认LCD12864 RS -- PD.13 #define LCD_RW_Pin GPIO_Pin_14 //默认LCD12864 RW -- PD.14 #define LCD_EN_Pin GPIO_Pin_15 //默认LCD12864 E -- PD.15 #define LCD_CONTROL_CLOCK RCC_APB2Periph_GPIOD //默认LCD12864的控制口时钟 #define LCD_DATAPORT_CLOCK RCC_APB2Periph_GPIOD //默认LCD12864的数据口时钟 #define LCD_RS_1 LCD_CONTROL->BSRR &=~LCD_RS_Pin;LCD_CONTROL->BSRR |=LCD_RS_Pin //RS置高电平 #define LCD_RS_0 LCD_CONTROL->BRR &=~LCD_RS_Pin;LCD_CONTROL->BRR |=LCD_RS_Pin //RS置低电平 #define LCD_RW_1 LCD_CONTROL->BSRR &=~LCD_RW_Pin;LCD_CONTROL->BSRR |=LCD_RW_Pin //RW置高电平 #define LCD_RW_0 LCD_CONTROL->BRR &=~LCD_RW_Pin;LCD_CONTROL->BRR |=LCD_RW_Pin //RW置低电平 #define LCD_EN_1 LCD_CONTROL->BSRR &=~LCD_EN_Pin;LCD_CONTROL->BSRR |=LCD_EN_Pin //EN置高电平 #define LCD_EN_0 LCD_CONTROL->BRR &=~LCD_EN_Pin;LCD_CONTROL->BRR |=LCD_EN_Pin //EN置低电平 用12864显示单色图片 首先介绍本12864液晶显示器: 型号:QC12864B 因为单片机读取的是数据,而不是直接的图片。得将图片进行取模,图片应该是单色图片,像素128*64。 下面我为大家介绍个实例。 ①、在电脑附件画图,首先设置属性 开始画图 保存文件,注意格式: ②、然后进行取模。 ③、编程: #include /*编译环境:Keil 7.50A c51 */ /*******************************************************/ /*********************************包含头文件********************************/ #include LCD12864原理与应用 1、LCD12864简介: LCD12864分为两种,带字库的和不带字库的,不带字库的液晶显示汉字的时候可以选择自己喜欢的字体。而带字库的液晶,只能显示GB2312字体,当然也可以显示其他的字体,不过是用图片的形式显示。 下面介绍不带字库的LCD12864,以Proteus中的AMPIRE128×64为例,如下图所示,它的液晶驱动器为KS0108。 与带字库的液晶不同,此块液晶含有两个液晶驱动器,每块驱动器都控制64*64个点,分为左右两个屏幕显示,总共为128*64个点(即有128×64个点)。这就是为什么AMPIRE128*64有CS1和CS2两个片选端的原因。此液晶有8页,一页有8行点阵点,左右各64列,共128列。如下图所示: 2、LCD12864中的几条重要指令 (一)行(line)设置命令: 由此可见显示的起始行地址为0XC0,共64行,有规律地改变起始行号,可以实现滚屏效果。(二)页(page)设置指令: 起始页地址为0XB8,因为液晶有64行点,分为8页,每页就有8行点。 (三)列(column)地址设置指令 每块驱动器的列地址都是从0X40到0X7F,共64列,所以此液晶共有128列点。 (四)读状态指令 3、用LCD12864显示汉字(一) 由于这块液晶不带字库,我们就要自己编写字库,编写字库所用的字模提取软件为Zimo21(软件下载地址https://www.docsj.com/doc/e715162569.html,/),LCD1602显示自定义字符的时候也是用它。在取模之前我们要进行一些设定,根据此液晶的显示原理,设置为“纵向取模,字节倒序”,如下图所示:(若不是这样,则取模得到的数据不是我们想要的,将会出现乱码,同样可以在https://www.docsj.com/doc/e715162569.html,/下载到关于字模提取原理文档) 字体选择默认的“宋体,常规,小四号”,小四号为16*16大小,如下图所示: LCD12864图形液晶并口显示 【教学引入】 液晶屏,在生活中很常见,我们常见的液晶显示器,如电脑的显示器,电视机,手机等等。 液晶屏在生活中已得到了普遍应用,它显示个各种各样的画面。 【教学目标】 1、掌握LCD12864液晶屏的用法; 2、编写LCD12864液晶屏的指令代码; 【知识目标】 1、掌握LCD12864液晶屏的用法; 2、掌握LCD12864液晶屏指令代码; 【教学准备】 电脑、Proteus、Keil 【教学方法】 教法:讲授法、讨论法 学法:练习法、探究法 【教学课时】 四课时 【教学过程】 一、12864液晶介绍 (1)12864是128*64点阵液晶模块的点阵数简称,业界约定俗成的简称。12864点阵的屏显成本相对较低,适用于各类仪器,小型设备的显示领域。12864M汉字图形点阵液晶显示模块,可显示汉字及图形,内置8192个中文汉字(16X16点阵)、128个字符(8X16点阵)及64X256点阵显示RAM(GDRAM)。 12864引脚说明 查阅“12864M.PDF”12864M液晶显示模块技术手册——四、用户指令集 1、指令表1:(RE=0:基本指令表),如下图,讲解了12864的基本指令集和扩充指令集。 当模块在接受指令前,微处理器必须先确认模块内部处于非忙碌状态,即读取BF标志时BF需为0。“RE”为基本指令集与扩充指令集的选择控制位元,往后的指令集将维持在最后的状态。 当选择G=0 :绘图显示OFF,汉字显示的时,12864屏只能显示8X4=32个汉字,下面是汉字显示的坐标 二、12864液晶屏驱动电路 原件名称所属类(Category) 所属子类(Sub-category) AT89C52 Microprocessor ICs 8051 Family POT-HG Resistors Variable RESPACK-8 Resistors Resistor Packs LCD12864A 自制- AT89C52的P0口连接12864的并行数据口,RP1为P0口的上拉排阻。 三、52代码编写 (1)打开keil uVision4,建立一个新的工程,工程名为"12864 graphic LCD parallel display",保存类型*.uvproj,单片机型号AT89C52。在工程中添加12864 graphic LCD parallel display.c文件,如下图 /*风清云扬*/ # include } else if(temp0==0x0b) { switch (temp1) { case 0xe0: num=12;break; case 0xd0: num=11;break; case 0xb0: num=10;break; case 0x70: num=9;break; default:num=0;break; } } else if(temp0==0x07) { switch (temp1) { case 0xe0: num=16;break; case 0xd0: num=15;break; case 0xb0: num=14;break; case 0x70: num=13;break; default:num=0;break; } } } } return num; } void main() { char num; while(1) { num=key_scan(); P2=num/10; P3=num%10; } } #include X4扫描式矩阵键盘课程设计 (总13页) -CAL-FENGHAI.-(YICAI)-Company One1 -CAL-本页仅作为文档封面,使用请直接删除 4X4扫描式矩阵键盘课程设计 课程设计名称: 4_4扫描式矩阵键盘设计 姓名: DUKE 班级:电子1008班 学号: 10086 成绩: 日期: 2014年1月6日 摘要 随着21世纪的到来,电子信息行业将是人类社会的高科技行业之一,式设施现代化的基础,也是人类通往科技巅峰的直通路。电子行业的发展从长远来看很重要,但最主要的还是科技问题。 矩阵式键盘提高效率进行按键操作管理有效方法,它可以提高系统准确性,有利于资源的节约,降低对操作者本身素质的要求。是它能准时、实时、高效地显示按键信息,以提高工作效率和资源利用率。 矩阵式键盘乃是当今使用最为广泛的键盘模式,该系统以N个端口连接控制N*N 个按键,显示在LED数码管上。单片机控制依据这是键盘显示系统,该系统可以对不同的按键进行实时显示,其核心是单片机和键盘矩阵电路部分,主要对按键与显示电路的关系、矩阵式技术及设备系统的硬件、软件等各个部分进行实现。 4*4矩阵式键盘采用AT89C51单片机为核心,主要由矩阵式键盘电路、译码电路、显示电路等组成,软件选用C语言编程。单片机将检测到的按键信号转换成数字量,显示于LED显示器上。该系统灵活性强,易于操作,可靠性高,将会有更广阔的开发前景。 目录 第一章:系统功能要求-------------------------------------------------------- 4*4 矩阵式键盘系统概述------------------------------------------------ 本设计任务和主要内容--------------------------------------------------- 第二章:方案论证--------------------------------------------------------------- 第三章:系统硬件电路的设计------------------------------------------------ 单片机控制系统原理----------------------------------------------------- 原理图绘制说明---------------------------------------------------------- 画出流程图---------------------------------------------------------------- 原理图绘制--------------------------------------------------------------- 第四章:系统程序的设计------------------------------------------------------ 程序的编写步骤-----------------------------------------------------------LCD12864显示程序
12864液晶显示图片原理(完整版)
汇编矩阵键盘程序
玩转12864液晶(1)--显示字符
LCD12864写字符串程序及其头文件
LCD显示程序
经典的矩阵键盘扫描程序
12864显示图形
基于STM32--LCD12864驱动程序
在12864显示任意图片及参考程序
矩阵键盘程序c程序,51单片机.
LCD12864原理与应用(源程序+原理图+proteus仿真)
LCD12864图形液晶并口显示
51单片机矩阵键盘程序
12864液晶显示程序(图案+文字)
X4扫描式矩阵键盘课程设计