linux SPI操作LCD12864液晶

液晶型号为JLX12864 COG液晶,资料网上有,linux下面通过SPI与IO控制,IO控制使用的是文件方式,SPI是开发板提供的驱动,这个SPI驱动应该每家提供的都不一样,需要自己去按照驱动文档操作,主要不通电就是底层的配置不一样。

//SPI.c这个是打开SPI驱动

/*
 * SPI.c
 *
 *  Created on: 2018年8月2日
 *      Author: cfan
 */
#include <stdio.h>
#include <unistd.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <termios.h>
#include "SPI.h"
#include <errno.h>  	// 包含errno所需要的头文件
#include <string.h>  	// 包含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!\r\n",__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)\n",pSpiDeviceName, strerror(errno), errno);
		return errno;
	}
	else
	{
		printf("Open SPI OK!\r\n");

	}

	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 <sys/ioctl.h>
#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([email protected]整理)
*时间        			:	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([email protected]整理)
*时间        			:	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([email protected]整理)
*时间        			:	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([email protected]整理)
*时间        			:	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([email protected]整理)
*时间        			:	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([email protected]整理)
*时间        			:	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([email protected]整理)
*时间        			:	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([email protected]整理)
*时间        			:	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([email protected]整理)
*时间        			:	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液晶驱动
 * 作者:		[email protected]
 * 邮箱:		[email protected]
 * 创建时间:	2012年5月30日20:40
 * 最后修改时间:2012年5月30日
 * 详细:		2016-02-01:增加获取显存函数
*************************************************************************************************************/
#include "ascii_8x16.h"
#include "JLX12864G.H"
#include <stdio.h>
#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:命令
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	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
* 返回	:	无
* 依赖	:	底层宏定义
* 作者	:	[email protected]
* 时间	:	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
* 返回	:	无
* 依赖	:	底层宏定义
* 作者	:	[email protected]
* 时间	:	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:句柄;
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	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:句柄;
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	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:字体大小
* 返回	:	无
* 依赖	:	底层宏定义
* 作者	:	[email protected]
* 时间	:	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
* 作者	:	[email protected]
* 时间	:	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:对比度值
* 返回	:	无
* 依赖	:	底层宏定义
* 作者	:	[email protected]
* 时间	:	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:对比度
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	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!\r\n");
		return;
	}
	if(WriteData == NULL)
	{
		printf("JLX12864G:ERROR *WriteData is NULL!\r\n");
		return;
	}
	if(SetRS == NULL)
	{
		printf("JLX12864G:ERROR *SetRS is NULL!\r\n");
		return;
	}
	if(DelayMS == NULL)
	{
		printf("JLX12864G:ERROR *DelayMS is NULL!\r\n");
		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:终点坐标
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	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 <stdio.h>
#include <string.h>

/*************************************************************************************************************************
* 函数			:	void LCD12864_GRAM_Init(LCD12864_HANDLE *pHandle)
* 功能			:	LCD12864显存模式初始化
* 参数			:	pHandle:句柄;
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	20120531
* 最后修改时间 	: 	2018-08-12
* 说明			: 	无
*************************************************************************************************************************/
void LCD12864_GRAM_Init(LCD12864_HANDLE *pHandle)
{
	if(pHandle == NULL)
	{
		printf("LCD12864:ERROR *pHandle is NULL!\r\n");
		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
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	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
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	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:句柄;
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	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:汉子显示模式,
* 返回			:	无
* 依赖			:	画点函数
* 作者			:	[email protected]
* 时间			:	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:句柄;范围
* 返回			:	无
* 依赖			:	底层函数
* 作者			:	[email protected]
* 时间			:	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:句柄;范围
* 返回			:	无
* 依赖			:	底层函数
* 作者			:	[email protected]
* 时间			:	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:句柄;起点终点坐标
* 返回			:	无
* 依赖			:	画点函数
* 作者			:	[email protected]
* 时间			:	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:句柄;多边形的两个坐标
* 返回			:	无
* 依赖			:	画线函数
* 作者			:	[email protected]
* 时间			:	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:显示模式,
* 返回			:	无
* 依赖			:	画点函数
* 作者			:	[email protected]
* 时间			:	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!\r\n");
	}
	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

猜你喜欢

转载自blog.csdn.net/cp1300/article/details/81805436