LCD12864

lcd12864_drive_function.h

#ifndef __LCD12864_DRIVE_FUNCTION_H
#define    __LCD12864_DRIVE_FUNCTION_H

#include "main.h"


#define LCD_MODE 0   //0:串行接口  1:4位并行接口   2:8位并行接口



/********************************************************************************
                                    引脚IO配置
*******************************************************************************/
#if LCD_MODE == 0

    //CS----片选,低电平有效
    #define CS_GPIO_PORT                    GPIOF                                   //GPIO端口
    #define CS_GPIO_PIN                        GPIO_Pin_15                               //GPIO引脚


    //SID----串行数据线
    #define SID_GPIO_PORT                    GPIOF
    #define SID_GPIO_PIN                    GPIO_Pin_14


    //SCLK----串行时钟输入
    #define SCLK_GPIO_PORT                    GPIOF
    #define SCLK_GPIO_PIN                    GPIO_Pin_12


    //RST----复位信号,低电平有效
    #define RST_GPIO_PORT                    GPIOF
    #define RST_GPIO_PIN                    GPIO_Pin_11


    #define LCD12864_GPIO_CLK                    RCC_APB2Periph_GPIOF               //GPIO端口时钟
    #define LCD12864_GPIO_ClockCmd             RCC_APB2PeriphClockCmd            //打开端口时钟的函数



    #define LCD12864_CS_H()                    GPIO_SetBits(CS_GPIO_PORT, CS_GPIO_PIN)
    #define LCD12864_SCLK_H()                GPIO_SetBits(SCLK_GPIO_PORT, SCLK_GPIO_PIN)
    #define LCD12864_SID_H()                GPIO_SetBits(SID_GPIO_PORT, SID_GPIO_PIN)
    #define LCD12864_RST_H()                GPIO_SetBits(RST_GPIO_PORT, RST_GPIO_PIN)


    #define LCD12864_CS_L()                    GPIO_ResetBits(CS_GPIO_PORT, CS_GPIO_PIN)
    #define LCD12864_SCLK_L()                GPIO_ResetBits(SCLK_GPIO_PORT, SCLK_GPIO_PIN)
    #define LCD12864_SID_L()                GPIO_ResetBits(SID_GPIO_PORT, SID_GPIO_PIN)
    #define LCD12864_RST_L()                GPIO_ResetBits(RST_GPIO_PORT, RST_GPIO_PIN)

#elif LCD_MODE == 1



#elif LCD_MODE == 2

    //RS----RS高电平表示写数据;RS低电平表示写指令
    #define RS_GPIO_PORT                    GPIOF                                   //GPIO端口
    #define RS_GPIO_PIN                        GPIO_Pin_10                               //GPIO引脚


    //RW----高电平读数据,电平写数据
    #define RW_GPIO_PORT                    GPIOF
    #define RW_GPIO_PIN                        GPIO_Pin_9


    //EN----使能信号
    #define EN_GPIO_PORT                    GPIOF
    #define EN_GPIO_PIN                        GPIO_Pin_8


    //PSB----并口通信将该引脚置为高电平
    #define PSB_GPIO_PORT                    GPIOF
    #define PSB_GPIO_PIN                    GPIO_Pin_14


    //RST----复位信号,低电平有效
    #define RST_GPIO_PORT                    GPIOF
    #define RST_GPIO_PIN                    GPIO_Pin_7


    //DATA----DB0~DB7,数据总线
    #define DATA_GPIO_PORT                       GPIOF                           
    #define DATA_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                    
         

    #define LCD12864_GPIO_CLK                    RCC_APB2Periph_GPIOF               //GPIO端口时钟
    #define LCD12864_GPIO_ClockCmd             RCC_APB2PeriphClockCmd            //打开端口时钟的函数




    #define LCD12864_RS_H()                    GPIO_SetBits(RS_GPIO_PORT, RS_GPIO_PIN)
    #define LCD12864_RW_H()                    GPIO_SetBits(RW_GPIO_PORT, RW_GPIO_PIN)
    #define LCD12864_EN_H()                    GPIO_SetBits(EN_GPIO_PORT, EN_GPIO_PIN)


    #define LCD12864_RS_L()                    GPIO_ResetBits(RS_GPIO_PORT, RS_GPIO_PIN)
    #define LCD12864_RW_L()                    GPIO_ResetBits(RW_GPIO_PORT, RW_GPIO_PIN)
    #define LCD12864_EN_L()                    GPIO_ResetBits(EN_GPIO_PORT, EN_GPIO_PIN)

#endif    



/********************************************************************************
                                    驱动函数封装
*******************************************************************************/

#define LCD12864_Delay_MS   SysTick_Delay_MS 

void LCD12864_Config_Init(void);
void LCD12864_Parameter_Init(void);



void LCD12864_Write_Cmd(uint8_t cmd);
void LCD12864_Write_Byte(uint8_t data);


void LCD12864_Clear(void);
void LCD12864_Display_Str(uint8_t X,uint8_t Y,uint8_t *s);
void LCD12864_Display_Int(uint8_t X,uint8_t Y,long int num);
void LCD12864_Display_Float(uint8_t X,uint8_t Y,float fnum);
void LCD12864_Display_Picture(uint8_t *p_str);
void LCD12864_Display_Picture_Left(uint8_t *p_str);

#endif

 

lcd12864_drive_function.c

#include "lcd12864_drive_function.h"


/***************************************************************************************************
lcd12864分四种通讯方式:并口直接访问方式、并口间接访问方式、4位并口方式、串口方式
并口直接访问方式:直接访问的话会给液晶定义一个地址,如果用51的话,使用MOVX就可以读写液晶的数据。
其他单片机的话也类似,定义一个读写地址使用读写液晶,而间接的话操作的只是某个IO,使其时序和要求的一致。
***************************************************************************************************/



/********************************************************************************
                                    引脚IO配置
*******************************************************************************/
#if LCD_MODE == 0

/**
  * @brief  LCD12864引脚配置
  * @param  无
  * @retval 无
  */
static void LCD12864_GPIO_Config(void)
{
    LCD12864_GPIO_ClockCmd(LCD12864_GPIO_CLK , ENABLE);      //开启GPIO外设时钟

    
    GPIO_InitTypeDef GPIO_InitStructure;  //定义一个GPIO_InitTypeDef类型的结构体

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;       //设置引脚模式为通用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;      //设置引脚速率为50MHz 

    GPIO_InitStructure.GPIO_Pin = CS_GPIO_PIN;      
    GPIO_Init(CS_GPIO_PORT, &GPIO_InitStructure);    

    GPIO_InitStructure.GPIO_Pin = SID_GPIO_PIN;
    GPIO_Init(SID_GPIO_PORT, &GPIO_InitStructure);    

    GPIO_InitStructure.GPIO_Pin = SCLK_GPIO_PIN;
    GPIO_Init(SCLK_GPIO_PORT, &GPIO_InitStructure);    
    
    GPIO_InitStructure.GPIO_Pin = RST_GPIO_PIN;
    GPIO_Init(RST_GPIO_PORT, &GPIO_InitStructure);

    return ;
}


/**
  * @brief  LCD12864引脚初始化
  * @param  无
  * @retval 无
  */
void LCD12864_Config_Init(void)    
{
    LCD12864_GPIO_Config();
}

#elif LCD_MODE == 1





#elif LCD_MODE == 2
/**
  * @brief  LCD12864引脚配置
  * @param  无
  * @retval 无
  */
static void LCD12864_GPIO_Config(void)
{
    LCD12864_GPIO_ClockCmd(LCD12864_GPIO_CLK , ENABLE);       //开启GPIO外设时钟

    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;       //设置引脚模式为通用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;      //设置引脚速率为50MHz

    GPIO_InitStructure.GPIO_Pin = DATA_GPIO_PIN;           
    GPIO_Init(DATA_GPIO_PORT, &GPIO_InitStructure);     

    GPIO_InitStructure.GPIO_Pin = RS_GPIO_PIN;      
    GPIO_Init(RS_GPIO_PORT, &GPIO_InitStructure);    

    GPIO_InitStructure.GPIO_Pin = RW_GPIO_PIN;
    GPIO_Init(RW_GPIO_PORT, &GPIO_InitStructure);    

    GPIO_InitStructure.GPIO_Pin = EN_GPIO_PIN;
    GPIO_Init(EN_GPIO_PORT, &GPIO_InitStructure);    

//    GPIO_InitStructure.GPIO_Pin = PSB_GPIO_PIN;
//    GPIO_Init(PSB_GPIO_PORT, &GPIO_InitStructure);    

    return ;
}


/**
  * @brief  LCD12864引脚输出配置
  * @param  无
  * @retval 无
  */
static void LCD12864_DATA_OUTPUT(void)
{
    LCD12864_GPIO_ClockCmd(LCD12864_GPIO_CLK , ENABLE);         //开启GPIO外设时钟

    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;       //设置引脚模式为通用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;      //设置引脚速率为50MHz 

    GPIO_InitStructure.GPIO_Pin = DATA_GPIO_PIN;           
    GPIO_Init(DATA_GPIO_PORT, &GPIO_InitStructure);     


    return ;
}



/**
  * @brief  LCD12864引脚输入配置
  * @param  无
  * @retval 无
  */
static void LCD12864_DATA_INTPUT(void) 
{
    LCD12864_GPIO_ClockCmd(LCD12864_GPIO_CLK , ENABLE);    //开启GPIO外设时钟
    
    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;       //设置引脚模式为浮空输入
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;           //设置引脚速率为50MHz 

    GPIO_InitStructure.GPIO_Pin = DATA_GPIO_PIN;               
    GPIO_Init(DATA_GPIO_PORT,&GPIO_InitStructure);    
}




/**
  * @brief  LCD12864引脚初始化
  * @param  无
  * @retval 无
  */
void LCD12864_Config_Init(void)    
{
    LCD12864_GPIO_Config();
}


#endif



/********************************************************************************
                                    驱动函数封装
*******************************************************************************/
#if LCD_MODE == 0

/**
  * @brief  发送数据
  * @param  Data:要写入的数据
  * @retval 无
  */
static void LCD12864_SendData(uint8_t Data)
{
    for(uint8_t i=0; i<8; i++)
    {
        if((Data << i) & 0x80)
        {
            LCD12864_SID_H();
        }
        else 
        {
            LCD12864_SID_L();
        }
        LCD12864_SCLK_L();
        LCD12864_SCLK_H();
    }
}



/**
  * @brief  写命令函数
  * @param  cmd:要写入的命令,分三字节发送
  * @retval 无
  */
void LCD12864_Write_Cmd(uint8_t Write_Cmd)
{
    LCD12864_CS_H();
    LCD12864_SendData(0xf8);
    LCD12864_SendData(Write_Cmd & 0xf0);
    LCD12864_SendData((Write_Cmd << 4) & 0xf0);
    LCD12864_CS_L();
    LCD12864_Delay_MS(2);
}



/**
  * @brief  写1字节数据
  * @param  Write_Data:要写入的数据
  * @retval 无
  */
void LCD12864_Write_Byte(uint8_t Write_Data)
{
    LCD12864_CS_H();
    LCD12864_SendData(0xfa);
    LCD12864_SendData(Write_Data & 0xf0);
    LCD12864_SendData((Write_Data << 4) & 0xf0);
    LCD12864_CS_L();
    LCD12864_Delay_MS(2);
}



/**
  * @brief  参数初始化
  * @param  无
  * @retval 无
  */
void LCD12864_Parameter_Init(void)
{      
    LCD12864_CS_H();
    LCD12864_RST_L();
    LCD12864_Delay_MS(1);
    LCD12864_RST_H();
    LCD12864_Delay_MS(3);
    LCD12864_Write_Cmd(0x30);
    LCD12864_Write_Cmd(0x0c);
    LCD12864_Write_Cmd(0x01);
    LCD12864_Write_Cmd(0x02);
    LCD12864_Write_Cmd(0x80);
}

#elif LCD_MODE == 1




#elif LCD_MODE == 2


/**
  * @brief  等待12864的忙状态结束
  * @param  无
  * @retval 无
  */
static void LCD12864_Read_Wait_Busy(void)                                     
{
    //RS=0  RW=1  EN=1
    LCD12864_DATA_INTPUT();                                             //把数据引脚 定义为浮空输入;
    LCD12864_RS_L();                                                      //RS = 0---指令
    LCD12864_RW_H();                                                    //RW = 1---读取
    LCD12864_EN_H();                                                    //EN = 1---使能
    while(GPIO_ReadInputData(DATA_GPIO_PORT) & 0x0080);                    //只要位7的值,位7是忙标志位。0--7 ,如果读出为1高电平,则表示液晶屏处在忙状态,当转为0时
    LCD12864_EN_L();                                                     //EN = 0;
    LCD12864_DATA_OUTPUT();                                             //把所有引脚定义为输出
}



/**
  * @brief  写命令函数
  * @param  cmd:寄存器地址
  * @retval 无
  */
void LCD12864_Write_Cmd(uint8_t Write_Cmd)
{ 
    //RS=0  RW=0  EN=1
    LCD12864_Read_Wait_Busy();                                          //等待12864忙状态结束
    LCD12864_RS_L();                                                      //RS = 0---指令
    LCD12864_RW_L();                                                       //RW = 0---写入
    LCD12864_EN_H();                                                    //EN = 1---使能
    DATA_GPIO_PORT->ODR=((DATA_GPIO_PORT->ODR & 0xff00)|Write_Cmd);           //此处,只有直接操作寄存器才能达到,只改变 输出数据寄存器ODR 的低8位,其它位不变的目的。因为,只有低8位是数据引脚,其它位可能是控制引脚,不能改变。
    LCD12864_Delay_MS(2);
    LCD12864_EN_L();                                                       //EN = 0;
    LCD12864_Delay_MS(2);     
}


/**
  * @brief  写1字节数据
  * @param  data:要写入的数据
  * @retval 无
  */
void LCD12864_Write_Byte(uint8_t Write_Data)                           
{
    //RS=1  RW=0  EN=1
    LCD12864_Read_Wait_Busy();                                          //等待12864忙状态结束
    LCD12864_RS_H();                                                    //RS = 1---数据
    LCD12864_RW_L();                                                       //RW = 0---写入
    LCD12864_EN_H();                                                    //EN = 1---使能
    DATA_GPIO_PORT->ODR=((DATA_GPIO_PORT->ODR & 0xff00)|Write_Data);           
    LCD12864_Delay_MS(2);
    LCD12864_EN_L();                                                       //EN = 0;
    LCD12864_Delay_MS(2); 
}




/**
  * @brief  参数初始化
  * @param  无
  * @retval 无
  */
void LCD12864_Parameter_Init(void) 
{
    //GPIO_SetBits(PSB_GPIO_PORT,PSB_GPIO_PIN);                       //令PSB=1,设置为并行数据模式。
    LCD12864_Delay_MS(2); 
    LCD12864_Write_Cmd(0x30);                                     //选择基本指令集,8位数据模式。
    LCD12864_Delay_MS(2);    
    LCD12864_Write_Cmd(0x0c);                                     //开显示,无游标,不反白
    LCD12864_Delay_MS(2); 
    LCD12864_Write_Cmd(0x01);                                     //清除显示,并将 DDRAM 的地址计数器 AC 设为 00H.
    LCD12864_Delay_MS(2);
    LCD12864_Write_Cmd(0x06);                                     //设置,外部读写数据后,地址记数器 AC 会自动加 1。
    LCD12864_Delay_MS(2);
    LCD12864_Write_Cmd(0x80);                                     //将 DDRAM 地址计数器 AC 设为 0.
    LCD12864_Delay_MS(2);    
}


#endif


/**
  * @brief  显示位置设定
  * @param  x:行  y:列
  * @retval 无
  */
static void LCD12864_Locate(uint8_t X,uint8_t Y)
{
    switch(X)
    {
        case 1: LCD12864_Write_Cmd(0x80+Y); break;
        case 2: LCD12864_Write_Cmd(0x90+Y); break;
        case 3: LCD12864_Write_Cmd(0x88+Y); break;
        case 4: LCD12864_Write_Cmd(0x98+Y); break;
    }
}



/**
  * @brief  显示字符串的函数
  * @param  str:要显示的字符串
  * @retval 无
  */
static void LCD12864_DisStr(uint8_t *str) 
{
    while(*str != '\0')
    {
        LCD12864_Write_Byte(*str);
        str++;
        LCD12864_Delay_MS(2);                           //控制每一个字符之间显示的时间 间隔
    }
}




/**
  * @brief  显示整数的函数
  * @param  num:要显示的整数,最多显示16位的整数,只能显示正数
  * @retval 无
  */
static void LCD12864_DisInt(long int num)                               
{
    uint8_t temp[17];
    uint8_t str[17];
    int i=0,j=0;
    while(num != 0)                                              //这里不能用num%10 != 0,如果num是10的整数倍,例如,100,这样就会出错,根本就不能进入循环体。
    {
        temp[i] = (num%10)+0x30;
        num/=10;                                              //num 除以 10 = 剩下的树的整数  124/10=12
        i++;
    }
    i--;                                                      //因为i在退出循环之前还自加了一次,此时,指向最后一个存储有用值的元素的后一个位置。
    while(i != -1)                                              //因为i=0时,temp[0]还是有用值。
    {
        str[j] = temp[i];
        j++;
        i--;    
    }
    str[j]='\0';                                              //因为i在退出循环之前还自加了一次,此时,
                                                            //指向最后一个存储有用值的元素的后一个位置。
    LCD12864_DisStr(str);
}



/**
  * @brief  显示浮点数的函数
  * @param  fnum:要显示的浮点数,显示有4位小数的浮点数,总位数不超过16位
  * @retval 无
  */
static void LCD12864_DisFloat(float fnum)
{
    long int num = fnum*10000;
    uint8_t temp[17];
    uint8_t str[17];
    int i=0,j=0;
    while(num != 0)                      
    {
        temp[i] = (num%10)+0x30;
        num/=10;
        i++;
        if(i == 4)                                            //4位小数处理完后,加入小数点。
        {
            temp[i] = '.';
            i++;
        }
    }
    i--;   
    while(i != -1)    
    {
        str[j] = temp[i]; 
        j++;
        i--;    
    }
    str[j]='\0';  
    LCD12864_DisStr(str);    
}



/**
  * @brief  显示图片的函数
  * @param  p_str:指向图片数组的指针
  * @retval 无
  */
static void LCD12864_DisPicture(uint8_t* p_str)
{
    for(uint8_t i=0;i<32;i++)              //上半屏的32排依次先写满
    {
        LCD12864_Write_Cmd(0x80+i);         //先送垂直地址
        LCD12864_Write_Cmd(0x80);           //再送水平地址,水平地址可自加1
        for(uint8_t j=0;j<16;j++)         //每排128个点,所以一共要16个两位16进制数(也就是8位二进制数)才能全部控制
        {
            LCD12864_Write_Byte(*p_str);
            p_str++;
        }
    }
    for(uint8_t i=0;i<32;i++)             //下半屏的32排操作原理和上半屏一样
    { 
        LCD12864_Write_Cmd(0x80+i);
        LCD12864_Write_Cmd(0x88);
        for(uint8_t j=0;j<16;j++)
        {
            LCD12864_Write_Byte(*p_str);
            p_str++;
        }
    }
}




/**
  * @brief  左边显示图片的函数
  * @param  p_str:指向图片数组的指针
  * @retval 无
  */
static void LCD12864_DisPicture_Left(uint8_t* p_str)
{
    for(uint8_t i=0;i<32;i++)              //上半屏的32排依次先写满
    {
        LCD12864_Write_Cmd(0x80+i);         //先送垂直地址
        LCD12864_Write_Cmd(0x80);           //再送水平地址,水平地址可自加1
        for(uint8_t j=0;j<8;j++)         //每排128个点,所以一共要16个两位16进制数(也就是8位二进制数)才能全部控制
        {
            LCD12864_Write_Byte(*p_str);
            p_str++;
        }
    }
    for(uint8_t i=0;i<32;i++)             //下半屏的32排操作原理和上半屏一样
    { 
        LCD12864_Write_Cmd(0x80+i);
        LCD12864_Write_Cmd(0x88);
        for(uint8_t j=0;j<8;j++)
        {
            LCD12864_Write_Byte(*p_str);
            p_str++;
        }
    }
}


/************************************************************************************/


/**
  * @brief  清全屏函数
  * @param  无
  * @retval 无
  */
void LCD12864_Clear(void)
{
    LCD12864_Write_Cmd(0x01);
}



/**
  * @brief  指定位置显示字符串
  * @param  x:行  y:列  s:要显示的字符串
  * @retval 无
  */
void LCD12864_Display_Str(uint8_t X,uint8_t Y,uint8_t *s)
{
    LCD12864_Locate(X,Y);
    LCD12864_DisStr(s);   //显示字符串
}


/**
  * @brief  指定位置显示整数
  * @param  x:行  y:列  s:要显示的整数
  * @retval 无
  */
void LCD12864_Display_Int(uint8_t X,uint8_t Y,long int num)
{
    LCD12864_Locate(X,Y);
    LCD12864_DisInt(num);   
}


/**
  * @brief  指定位置显示浮点数
  * @param  x:行  y:列  s:要显示的浮点数
  * @retval 无
  */
void LCD12864_Display_Float(uint8_t X,uint8_t Y,float fnum)
{
    LCD12864_Locate(X,Y);
    LCD12864_DisFloat(fnum);   
}


/**
  * @brief  显示图片
  * @param  p_str:指向图片数组的指针
  * @retval 无
  */
void LCD12864_Display_Picture(uint8_t *p_str)
{
    LCD12864_DisPicture(p_str);   
}



/**
  * @brief  左边显示图片的函数
  * @param  p_str:指向图片数组的指针
  * @retval 无
  */
void LCD12864_Display_Picture_Left(uint8_t *p_str)
{
    LCD12864_DisPicture_Left(p_str);   
}

 

posted @ 2020-08-13 22:06  孤情剑客  阅读(617)  评论(0)    收藏  举报