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); }

浙公网安备 33010602011771号