1.前言
最近搞在开一个新项目,核心在于低成本,于是重新看回了咱们的老朋友STC。不看不知道,一看吓一跳,STC出的芯片外设真全,涵盖了基础的各种外设。不过嘛,STC嘛,都熟悉。基本的外设很快上手了,不得不说姚总的芯片手册是真不错,各种情况都列举写在手册里了,硬件也挺简单的。不过有些地方还是美中不足的,比如这个LCM模块,库函数写的非常不完善,基本处于无法使用的情况。没办法,只能大改库了。
2.程序
我们先看一下原本的库函数
sbit LCD_RS = P4^5; //数据/命令切换
sbit LCD_WR = P4^2; //写控制
sbit LCD_RD = P4^4; //读控制
sbit LCD_CS = P3^4; //片选
sbit LCD_RESET = P4^3; //复位typedef struct
{u8 LCM_Enable; //LCM接口使能 ENABLE,DISABLEu8 LCM_Mode; //LCM接口模式 MODE_I8080,MODE_M6800u8 LCM_Bit_Wide; //LCM数据宽度 BIT_WIDE_8,BIT_WIDE_16u8 LCM_Setup_Time; //LCM通信数据建立时间 0~7u8 LCM_Hold_Time; //LCM通信数据保持时间 0~3
} LCM_InitTypeDef;
void LCM_Inilize(LCM_InitTypeDef *LCM)
{LCMIFSTA = 0x00;if(LCM->LCM_Mode == MODE_M6800) LCMIFCFG |= MODE_M6800; //LCM接口模式:M6800else LCMIFCFG &= ~MODE_M6800; //LCM接口模式:I8080if(LCM->LCM_Bit_Wide == BIT_WIDE_16) LCMIFCFG |= BIT_WIDE_16; //LCM数据宽度:16位else LCMIFCFG &= ~BIT_WIDE_16; //LCM数据宽度:8位if(LCM->LCM_Setup_Time <= 7) LCMIFCFG2 = (LCMIFCFG2 & ~0x1c) | (LCM->LCM_Setup_Time << 2); //LCM通信数据建立时间:0~7if(LCM->LCM_Hold_Time <= 3) LCMIFCFG2 = (LCMIFCFG2 & ~0x03) | LCM->LCM_Hold_Time; //LCM通信数据建立时间:0~7if(LCM->LCM_Enable == ENABLE) LCMIFCR |= 0x80; //使能LCM接口功能else LCMIFCR &= ~0x80; //禁止LCM接口功能
}
原本的库函数里面只有一个初始化函数,端口,中断都没有写。
首先我们从定义开始讲起
这里的管脚只保留片选和复位两个管脚,剩下的3个管脚均由硬件LCM模块控制。
然后是结构体的定义
我重新加入了控制管脚,数据管脚,中断的定义。这些都是下面重要的参数
然后是具体的设置函数
void init_lcd(void)
{LcdStruct->LCM_Enable=ENABLE; //启动LCM模块LcdStruct->LCM_Control_Pin=3; //控制管脚为第4种组合LcdStruct->LCM_Data_Pin=3; //数据管脚为第4种组合LcdStruct->LCM_Isr_Enable=ENABLE; //使能LCM中断LcdStruct->LCM_Mode=MODE_I8080; //I8080模式LcdStruct->LCM_Bit_Wide=BIT_WIDE_8; //8位数据宽带LcdStruct->LCM_Setup_Time=1; //建立时间为1个周期LcdStruct->LCM_Hold_Time=3; //保持时间为3个周期LCM_Inilize(LcdStruct); //将设置投入寄存器
}
首先是初始化,按照需要进行配置就可以了。这里放出一个参考程序我使用I8080模式,8位数据模式。
然后是发送数据和发送参数
void LCD_WR_CMD(unsigned int Cmd)
{if(LcdStruct->LCM_Bit_Wide==BIT_WIDE_8){LCMIFDATL = Cmd;}else{LCMIFDATL = Cmd&0xff;LCMIFDATH = Cmd>>8;}LCD_CS=0;LCMIFCR = 0x84; //启动总线 发送指令while(!LCD_CS);
} void LCD_WR_DATA(unsigned int Data)
{if(LcdStruct->LCM_Bit_Wide==BIT_WIDE_8){LCMIFDATL = Data;}else{LCMIFDATL = Data&0xff;LCMIFDATH = Data>>8;}LCD_CS=0;LCMIFCR = 0x85; //启动总线 发送数据while(!LCD_CS);
}
这个没什么很大的出入
然后是中断服务函数
void LCM_ISR_Handler (void) interrupt LCM_VECTOR
{// TODO: 在此处添加用户代码if(LCMIFSTA & 0x01){LCD_CS=1;LCMIFSTA = 0x00;LcmFlag = 0;}
}
注意一下CS管脚要在所有数据发送完毕后拉高
3.I8080波形
手册上给出了两张图
只能说比较抽象,我们来具体看一下实际的波形
我们单独分析一个数据来看
首先是控制管脚,左侧是发送命令,右侧是发送数据,唯一的区别在于RS,数据是高,命令是低,也与实际手册上一致。
然后是数据,因为是并行总线,所以单次发送的数据是8位。
4.结语
STC系列的硬件做的还是不错的,但是软件和现在发展迅猛的ARM系列还是有差距的,尤其是魔改过后的STC,存储,中断用起来都非常难受。特别是Keil,估计Keil官方也没有想到8051架构能魔改成这样,前面调用函数的时候原本外部参数放在idata里,结果都找不到,程序运行一半直接乱飞,后来通过反汇编查看地址才发现问题,最后把参数放到xdata里才解决,更难受的是编译器都找不到问题,直接下载更是找不到,要不是有stc-usb仿真就直接GG了,大家记得也注意这个问题。那么OK,估计STC的这个模块用的人也不是特别多,就不多说了,我们下一篇文章见。