基于HC32L136K8TA官方库开发的LCD12864低层驱动记录


前言

本工程案例为记录开发过程以及一些问题的解决


一、工程介绍:

本工程是在KELI环境中,直接引用官方的函数库进行开发。引脚的定义以及引用为本人通过多次测试后进行使用。

二、开发步骤

1.引入库(打开GPIO官方例子进行了修改)

在这里插入图片描述

2.GPIO引脚初始化

  • 宏定义:
#define CON_PORT  GpioPortB 
#define DAT_PORT  GpioPortA 
#define CS1       GpioPin0
#define CS2       GpioPin1
#define RS        GpioPin3
#define RW        GpioPin4
#define EN        GpioPin5
#define LIGHT     GpioPin6

#define Max_Column	128
#define Max_Line	8
#define OUT     0
#define IN      1
  • 控制脚:
static void App_LcdConInit(void)
{
    stc_gpio_cfg_t stcGpioCfg;

    Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);  //打开GPIO外设时钟

    stcGpioCfg.enDir = GpioDirOut;                          //端口方向配置->输出
    stcGpioCfg.enDrv = GpioDrvH;	                          //驱动能力配置->高驱动能力
    stcGpioCfg.enPu = GpioPuDisable;                        //端口上下拉配置->无
    stcGpioCfg.enPd = GpioPdDisable;
    stcGpioCfg.enOD = GpioOdDisable;                        //开漏输出配置->开漏输出关闭
    stcGpioCfg.enCtrlMode = GpioAHB;                        //总线控制模式配置->AHB

    Gpio_Init(CON_PORT, GpioPin0, &stcGpioCfg);             //< LCD控制引脚初始化
    Gpio_Init(CON_PORT, GpioPin1, &stcGpioCfg);
    Gpio_Init(CON_PORT, GpioPin3, &stcGpioCfg);
    Gpio_Init(CON_PORT, GpioPin4, &stcGpioCfg);
    Gpio_Init(CON_PORT, GpioPin5, &stcGpioCfg);
    Gpio_Init(CON_PORT, GpioPin6, &stcGpioCfg);
    Gpio_SetClrPort(CON_PORT,0x0000007a);                   //< LCD控制引脚关闭
}
  • 数据脚:
static void App_LcdDataInit(void)
{
    stc_gpio_cfg_t stcGpioCfg;

    Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);  //打开GPIO外设时钟

    stcGpioCfg.enDir = GpioDirOut;                           //端口方向配置->输出
    stcGpioCfg.enDrv = GpioDrvH;	                           //驱动能力配置->低驱动能力
    stcGpioCfg.enPu = GpioPdDisable;                         //端口上下拉配置->无
    stcGpioCfg.enPd = GpioPdDisable;
    stcGpioCfg.enOD = GpioPdDisable;                         //开漏输出配置->开漏输出关闭
    stcGpioCfg.enCtrlMode = GpioAHB;                         //总线控制模式配置->AHB
    Gpio_Init(DAT_PORT, GpioPin0, &stcGpioCfg);          // LCD数据引脚初始化
    Gpio_Init(DAT_PORT, GpioPin1, &stcGpioCfg);
    Gpio_Init(DAT_PORT, GpioPin2, &stcGpioCfg);
    Gpio_Init(DAT_PORT, GpioPin3, &stcGpioCfg);
    Gpio_Init(DAT_PORT, GpioPin4, &stcGpioCfg);
    Gpio_Init(DAT_PORT, GpioPin5, &stcGpioCfg);
    Gpio_Init(DAT_PORT, GpioPin6, &stcGpioCfg);
    Gpio_Init(DAT_PORT, GpioPin7, &stcGpioCfg);
    Gpio_SetClrPort(DAT_PORT,0x000000ff);                    //< LCD数据引脚关闭
}

3.主时钟初始化以及延时函数封装

  • 由于官方使用滴答时钟最小延时为10US,而屏幕的驱动需要的延时很低,故封装了一个简单的延时函数供工程使用:
/**
 * \brief   delay1us
 *          delay approximately 1us.
 * \param   [in]  u32Cnt
 * \retval  void
 */
void delay_1us(uint32_t u32Cnt)
{     	
    do
    {									   
				__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
				__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
				__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();__NOP();__NOP();			
    }
    while(--u32Cnt);
} 

4.驱动LCD函数(该方案比较稳当,但是驱动速度还可以提高,希望大神们多多指教):

void sendData(u8 dataPort,u8 data) //引用到该函数是为发送数据,可以使用其他函数替代。【如"Gpio_SetPort"或者“Gpio_SetClrPort”】
{
    if((data & 0x01) == 0x01)
        Gpio_SetIO(dataPort,GpioPin0);
    else
        Gpio_ClrIO(dataPort,GpioPin0);

    if((data & 0x02) == 0x02)
        Gpio_SetIO(dataPort,GpioPin1);
    else
        Gpio_ClrIO(dataPort,GpioPin1);

    if((data & 0x04) == 0x04)
        Gpio_SetIO(dataPort,GpioPin2);
    else
        Gpio_ClrIO(dataPort,GpioPin2);

    if((data & 0x08) == 0x08)
        Gpio_SetIO(dataPort,GpioPin3);
    else
        Gpio_ClrIO(dataPort,GpioPin3);

    if((data & 0x10) == 0x10)
        Gpio_SetIO(dataPort,GpioPin4);
    else
        Gpio_ClrIO(dataPort,GpioPin4);

    if((data & 0x20) == 0x20)
        Gpio_SetIO(dataPort,GpioPin5);
    else
        Gpio_ClrIO(dataPort,GpioPin5);

    if((data & 0x40) == 0x40)
        Gpio_SetIO(dataPort,GpioPin6);
    else
        Gpio_ClrIO(dataPort,GpioPin6);

    if((data & 0x80) == 0x80)
        Gpio_SetIO(dataPort,GpioPin7);
    else
        Gpio_ClrIO(dataPort,GpioPin7);
}

void dataPortReInit(u8 mode)//刚调试程序时,没有加入这一段函数,驱动屏幕有输出不拉低现象,使能LCD后数据BUSY依旧保持高电平
{
    stc_gpio_cfg_t stcGpioCfg;
    Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);     //打开GPIO外设时钟
    if(mode == IN)//输入
    {
        stcGpioCfg.enDir = GpioDirIn;                           //端口方向配置->输出
        stcGpioCfg.enDrv = GpioDrvH;	                          //驱动能力配置->低驱动能力
        stcGpioCfg.enPu = GpioPdDisable;                        //端口上下拉配置->无
        stcGpioCfg.enPd = GpioPdDisable;
        stcGpioCfg.enOD = GpioPdDisable;                        //开漏输出配置->开漏输出关闭
        stcGpioCfg.enCtrlMode = GpioAHB;                        //总线控制模式配置->AHB
        Gpio_Init(DAT_PORT, GpioPin0, &stcGpioCfg);             // LCD数据引脚初始化
        Gpio_Init(DAT_PORT, GpioPin1, &stcGpioCfg);
        Gpio_Init(DAT_PORT, GpioPin2, &stcGpioCfg);
        Gpio_Init(DAT_PORT, GpioPin3, &stcGpioCfg);
        Gpio_Init(DAT_PORT, GpioPin4, &stcGpioCfg);
        Gpio_Init(DAT_PORT, GpioPin5, &stcGpioCfg);
        Gpio_Init(DAT_PORT, GpioPin6, &stcGpioCfg);
        Gpio_Init(DAT_PORT, GpioPin7, &stcGpioCfg);
    }
    else   //输出
    {
        stcGpioCfg.enDir = GpioDirOut;                           //端口方向配置->输出
        stcGpioCfg.enDrv = GpioDrvH;	                           //驱动能力配置->低驱动能力
        stcGpioCfg.enPu = GpioPdDisable;                         //端口上下拉配置->无
        stcGpioCfg.enPd = GpioPdDisable;
        stcGpioCfg.enOD = GpioPdDisable;                         //开漏输出配置->开漏输出关闭
        stcGpioCfg.enCtrlMode = GpioAHB;                         //总线控制模式配置->AHB
        Gpio_Init(DAT_PORT, GpioPin0, &stcGpioCfg);              // LCD数据引脚初始化
        Gpio_Init(DAT_PORT, GpioPin1, &stcGpioCfg);
        Gpio_Init(DAT_PORT, GpioPin2, &stcGpioCfg);
        Gpio_Init(DAT_PORT, GpioPin3, &stcGpioCfg);
        Gpio_Init(DAT_PORT, GpioPin4, &stcGpioCfg);
        Gpio_Init(DAT_PORT, GpioPin5, &stcGpioCfg);
        Gpio_Init(DAT_PORT, GpioPin6, &stcGpioCfg);
        Gpio_Init(DAT_PORT, GpioPin7, &stcGpioCfg);
    }
}

void CheckBusy(void)
{
    u8 status;
    
    Gpio_ClrIO(CON_PORT,RS);
    delay_1us(1);
    Gpio_SetIO(CON_PORT,RW);
    delay_1us(1); 
    
    sendData(DAT_PORT,0x00FF); 
   
    delay_1us(1);
    dataPortReInit(IN); 
    do
    {
        Gpio_SetIO(CON_PORT,EN);               //开使能
        delay_1us(1);
        status = Gpio_GetInputIO(DAT_PORT,GpioPin7);//接收BF位,判断是否忙
    } while(status & 0X01);
    Gpio_ClrIO(CON_PORT,EN);
    dataPortReInit(OUT);
}

static void writecom(u8 l_or_r,u8 com)      //写指令  0是左边  1是右边  2是两边
{
    if(l_or_r >= 2)
    {
        CheckBusy();
        delay_1us(1);
        Gpio_SetIO(CON_PORT,CS1);            //选中左片选
        delay_1us(1);
        Gpio_ClrIO(CON_PORT,CS2);
        delay_1us(1);
        Gpio_ClrIO(CON_PORT,RS);            //写指令
        delay_1us(1);
        Gpio_ClrIO(CON_PORT,RW);            //读
        delay_1us(1);

        sendData(DAT_PORT,com);
        delay_1us(1);
        Gpio_SetIO(CON_PORT,EN);             //开使能
        delay_1us(10);                      //10us应该能发送完了
        Gpio_ClrIO(CON_PORT,EN);

        delay_1us(10);

        CheckBusy();
        delay_1us(1);
        Gpio_ClrIO(CON_PORT,CS1);            //选中左片选
        delay_1us(1);
        Gpio_SetIO(CON_PORT,CS2);
        delay_1us(1);
        Gpio_ClrIO(CON_PORT,RS);            //写指令
        delay_1us(1);
        Gpio_ClrIO(CON_PORT,RW);            //读
        delay_1us(1);

        sendData(DAT_PORT,com);
        delay_1us(1);
        Gpio_SetIO(CON_PORT,EN);             //开使能
        delay_1us(10);
        Gpio_ClrIO(CON_PORT,EN);
    }
    else
    {
        if(l_or_r == 1)
        {
            CheckBusy();
            delay_1us(1);
            Gpio_ClrIO(CON_PORT,CS1);            //选中左片选
            delay_1us(1);
            Gpio_SetIO(CON_PORT,CS2);
            delay_1us(1);
            Gpio_ClrIO(CON_PORT,RS);            //写指令
            delay_1us(1);
            Gpio_ClrIO(CON_PORT,RW);            //读
            delay_1us(1);

            sendData(DAT_PORT,com);
            delay_1us(1);
            Gpio_SetIO(CON_PORT,EN);             //开使能
            delay_1us(10);
            Gpio_ClrIO(CON_PORT,EN);
        }
        else
        {
            CheckBusy();
            delay_1us(1);
            Gpio_SetIO(CON_PORT,CS1);            //选中左片选
            delay_1us(1);
            Gpio_ClrIO(CON_PORT,CS2);
            delay_1us(1);
            Gpio_ClrIO(CON_PORT,RS);            //写指令
            delay_1us(1);
            Gpio_ClrIO(CON_PORT,RW);            //读
            delay_1us(1);

            sendData(DAT_PORT,com);
            delay_1us(1);
            Gpio_SetIO(CON_PORT,EN);             //开使能
            delay_1us(10);
            Gpio_ClrIO(CON_PORT,EN);
        }
    }
}

static void writedat(u8 l_or_r,u8 dat)      //写数据
{
    if(l_or_r >= 2)
    {
        CheckBusy();
        delay_1us(1);
        Gpio_SetIO(CON_PORT,CS1);            //选中左片选
        delay_1us(1);
        Gpio_ClrIO(CON_PORT,CS2);
        delay_1us(1);
        Gpio_SetIO(CON_PORT,RS);            //写指令
        delay_1us(1);
        Gpio_ClrIO(CON_PORT,RW);            //读
        delay_1us(1);

        sendData(DAT_PORT,dat);
        delay_1us(1);
        Gpio_SetIO(CON_PORT,EN);             //开使能
        delay_1us(10);
        Gpio_ClrIO(CON_PORT,EN);

        delay_1us(10);

        CheckBusy();
        delay_1us(1);
        Gpio_ClrIO(CON_PORT,CS1);            //选中左片选
        delay_1us(1);
        Gpio_SetIO(CON_PORT,CS2);
        delay_1us(1);
        Gpio_SetIO(CON_PORT,RS);            //写指令
        delay_1us(1);
        Gpio_ClrIO(CON_PORT,RW);            //读
        delay_1us(1);

        sendData(DAT_PORT,dat);
        delay_1us(1);
        Gpio_SetIO(CON_PORT,EN);             //开使能
        delay_1us(10);
        Gpio_ClrIO(CON_PORT,EN);
    }
    else
    {
        if(l_or_r == 1)
        {
            CheckBusy();
            delay_1us(1);
            Gpio_ClrIO(CON_PORT,CS1);            //选中左片选
            delay_1us(1);
            Gpio_SetIO(CON_PORT,CS2);
            delay_1us(1);
            Gpio_SetIO(CON_PORT,RS);            //写指令
            delay_1us(1);
            Gpio_ClrIO(CON_PORT,RW);            //读
            delay_1us(1);

            sendData(DAT_PORT,dat);
            delay_1us(1);
            Gpio_SetIO(CON_PORT,EN);             //开使能
            delay_1us(10);
            Gpio_ClrIO(CON_PORT,EN);
        }
        else
        {
            CheckBusy();
            delay_1us(1);
            Gpio_SetIO(CON_PORT,CS1);            //选中左片选
            delay_1us(1);
            Gpio_ClrIO(CON_PORT,CS2);
            delay_1us(1);
            Gpio_SetIO(CON_PORT,RS);            //写指令
            delay_1us(1);
            Gpio_ClrIO(CON_PORT,RW);            //读
            delay_1us(1);

            sendData(DAT_PORT,dat);
            delay_1us(1);
            Gpio_SetIO(CON_PORT,EN);             //开使能
            delay_1us(10);
            Gpio_ClrIO(CON_PORT,EN);
        }
    }
}

5.驱动LCD函数:

void clear_lcd(void)
{
    u8 x,y;
    for(x=0xb8; x<=0xbf; x++)
    {
        writecom(0,x);
        for(y=0x40; y<=0x80; y++)
        {
            writecom(0,y);
            writedat(0,0X00); //0X00
        }
    }

    for(x=0xb8; x<=0xbf; x++)
    {
        writecom(1,x);
        for(y=0x40; y<=0x80; y++)
        {
            writecom(1,y);
            writedat(1,0X00);
        }
    }
}

void lcd12864_init(void)
{
    writecom(2,0x3e);//全屏关
    writecom(2,0xc0);//从c0行开始
    writecom(2,0x3f);//全屏开
    writecom(2,0xb8);//从第一页开始显示
    writecom(2,0x40);//从第一列开始显示
    writecom(2,0xc0);//从c0行开始
}
//x:0~127
//y:0~7
void LCD_ShowF6x8Char(u8 x, u8 y, u8 chr)
{
    u8  c=0,i=0;
    u8  xCoo;
    u8  xReal=0;

    c=chr-' ';//得到偏移后的值

    if(((x+6)>Max_Column) || (y>Max_Line))
    {
    }
    else
    {
        for(i=0; i<6; i++)
        {
            if(x < 64)
            {
                xCoo = 0;
                xReal = x;
            }
            else
            {
                xCoo = 1;
                xReal = x - 64;
            }

            writecom(xCoo,(y+0xb8));
            writecom(xCoo,(xReal+0x40));
            writedat(xCoo,F6x8[c][i]);
            x++;
        }
    }
}
//x:0~127
//y:0~7
void LCD_ShowContinueEngString(u8 x,u8 y,u8 *chr)
{
    u8  j=0;
    u8  i=0;
    u8  chrNum=0;

    chrNum = strlen(chr);
    while(chr[j] != '\0')
//    for(i=0; i<chrNum; i++)
    {
        LCD_ShowF6x8Char(x,y,chr[j]);
        x += 6;
        j++;
        if(x >= Max_Column)
        {
            break;
        }
    }
}
  • 主函数:
const u8  messageBuf[5]= {"12345"};
 ******************************************************************************/
int32_t main(void)
{

    App_LedInit();		  ///< LED端口初始化
    delay1ms(20);

    App_PortCfg();    //按键端口配置
    delay1ms(10);

    App_ClkInit();    //时钟初始化配置
    delay1ms(10);

    App_Xth32MHzToPll48MHz();	  //设置系统时钟为48MHZ
    delay1ms(10);

    App_LcdInit();  //LED控制引脚初始化
    delay1ms(50);

    App_LcdDataInit();//LED数据引脚初始化
    delay1ms(50);

    lcd12864_init();  屏幕引脚初始化
    while(1)
    {
        Gpio_SetIO(CON_PORT,LIGHT);
        clear_lcd();
        delay1ms(500);
        LCD_ShowContinueEngString(96,0,&messageBuf);
    }
}

总结

以上为这次工程的主要内容,一些其他的细节就不一一细讲了。本次分享为LCD的驱动以及简单的显示函数介绍,所以在以上基础上需要增加字库和一些基本的函数方可进行运行。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值