linux SPI操作LCD12864液晶

2019-07-13 01:17发布

液晶型号为JLX12864 COG液晶,资料网上有,linux下面通过SPI与IO控制,IO控制使用的是文件方式,SPI是开发板提供的驱动,这个SPI驱动应该每家提供的都不一样,需要自己去按照驱动文档操作,主要不通电就是底层的配置不一样。 //SPI.c这个是打开SPI驱动 /* * SPI.c * * Created on: 2018年8月2日 * Author: cfan */ #include #include #include #include #include #include #include #include #include "SPI.h" #include // 包含errno所需要的头文件 #include // 包含strerror所需要的头文件 #include "typedef.h" //SPI初始化 int SPI_Init(SPI_HANDLE *pHandle, const char *pSpiDeviceName) { pHandle->fd = -1; if(pSpiDeviceName == NULL || pHandle==NULL || strlen(pSpiDeviceName)>SPI_DEVICE_NAME_MAX_LEN) { printf("%s(%d)Check the input parameters! ",__FILE__ , __LINE__); return -1; } strcpy(pHandle->SpiDeviceName, pSpiDeviceName); //记录串口设备名称 //打开SPI pHandle->fd = open(pSpiDeviceName, O_RDWR|O_NOCTTY|O_NDELAY); //读写独占方式打开SPI if (pHandle->fd < 0) { //打印错误信息 printf("Can't Open SPI(%s) : %s(%d) ",pSpiDeviceName, strerror(errno), errno); return errno; } else { printf("Open SPI OK! "); } return 0; } //spi.h /* * SPI.h * * Created on: 2018年8月2日 * Author: cfan */ #ifndef HARDWARE_SPI_H_ #define HARDWARE_SPI_H_ #include "termios.h" #include "typedef.h" #define SPI_DEVICE_NAME_MAX_LEN 35 //SPI名称最大长度 //SPI接口句柄 typedef struct { int fd; char SpiDeviceName[SPI_DEVICE_NAME_MAX_LEN+1]; //SPI名称 }SPI_HANDLE; //SPI初始化 int SPI_Init(SPI_HANDLE *pHandle, const char *pSpiDeviceName); #endif /* HARDWARE_SPI_H_ */ //SPI驱动调用,这个是开发板提供的,各个厂家应该都不一样,需要自己去查询 #include "common.h" #include "spi_enum.h" #include "spidev.h" #include #include "nano_pi_spi.h" //开发板官方提供的SPI驱动接口 #define SPI_MAX_SPEED 25000000 //最大时钟速度 /************************************************************************************************************************* *函数 : int setSPIWriteBitsPerWord(int spi_fd, int bits) *功能 : 设置每次读SPI设备的字长,单位是比特. *参数 : spi_fd: SPI设备的文件描述符;bits: 字长,单位是比特 *返回 : 成功返回0,失败返回负数 *依赖 : 无 *作者 : Friendly NanoPI-NEO(cp1300@139.com整理) *时间 : 2018-08-12 *最后修改时间 : 2018-08-12 *说明 : 虽然大部分SPI接口的字长是8或者16,仍然会有一些特殊的例子。 需要说明的是,如果这个成员为零的话,默认使用8作为字长(ioctl SPI_IOC_WR_BITS_PER_WORD) *************************************************************************************************************************/ int setSPIWriteBitsPerWord(int spi_fd, int bits) { clearLastError(); int ret = ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &bits); if (ret < 0) { setLastError("Can't ioctl SPI_IOC_WR_BITS_PER_WORD"); } return ret; } /************************************************************************************************************************* *函数 : int setSPIReadBitsPerWord(int spi_fd, int bits) *功能 : 设置每次写SPI设备的字长,单位是比特 *参数 : spi_fd: SPI设备的文件描述符;bits: 字长,单位是比特 *返回 : 成功返回0,失败返回负数 *依赖 : 无 *作者 : Friendly NanoPI-NEO(cp1300@139.com整理) *时间 : 2018-08-12 *最后修改时间 : 2018-08-12 *说明 : 虽然大部分SPI接口的字长是8或者16,仍然会有一些特殊的例子。 需要说明的是,如果这个成员为零的话,默认使用8作为字长(ioctl SPI_IOC_WR_BITS_PER_WORD) *************************************************************************************************************************/ int setSPIReadBitsPerWord(int spi_fd, int bits) { int ret = ioctl(spi_fd, SPI_IOC_RD_BITS_PER_WORD, &bits); clearLastError(); if (ret < 0) { setLastError("Can't ioctl SPI_IOC_RD_BITS_PER_WORD"); } return ret; } /************************************************************************************************************************* *函数 : int setSPIBitOrder(int spi_fd, int order) *功能 : 设备SPI传输时是先传输低比特位还是高比特位 *参数 : spi_fd: SPI设备的文件描述符;order: 传SPIEnum.MSBFIRST或SPIEnum.LSBFIRST *返回 : 成功返回0,失败返回负数 *依赖 : 无 *作者 : Friendly NanoPI-NEO(cp1300@139.com整理) *时间 : 2018-08-12 *最后修改时间 : 2018-08-12 *说明 : 可选的参数有SPIEnum.MSBFIRST和SPIEnum.LSBFIRST *************************************************************************************************************************/ int setSPIBitOrder(int spi_fd, int order) { int ret; int spi_mode = 0; clearLastError(); if(order == LSBFIRST) { spi_mode |= SPI_LSB_FIRST; } else { spi_mode &= ~SPI_LSB_FIRST; } ret = ioctl(spi_fd, SPI_IOC_WR_MODE, &spi_mode); if (ret < 0) { setLastError("Can't ioctl SPI_IOC_WR_MODE"); return ret; } return ret; } /************************************************************************************************************************* *函数 : int setSPIMaxSpeed(int spi_fd, unsigned int spi_speed) *功能 : 设备SPI传输速度 *参数 : spi_fd: SPI设备的文件描述符;spi_speed: 速度(分频,越小速度越高) *返回 : 成功返回0,失败返回负数 *依赖 : 无 *作者 : Friendly NanoPI-NEO(cp1300@139.com整理) *时间 : 2018-08-12 *最后修改时间 : 2018-08-12 *说明 : *************************************************************************************************************************/ int setSPIMaxSpeed(int spi_fd, unsigned int spi_speed) { int ret; unsigned int realSpeed; clearLastError(); if (spi_speed<0 || spi_speed>SPI_MAX_SPEED) { setLastError("invalid spi speed %d", spi_speed); } ret = ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed); if (ret < 0) { setLastError("Can't ioctl SPI_IOC_WR_MAX_SPEED_HZ"); return ret; } ret = ioctl(spi_fd, SPI_IOC_RD_MAX_SPEED_HZ, &realSpeed); if (ret < 0) { setLastError("Can't ioctl SPI_IOC_RD_MAX_SPEED_HZ"); return ret; } return ret; } /************************************************************************************************************************* *函数 : int setSPIDataMode(int spi_fd, int mode) *功能 : 设置SPI设备的模式 *参数 : spi_fd: SPI设备的文件描述符;mode: SPI设备的模式,可传入SPI_MODE0 ~ SPI_MODE3 *返回 : 成功返回0,失败返回负数 *依赖 : 无 *作者 : Friendly NanoPI-NEO(cp1300@139.com整理) *时间 : 2018-08-12 *最后修改时间 : 2018-08-12 *说明 : *************************************************************************************************************************/ int setSPIDataMode(int spi_fd, int mode) { int ret; int spi_mode = 0; clearLastError(); switch(mode) { case SPI_MODE0: spi_mode &= ~(SPI_CPHA|SPI_CPOL); break; case SPI_MODE1: spi_mode &= ~(SPI_CPOL); spi_mode |= (SPI_CPHA); break; case SPI_MODE2: spi_mode |= (SPI_CPOL); spi_mode &= ~(SPI_CPHA); break; case SPI_MODE3: spi_mode |= (SPI_CPHA|SPI_CPOL); break; default: setLastError("error SPIDataMode"); return -1; } ret = ioctl(spi_fd, SPI_IOC_WR_MODE, &mode); if (ret < 0) { setLastError("Can't ioctl SPI_IOC_WR_MODE"); return ret; } ret = ioctl(spi_fd, SPI_IOC_RD_MODE, &mode); if (ret < 0) { setLastError("Can't ioctl SPI_IOC_RD_MODE"); return ret; } return ret; } /************************************************************************************************************************* *函数 : int SPItransferOneByte(int spi_fd, unsigned char byteData, int spi_delay, int spi_speed, int spi_bits) *功能 : 同时发送与接收一个字节的数据 *参数 : spi_fd: SPI设备的文件描述符;byteData:要写入SPI设备的数据;spi_delay:延时;spi_speed:传输速度;spi_bits:字长,单位是比特 *返回 : 成功返回读到的数据,失败返回负数 *依赖 : 无 *作者 : Friendly NanoPI-NEO(cp1300@139.com整理) *时间 : 2018-08-12 *最后修改时间 : 2018-08-12 *说明 : *************************************************************************************************************************/ int SPItransferOneByte(int spi_fd , unsigned char byteData, int spi_delay, int spi_speed, int spi_bits) { int ret; unsigned char tx[1] = {0}; unsigned char rx[1] = {0}; tx[0] = byteData; struct spi_ioc_transfer tr; tr.tx_buf = (unsigned long)tx; tr.rx_buf = (unsigned long)rx; tr.len = 1; tr.delay_usecs = spi_delay; tr.speed_hz = spi_speed; tr.bits_per_word = spi_bits; clearLastError(); ret = ioctl(spi_fd, SPI_IOC_MESSAGE(1), &tr); if (ret < 0) { setLastError("Can't ioctl SPI_IOC_MESSAGE"); return ret; } return rx[0]; } /************************************************************************************************************************* *函数 : int SPItransferBytes(int spi_fd, unsigned char * writeData, int writeLen, unsigned char * readBuffer, *函数 int readLen, int spi_delay, int spi_speed, int spi_bits) *功能 : 同时发送与接收多个字节的数据 *参数 : spi_fd: SPI设备的文件描述符;writeData:要写入的数据;readBuff: 存放读取数据的缓冲区;spi_delay:延时;spi_speed:传输速度; spi_bits:字长,单位是比特 *返回 : 成功返回0,失败返回负数 *依赖 : 无 *作者 : Friendly NanoPI-NEO(cp1300@139.com整理) *时间 : 2018-08-12 *最后修改时间 : 2018-08-12 *说明 : *************************************************************************************************************************/ int SPItransferBytes(int spi_fd, unsigned char * writeData, int writeLen, unsigned char * readBuffer, int readLen, int spi_delay, int spi_speed, int spi_bits) { unsigned int len = writeLen; if (len > readLen) { len = readLen; } unsigned char * pWriteData = writeData; unsigned char * pReadBuffer = readBuffer; struct spi_ioc_transfer tr; tr.tx_buf = (unsigned long)pWriteData; tr.rx_buf = (unsigned long)pReadBuffer; tr.len = len; tr.delay_usecs = spi_delay; tr.speed_hz = spi_speed; tr.bits_per_word = spi_bits; int ret = ioctl(spi_fd, SPI_IOC_MESSAGE(1), &tr); clearLastError(); if (ret < 0) { setLastError("Can't ioctl SPI_IOC_MESSAGE"); } return ret; } /************************************************************************************************************************* *函数 : int writeBytesToSPI(int spi_fd, unsigned char * writeData, int writeLen, int spi_delay, int spi_speed, *函数 int spi_bits) *功能 : 写多个字节的数据到SPI设 备 *参数 : spi_fd: SPI设备的文件描述符;writeData:要写入的数据;spi_delay:延时;spi_speed:传输速度;spi_bits:字长,单位是比特 *返回 : 成功返回0,失败返回负数 *依赖 : 无 *作者 : Friendly NanoPI-NEO(cp1300@139.com整理) *时间 : 2018-08-12 *最后修改时间 : 2018-08-12 *说明 : *************************************************************************************************************************/ int writeBytesToSPI(int spi_fd, unsigned char * writeData, int writeLen, int spi_delay, int spi_speed, int spi_bits) { unsigned int len = writeLen; unsigned char * pWriteData = writeData; struct spi_ioc_transfer tr; tr.tx_buf = (unsigned long)pWriteData; tr.rx_buf = (unsigned long)0; tr.len = len; tr.delay_usecs = spi_delay; tr.speed_hz = spi_speed; tr.bits_per_word = spi_bits; int ret = ioctl(spi_fd, SPI_IOC_MESSAGE(1), &tr); clearLastError(); if (ret < 0) { setLastError("Can't ioctl SPI_IOC_MESSAGE"); } return ret; } /************************************************************************************************************************* *函数 : int readBytesFromSPI(int spi_fd, unsigned char * readBuffer, int readLen, int spi_delay, int spi_speed, *函数 int spi_bits) *功能 : 从SPI设备读取多个字节 *参数 : spi_fd: SPI设备的文件描述符;readBuff: 存放读取数据的缓冲区;readLen:读取长度(不能超过缓冲区大小) spi_delay:延时;spi_speed:传输速度;spi_bits:字长,单位是比特 *返回 : 成功返回0,失败返回负数 *依赖 : 无 *作者 : Friendly NanoPI-NEO(cp1300@139.com整理) *时间 : 2018-08-12 *最后修改时间 : 2018-08-12 *说明 : *************************************************************************************************************************/ int readBytesFromSPI(int spi_fd, unsigned char * readBuffer, int readLen, int spi_delay, int spi_speed, int spi_bits) { unsigned int len = readLen; unsigned char * pReadBuffer = readBuffer; struct spi_ioc_transfer tr; tr.tx_buf = (unsigned long)0; tr.rx_buf = (unsigned long)pReadBuffer; tr.len = len; tr.delay_usecs = spi_delay; tr.speed_hz = spi_speed; tr.bits_per_word = spi_bits; int ret = ioctl(spi_fd, SPI_IOC_MESSAGE(1), &tr); clearLastError(); if (ret < 0) { setLastError("Can't ioctl SPI_IOC_MESSAGE"); } return ret; } //JLX12864G.c 液晶硬件底层操作 /************************************************************************************************************* * 文件名: JLX12864G.c * 功能: JLX12864G-0088 JLX12864G液晶驱动 * 作者: cp1300@139.com * 邮箱: cp1300@139.com * 创建时间: 2012年5月30日20:40 * 最后修改时间:2012年5月30日 * 详细: 2016-02-01:增加获取显存函数 *************************************************************************************************************/ #include "ascii_8x16.h" #include "JLX12864G.H" #include #include "typedef.h" //字模取模方式:阴码,列行式,逆向(低位在前) //汉字支持 #define CHINESE_ENABLE 0 #if LCD_BUFF_ENABLE //使能了显存 //获取显存地址 //2016-02-01:增加获取显存函数 u8 *JLX12864G_GetGramBuff(JLX12864G_HANDLE *pHandle) { return (u8 *)&pHandle->LCD_BUFF[0][0]; } #endif /************************************************************************************************************************* * 函数 : void JLX12864G_WriteCommand(JLX12864G_HANDLE *pHandle, u8 cmd) * 功能 : 向JLX12864G写入一字节命令 * 参数 : pHandle:句柄;cmd:命令 * 返回 : 无 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 20120530 * 最后修改时间 : 2018-08-12 * 说明 : RS=0,时钟上升沿数据有效,先发送高位 *************************************************************************************************************************/ void JLX12864G_WriteCommand(JLX12864G_HANDLE *pHandle, u8 cmd) { pHandle->SetRS(0); //RS=0 pHandle->WriteData(&cmd, 1); //发送数据 pHandle->SetRS(1); //RS=1 } /************************************************************************************************************************* * 函数 : static void JLX12864G_SetPageAdd(JLX12864G_HANDLE *pHandle, u8 PageAdd) * 功能 : 设置光标页地址 * 参数 : pHandle:句柄;PageAdd:页地址,0-7 * 返回 : 无 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 20120531 * 最后修改时间 : 20120531 * 说明 : 共64行,没8行为一页,共8页 *************************************************************************************************************************/ static void JLX12864G_SetPageAdd(JLX12864G_HANDLE *pHandle, u8 PageAdd) { JLX12864G_WriteCommand(pHandle, 0xb0 + PageAdd); } /************************************************************************************************************************* * 函数 : static void JLX12864G_SetLineAdd(JLX12864G_HANDLE *pHandle, u8 LineAdd) * 功能 : 设置光标列地址 * 参数 : pHandle:句柄;LineAdd:列地址,0-127 * 返回 : 无 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 20120531 * 最后修改时间 : 20120531 * 说明 : 共128列 *************************************************************************************************************************/ static void JLX12864G_SetLineAdd(JLX12864G_HANDLE *pHandle, u8 LineAdd) { LineAdd += JLX12864G_X_OFFSET; JLX12864G_WriteCommand(pHandle, 0x10 + (LineAdd >> 4)); //列地址高4位 JLX12864G_WriteCommand(pHandle, 0x00 + (LineAdd & 0x0f)); //列地址低4位 } /************************************************************************************************************************* * 函数 : void JLX12864G_ClearAll(JLX12864G_HANDLE *pHandle) * 功能 : JLX12864G液晶清屏 * 参数 : pHandle:句柄; * 返回 : 无 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 20120530 * 最后修改时间 : 20120530 * 说明 : 无 *************************************************************************************************************************/ void JLX12864G_ClearAll(JLX12864G_HANDLE *pHandle) { u8 i,j; u32 data = 0; for(i = 0;i < 9;i ++) { JLX12864G_SetPageAdd(pHandle, i); JLX12864G_SetLineAdd(pHandle, 0); for(j = 0;j < 132/4;j ++) { pHandle->WriteData((u8 *)&data, 4); } } } /************************************************************************************************************************* * 函数 : void JLX12864G_FillAll(JLX12864G_HANDLE *pHandle) * 功能 : JLX12864G液晶填充 * 参数 : pHandle:句柄; * 返回 : 无 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 20120530 * 最后修改时间 : 20120530 * 说明 : 无 *************************************************************************************************************************/ void JLX12864G_FillAll(JLX12864G_HANDLE *pHandle) { u8 i,j; u32 data = 0xffffffff; for(i = 0;i < 9;i ++) { JLX12864G_SetPageAdd(pHandle, i); JLX12864G_SetLineAdd(pHandle, 0); for(j = 0;j < 132/4;j ++) { pHandle->WriteData((u8 *)&data, 4); } } } /************************************************************************************************************************* * 函数 : void JLX12864G_ShowOneChar(JLX12864G_HANDLE *pHandle,u8 PageAdd,u8 LineAdd,u8 CHAR,u8 FontSize) * 功能 : 在指定位置显示一个字符 * 参数 : pHandle:句柄;PageAdd:页,0~7,共8页;L:0~127共128列,CHAR:需要显示的字符,FontSize:字体大小 * 返回 : 无 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 20120530 * 最后修改时间 : 20120530 * 说明 : 显示一个ASCII字符 *************************************************************************************************************************/ void JLX12864G_ShowOneChar(JLX12864G_HANDLE *pHandle,u8 PageAdd,u8 LineAdd,u8 CHAR,u8 FontSize) { u8 i,j,k; const unsigned char *p; CHAR -= 32; if(CHAR > ASCII_MAX - 1) return; if(FontSize == 12) p = ASCII_8X12[CHAR]; //12号 else p = ASCII_8X16[CHAR]; //16号 for(i = 0;i < 2;i ++) { JLX12864G_SetPageAdd(pHandle, PageAdd + i); JLX12864G_SetLineAdd(pHandle, LineAdd); k = i * 8; pHandle->WriteData((u8 *)&p[k+j], 8); /*for(j = 0;j < 8;j ++) { pHandle->WriteByteData(p[k+j]); }*/ } } /************************************************************************************************************************* * 函数 : void LCD_PrintfChar(JLX12864G_HANDLE *pHandle,u8 PageAdd,u8 LineAdd,const char *p,u8 FontSize) * 功能 : 在指定位置显示字符串 * 参数 : pHandle:句柄;PageAdd:页,0~7,共8页;L:0~127共128列;p:字符指针,FontSize:子大小;16或者12 * 返回 : 无 * 依赖 : JLX12864G_ShowOneChar * 作者 : cp1300@139.com * 时间 : 20120601 * 最后修改时间 : 20120601 * 说明 : FontSize = 16或者 12 *************************************************************************************************************************/ void JLX12864G_PrintfChar(JLX12864G_HANDLE *pHandle,u8 PageAdd,u8 LineAdd,const char *p,u8 FontSize) { while(*p != 0) { JLX12864G_ShowOneChar(pHandle, PageAdd,LineAdd,*p,FontSize); p ++; LineAdd += 8; } } /************************************************************************************************************************* * 函数 : void JLX12864G_SetConAdj(JLX12864G_HANDLE *pHandle,u8 cont) * 功能 : 设置液晶的对比度 * 参数 : pHandle:句柄;cont:对比度值 * 返回 : 无 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 2014-08-24 * 最后修改时间 : 2014-08-24 * 说明 : 需要先初始化LCD *************************************************************************************************************************/ void JLX12864G_SetConAdj(JLX12864G_HANDLE *pHandle,u8 cont) { if(cont < 25)cont = 25; if(cont > 60)cont = 60; JLX12864G_WriteCommand(pHandle, 0x81); /*微调对比度*/ JLX12864G_WriteCommand(pHandle, cont); /*微调对比度的值,可设置范围0~63*/ pHandle->LCD_Cont = cont; //更新对比度 } /************************************************************************************************************************* * 函数 : void JLX12864G_Init(JLX12864G_HANDLE *pHandle, void (*WriteData)(u8 data,u8 len), //写数据接口 void (*SetRS)(u8 level), //设置RS电平 void (*SetRST)(u8 level), //设置RST电平 void (*DelayMS)(u8 ms), //ms延时 u8 LCDCont) * 功能 : 初始化JLX12864G液晶 * 参数 : pHandle:句柄;WriteByteData:写一字节函数;SetRS:设置RS电平;SetRST:设置RST电平;DelayMS:系统ms延时;LCDCont:对比度 * 返回 : 无 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 20120530 * 最后修改时间 : 2018-08-12 * 说明 : 初始化JLX12864G液晶 *************************************************************************************************************************/ void JLX12864G_Init(JLX12864G_HANDLE *pHandle, void (*WriteData)(u8 *data,u8 len), //写数据接口 void (*SetRS)(u8 level), //设置RS电平 void (*SetRST)(u8 level), //设置RST电平 void (*DelayMS)(u8 ms), //ms延时 u8 LCDCont) { if(pHandle == NULL) { printf("JLX12864G:ERROR *pHandle is NULL! "); return; } if(WriteData == NULL) { printf("JLX12864G:ERROR *WriteData is NULL! "); return; } if(SetRS == NULL) { printf("JLX12864G:ERROR *SetRS is NULL! "); return; } if(DelayMS == NULL) { printf("JLX12864G:ERROR *DelayMS is NULL! "); return; } pHandle->WriteData = WriteData; pHandle->SetRS = SetRS; pHandle->SetRST = SetRST; pHandle->DelayMS = DelayMS; if(pHandle->SetRST != NULL) { pHandle->SetRST(0);//液晶复位开始 pHandle->DelayMS(1); pHandle->SetRST(1);//液晶复位结束 } pHandle->DelayMS(1); JLX12864G_WriteCommand(pHandle, 0xe2); /*软复位*/ JLX12864G_WriteCommand(pHandle, 0x2c); /*升压步聚1*/ JLX12864G_WriteCommand(pHandle, 0x2e); /*升压步聚2*/ JLX12864G_WriteCommand(pHandle, 0x2f); /*升压步聚3*/ JLX12864G_WriteCommand(pHandle, 0x23); /*粗调对比度,可设置范围20~27*/ // JLX12864G_WriteCommand(0x81); /*微调对比度*/ // JLX12864G_WriteCommand(0x30); /*微调对比度的值,可设置范围0~63*/ JLX12864G_SetConAdj(pHandle, LCDCont); JLX12864G_WriteCommand(pHandle, 0xa2); /*1/9 偏压比(bias)*/ #if(LCD_ROTATE_180) //旋转180度显示 JLX12864G_WriteCommand(pHandle, 0xc0); /*行扫描顺序:从下到上*/ JLX12864G_WriteCommand(pHandle, 0xa1); /*列扫描顺序:从右到左*/ #else JLX12864G_WriteCommand(pHandle, 0xc8); /*行扫描顺序:从上到下*/ JLX12864G_WriteCommand(pHandle, 0xa0); /*列扫描顺序:从左到右*/ #endif JLX12864G_WriteCommand(pHandle, 0x40); //初始化显示行为0 JLX12864G_WriteCommand(pHandle, 0xa4); //常规显示 JLX12864G_WriteCommand(pHandle, 0xaf); /*开显示*/ JLX12864G_ClearAll(pHandle); pHandle->LCD_Cont = LCDCont; //isPowerStatus = TRUE; //上电完成 } /************************************************************************************************************************* * 函数 : void JLX12864G_GRAM_Up(JLX12864G_HANDLE *pHandle, u8 LCD_BUFF[8][128], u8 x1,u8 y1,u8 x2,u8 y2) * 功能 : 更新显存至液晶 * 参数 : pHandle:句柄;LCD_BUFF:显存地址;x1,y1:起始坐标;x2,y2:终点坐标 * 返回 : 无 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 20120531 * 最后修改时间 : 2018-08-12 * 说明 : y坐标会页对齐 *************************************************************************************************************************/ void JLX12864G_GRAM_Up(JLX12864G_HANDLE *pHandle, u8 LCD_BUFF[8][128], u8 x1,u8 y1,u8 x2,u8 y2) { u8 i,j; if(x2 > 127) x2 = 127; y1 /= 8; //计算页地址 y2 /= 8; for(i = 0;i < (y2 - y1 + 1);i ++) { JLX12864G_SetPageAdd(pHandle, y1 + i); //写入页地址 JLX12864G_SetLineAdd(pHandle, x1); //写入行地址 pHandle->WriteData(&LCD_BUFF[y1 + i][x1 + 0], (x2 - x1 + 1)); /*for(j = 0;j < (x2 - x1 + 1);j ++) { LCD12864_WriteData(pHandle, LCD_BUFF[y1 + i][x1 + j]); }*/ } } //LCD12864.c 这个是个内存中的虚拟LCD,每次操作都在内存中操作,然后同步到实际LCD /* * LCD12864_Virtual.c * 虚拟LCD12864 * Created on: 2018年8月12日 * Author: cfan */ #include "LCD12864.h" #include "typedef.h" #include "ASCII_8x16.h" #include #include /************************************************************************************************************************* * 函数 : void LCD12864_GRAM_Init(LCD12864_HANDLE *pHandle) * 功能 : LCD12864显存模式初始化 * 参数 : pHandle:句柄; * 返回 : 无 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 20120531 * 最后修改时间 : 2018-08-12 * 说明 : 无 *************************************************************************************************************************/ void LCD12864_GRAM_Init(LCD12864_HANDLE *pHandle) { if(pHandle == NULL) { printf("LCD12864:ERROR *pHandle is NULL! "); return; } memset(pHandle->LCD_BUFF, 0, 8*128); } /************************************************************************************************************************* * 函数 : void LCD12864_GRAM_DrawPoint(LCD12864_HANDLE *pHandle, u8 x,u8 y) * 功能 : 在显存里面指定位置画点 * 参数 : pHandle:句柄;x:X坐标,0-127;y:y坐标,0-63 * 返回 : 无 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 20120531 * 最后修改时间 : 2018-08-12 * 说明 : 无 *************************************************************************************************************************/ void LCD12864_GRAM_DrawPoint(LCD12864_HANDLE *pHandle, u8 x,u8 y) { if(x > 127 || y > 63) return; pHandle->LCD_BUFF[y / 8][x] |= (1 << (y % 8)); } /************************************************************************************************************************* * 函数 : void LCD12864_GRAM_ClearPoint(LCD12864_HANDLE *pHandle, u8 x,u8 y) * 功能 : 擦除显存里面指定位置的点 * 参数 : pHandle:句柄;x:X坐标,0-127;y:y坐标,0-63 * 返回 : 无 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 20120531 * 最后修改时间 : 2018-08-12 * 说明 : 无 *************************************************************************************************************************/ void LCD12864_GRAM_ClearPoint(LCD12864_HANDLE *pHandle, u8 x, u8 y) { if(x > 127 || y > 63) return; pHandle->LCD_BUFF[y / 8][x] &= ~(1 << (y % 8)); } /************************************************************************************************************************* * 函数 : void LCD12864_GRAM_ClearAll(LCD12864_HANDLE *pHandle) * 功能 : 清除全部显存 * 参数 : pHandle:句柄; * 返回 : 无 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 20120531 * 最后修改时间 : 2018-08-12 * 说明 : 无 *************************************************************************************************************************/ void LCD12864_GRAM_ClearAll(LCD12864_HANDLE *pHandle) { u8 i,j; for(i = 0;i < 8;i ++) { for(j = 0;j < 128;j ++) { pHandle->LCD_BUFF[i][j] = 0x00; } } } /************************************************************************************************************************* * 函数 : void LCD12864_GRAM_ShowChar(LCD12864_HANDLE *pHandle, u8 x,u8 y,u8 CHAR,LCD12864_FONT_MODE FontMode) * 功能 : 在指定位置显示一个指定大小的字符 * 参数 : pHandle:句柄;x,y:显示开始坐标,p:汉子点阵缓冲区;FontMode:汉子显示模式, * 返回 : 无 * 依赖 : 画点函数 * 作者 : cp1300@139.com * 时间 : 20120603 * 最后修改时间 : 2018-08-12 * 说明 : *************************************************************************************************************************/ void LCD12864_GRAM_ShowChar(LCD12864_HANDLE *pHandle, u8 x,u8 y,u8 CHAR,LCD12864_FONT_MODE FontMode) { u8 i,j; u8 FontSize = (u8)FontMode&0x0f; //获取字体大小 u8 *p; void (*DrawPoint)(LCD12864_HANDLE *pHandle, u8 i,u8 j); void (*ClearPoint)(LCD12864_HANDLE *pHandle, u8 i,u8 j); CHAR -= 32; if(CHAR > 95 - 1) //限制ASCII范围 return; if(FontSize) { FontSize = 12; p = (u8 *)ASCII_8X12[CHAR]; //12号 } else { FontSize = 16; p = (u8 *)ASCII_8X16[CHAR]; //16号 } if(FontMode & 0x40) //反显 { DrawPoint = LCD12864_GRAM_ClearPoint; ClearPoint = LCD12864_GRAM_DrawPoint; } else //正常模式 { ClearPoint = LCD12864_GRAM_ClearPoint; DrawPoint = LCD12864_GRAM_DrawPoint; } if(FontMode & 0x80) //叠加显示 { for(j = 0;j < 8;j ++) { for(i = 0;i < 8;i ++) { if(*p & (1 << i)) (*DrawPoint)(pHandle, x + j,y + i); } p ++; } for(j = 0;j < 8;j ++) { for(i = 0;i < FontSize - 8;i ++) { if(*p & (1 << i)) (*DrawPoint)(pHandle, x + j,y + 8 + i); } p ++; } } else //非叠加显示 { for(j = 0;j < 8;j ++) { for(i = 0;i < 8;i ++) { if(*p & (1 << i)) (*DrawPoint)(pHandle, x + j,y + i); else (*ClearPoint)(pHandle, x + j,y + i); } p ++; } for(j = 0;j < 8;j ++) { for(i = 0;i < FontSize - 8;i ++) { if(*p & (1 << i)) (*DrawPoint)(pHandle, x + j,y + 8 + i); else (*ClearPoint)(pHandle, x + j,y + 8 + i); } p ++; } } } /************************************************************************************************************************* * 函数 : void LCD12864_GRAM_Fill(LCD12864_HANDLE *pHandle, u16 xStart, u16 yStart, u16 xEnd, u16 yEnd) * 功能 : 指定位置填充 * 参数 : pHandle:句柄;范围 * 返回 : 无 * 依赖 : 底层函数 * 作者 : cp1300@139.com * 时间 : 20110920 * 最后修改时间 : 2018-08-12 * 说明 : 无 *************************************************************************************************************************/ void LCD12864_GRAM_Fill(LCD12864_HANDLE *pHandle, u16 xStart, u16 yStart, u16 xEnd, u16 yEnd) { u16 i,j; for(i = xStart;i < xEnd; i ++) { for(j = yStart;j < yEnd;j ++) { LCD12864_GRAM_DrawPoint(pHandle,i,j); } } } /************************************************************************************************************************* * 函数 : void LCD12864_GRAM_Clear(LCD12864_HANDLE *pHandle, u16 xStart, u16 yStart, u16 xEnd, u16 yEnd) * 功能 : 清除指定位置 * 参数 : pHandle:句柄;范围 * 返回 : 无 * 依赖 : 底层函数 * 作者 : cp1300@139.com * 时间 : 20110920 * 最后修改时间 : 2018-08-12 * 说明 : 无 *************************************************************************************************************************/ void LCD12864_GRAM_Clear(LCD12864_HANDLE *pHandle, u16 xStart, u16 yStart, u16 xEnd, u16 yEnd) { u16 i,j; for(i = xStart;i < xEnd; i ++) { for(j = yStart;j < yEnd;j ++) { LCD12864_GRAM_ClearPoint(pHandle,i,j); } } } /************************************************************************************************************************* * 函数 : void LCD12864_GRAM_DrawLine(LCD12864_HANDLE *pHandle,u16 x1, u16 y1, u16 x2, u16 y2) * 功能 : 画线函数 * 参数 : pHandle:句柄;起点终点坐标 * 返回 : 无 * 依赖 : 画点函数 * 作者 : cp1300@139.com * 时间 : 20110920 * 最后修改时间 : 2018-08-12 * 说明 : 无 *************************************************************************************************************************/ void LCD12864_GRAM_DrawLine(LCD12864_HANDLE *pHandle,u16 x1, u16 y1, u16 x2, u16 y2) { u16 t; int xerr=0,yerr=0,delta_x,delta_y,distance; int incx,incy,uRow,uCol; //TFT_LCD_SetRamAddr(0,239,0,319);//设置显示窗口 delta_x=x2-x1; //计算坐标增量 delta_y=y2-y1; uRow=x1; uCol=y1; if(delta_x>0)incx=1; //设置单步方向 else if(delta_x==0)incx=0;//垂直线 else {incx=-1;delta_x=-delta_x;} if(delta_y>0)incy=1; else if(delta_y==0)incy=0;//水平线 else{incy=-1;delta_y=-delta_y;} if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 else distance=delta_y; for(t=0;t<=distance+1;t++ )//画线输出 { LCD12864_GRAM_DrawPoint(pHandle, uRow,uCol);//画点 xerr+=delta_x ; yerr+=delta_y ; if(xerr>distance) { xerr-=distance; uRow+=incx; } if(yerr>distance) { yerr-=distance; uCol+=incy; } } } /************************************************************************************************************************* * 函数 : void LCD12864_GRAM_DrawRectangle(LCD12864_HANDLE *pHandle,u16 x1, u16 y1, u16 x2, u16 y2) * 功能 : 在指定位置画一个矩形 * 参数 : pHandle:句柄;多边形的两个坐标 * 返回 : 无 * 依赖 : 画线函数 * 作者 : cp1300@139.com * 时间 : 20110920 * 最后修改时间 : 2018-08-12 * 说明 : 无 *************************************************************************************************************************/ void LCD12864_GRAM_DrawRectangle(LCD12864_HANDLE *pHandle,u16 x1, u16 y1, u16 x2, u16 y2) { LCD12864_GRAM_DrawLine(pHandle, x1,y1,x2,y1); LCD12864_GRAM_DrawLine(pHandle, x1,y1,x1,y2); LCD12864_GRAM_DrawLine(pHandle, x1,y2,x2,y2); LCD12864_GRAM_DrawLine(pHandle, x2,y1,x2,y2); } /************************************************************************************************************************* * 函数 : void LCD12864_GRAM_ShowString(LCD12864_HANDLE *pHandle, u16 x,u16 y,const char *pStr,LCD12864_FONT_MODE Font_MODE) * 功能 : 在显存指定位置显示字符串 * 参数 : pHandle:句柄;x,y:显示开始坐标,pStr:字符串缓冲区;FontMode:显示模式, * 返回 : 无 * 依赖 : 画点函数 * 作者 : cp1300@139.com * 时间 : 2014-08-20 * 最后修改时间 : 2018-08-12 * 说明 : *************************************************************************************************************************/ void LCD12864_GRAM_ShowString(LCD12864_HANDLE *pHandle, u16 x,u16 y,const char *pStr,LCD12864_FONT_MODE Font_MODE) { u8 Font_Size = Font_MODE & 0x0f; #if CHINESE_ENABLE u8 buff[32]; #endif while(*pStr != 0) { #if CHINESE_ENABLE if(*pStr > 0x80)//汉字 { FONT_GetFontLattice(buff, (u8*)pStr, ST16X16); //获取汉字点阵 LCD12864_GRAM_ShowChina(x,y,buff,Font_MODE); //显示汉字 pStr += 2; if(x > 127 - 16) //自动换行 { x = 0; y += 16; } else { x += 16; } } else //ASCII #endif { LCD12864_GRAM_ShowChar(pHandle, x,y,*pStr,Font_MODE); pStr++; if(x > 127 - 8) //自动换行 { x = 0; y += Font_Size; } else { x += 8; } } } } //LCD12864.h /* * LCD12864_Virtual.h * * Created on: 2018年8月12日 * Author: cfan */ #ifndef PROGRAM_LCD_LCD12864_H_ #define PROGRAM_LCD_LCD12864_H_ #include "typedef.h" typedef enum { FONT16_DEFAULT = (0x80+16), //16号,叠加显示 FONT12_DEFAULT = (0x80+12), //12号,叠加显示 FONT16_COVER = (16), //16号,覆盖显示 FONT12_COVER = (12), //12号,覆盖显示 FONT16_REVERSE = (0x40+16), //16号,反显显示 FONT12_REVERSE = (0x40+12), //12号,反显显示 }LCD12864_FONT_MODE; //LCD12864 句柄 typedef struct { u8 LCD_BUFF[8][128];//显存 //void (*UpdateGRAM)(u8 LCD_BUFF[8][128], u8 x1,u8 y1,u8 x2,u8 y2); }LCD12864_HANDLE; void LCD12864_GRAM_Init(LCD12864_HANDLE *pHandle);//LCD12864显存模式初始化 void LCD12864_GRAM_ShowString(LCD12864_HANDLE *pHandle, u16 x,u16 y,const char *pStr,LCD12864_FONT_MODE Font_MODE); //在显存指定位置显示字符串 #endif /* PROGRAM_LCD_LCD12864_H_ */ //测试线程 //测试线程 void *func(void *arg) { float ftemp = 0; char buff[64]; SPI_Init(&SPI_Handle, "/dev/spidev0.0"); //打开SPI驱动 setSPIReadBitsPerWord(SPI_Handle.fd, 8); //8bit模式 setSPIBitOrder(SPI_Handle.fd, MSBFIRST); //高位在前 //setSPIMaxSpeed(SPI_Handle.fd, 500); //设备SPI传输速度 10K setSPIDataMode(SPI_Handle.fd, SPI_MODE0); //模式0 if(initPinGPIO(BOARD_NANOPI_M1) < 0) //初始化开发板型号 { printf("error:gpio init error! "); } exportGPIOPin(LCD_RST_PIN_INDEX); //导出IO文件 RST接口 setGPIODirection(LCD_RST_PIN_INDEX, GPIO_OUT); //输出 exportGPIOPin(LCD_RS_PIN_INDEX); //导出IO文件 RS接口 setGPIODirection(LCD_RS_PIN_INDEX, GPIO_OUT); //输出 //初始化JLX12864G硬件 JLX12864G_Init(&mJLX12864G_Handle, JLX12864G_WriteData, JLX12864G_SetRS, JLX12864G_SetRST, JLX12864G_DelayMS, 40); LCD12864_GRAM_Init(&g_LCD12864_Handle); //初始化虚拟LCD12864屏幕 while(1) { ftemp = GetCPU_Temp(); //获取CPU温度 sprintf(buff,"CPU TEMP:%.02f",ftemp); //格式化字符串 LCD12864_GRAM_ShowString(&g_LCD12864_Handle, 0 ,0, buff, FONT16_COVER); //覆盖显示-将字符串在虚拟LCD12864中显示 JLX12864G_GRAM_Up(&mJLX12864G_Handle, g_LCD12864_Handle.LCD_BUFF, 0,0,128,64); //更新显存到JLX12864G sleep(3); } } 示例代码:https://download.csdn.net/download/cp1300/10611732