SPI,是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便。
SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共有的,它们是SDI(数据输入),SDO(数据输出),SCK(时钟),CS(片选)。
#define CS_GPIO (0)
#define CLK_GPIO (1)
#define MOSI_GPIO (2)
#define MISO_GPIO (3)
#define IRQ_GPIO (4)
#define CS(a) Set_SPI_Related_Gpio(a, CS_GPIO)
#define DCLK(a) Set_SPI_Related_Gpio(a, CLK_GPIO)
#define DIN(a) Set_SPI_Related_Gpio(a, MOSI_GPIO)
#define DOUT() Get_SPI_Related_Gpio(MISO_GPIO)
/**
* @brief Write Byte to LCD
* @param byte : Byte
*/
void WriteByteSPI(unsigned char byte)
{
unsigned char buf;
unsigned char i;
CS(0);
for(i=0;i<8;i++)
{
buf=(byte>>(7-i))&0x1;
DIN(buf);
DCLK(0);
DCLK(1);
}
CS(1);
}
/**
* @brief Read data from spi
*/
static unsigned short ReadByteSPI(void)
{
unsigned short buf=0,temp;
unsigned char i;
uint level = 0;
DIN(0);
DCLK(1);
CS(0);
for(i=0;i<8;i++)
{
DCLK(0);
level = DOUT();
temp= (level) ? 1:0;
buf|=(temp<<(7-i));
//Delayus(5);
DCLK(0);
DCLK(1);
}
CS(1);
buf&=0xff;
return(buf);
}
//LCD.h
#include "HAL_conf.h"
#define SPI_CS(a) \
if (a) \
GPIOA->BSRR = GPIO_Pin_4; \
else \
GPIOA->BRR = GPIO_Pin_4;
#define SPI_DCLK(a) \
if (a) \
GPIOA->BSRR = GPIO_Pin_5; \
else \
GPIOA->BRR = GPIO_Pin_5;
#define SPI_SDA(a) \
if (a) \
GPIOA->BSRR = GPIO_Pin_7; \
else \
GPIOA->BRR = GPIO_Pin_7;
#define lcd_RS(a) \
if (a) \
GPIOA->BSRR = GPIO_Pin_3; \
else \
GPIOA->BRR = GPIO_Pin_3;
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define BROWN 0XBC40 //棕色
#define BRRED 0XFC07 //棕红色
#define GRAY 0X8430 //灰色
void LCD_Initial(void); //LCD初始化函数
void Delayms(unsigned short time);
void LCD_WriteRegIndex(unsigned char Index);
void LCD_WriteData(unsigned short dat);
void LCD_WR_REG(u16 Index,u16 CongfigTemp);
void Lcd_SetCursor(u16 x,u16 y);
void SPILCD_SetWindow(unsigned short xstat,unsigned short xend,unsigned short ystat,unsigned short yend);
void SPILCD_DrawPoint(unsigned short x,unsigned short y,unsigned short color);
void SPILCD_Clear(unsigned short Color);
void SPILCD_Clear_Fast(unsigned char single_Color);
void SPILCD_Fill(unsigned short xsta,unsigned short ysta,unsigned short xend,unsigned short yend,unsigned short color);
void SPILCD_DrawLine(unsigned short x1,unsigned short y1,unsigned short x2,unsigned short y2,unsigned short color);
void SPILCD_ShowChar(unsigned short x,unsigned short y,unsigned char num, unsigned int fColor, unsigned int bColor,unsigned char flag) ;
void LCD_PutString(unsigned short x, unsigned short y, char *s, unsigned int fColor, unsigned int bColor,unsigned char flag);
void LCD_Fill_Pic(u16 x, u16 y,u16 pic_H, u16 pic_V, const unsigned char* pic);
//LCD.c
#include "LCD.h"
#include "ASCII.h"
#include "GB1616.h" //16*16汉字字模
#define SPILCD_W 176
#define SPILCD_H 220
void Delayms(unsigned short time) //延时函数
{
unsigned short i,j;
for(i=0;i<time;i++)
for(j=0;j<5000;j++) ;
}
void LCD_WriteByteSPI(unsigned char byte) //SPI模拟函数,写一个8bit的数据
{
unsigned char buf;
unsigned char i;
for(i=0;i<8;i++)
{
buf=(byte>>(7-i))&0x1;
SPI_SDA(buf);
SPI_DCLK(0);
SPI_DCLK(1);
}
}
void LCD_WriteoneSPI(unsigned char byte) //写一个4bit的数据
{
unsigned char buf;
unsigned char i;
for(i=0;i<4;i++)
{
buf=(byte>>(3-i))&0x1;
SPI_SDA(buf);
SPI_DCLK(0);
SPI_DCLK(1);
}
}
void WriteComm(unsigned char dat) //写命令
{
// SPI_CS(0);
lcd_RS(0);
LCD_WriteByteSPI(dat);
lcd_RS(1);
// SPI_CS(1);
}
void LCD_WriteRegIndex(unsigned char Index) //写命令的参数
{
lcd_RS(0);
LCD_WriteByteSPI(Index);
lcd_RS(1);
}
void LCD_WriteData(unsigned short dat) //写数据
{
LCD_WriteByteSPI(dat>>8); // start byte RS=1,RW=0----Write a GRAM data
LCD_WriteByteSPI(dat);
}
/******************************************
函数名:Lcd写命令函数
功能:向Lcd指定位置写入应有命令或数据
入口参数:Index 要寻址的寄存器地址
ConfigTemp 写入的数据或命令值
******************************************/
void LCD_WR_REG(u16 Index,u16 CongfigTemp)
{
LCD_WriteRegIndex(Index);
LCD_WriteByteSPI(CongfigTemp);
//LCD_WriteData(CongfigTemp);
}
void LCD_Initial(void) //LCD初始化函数
{
GPIO_SetBits(GPIOA, GPIO_Pin_2);//打开背光
//Power Voltage Setting
LCD_WR_REG(0x1A,0x02); //BT
LCD_WR_REG(0x1B,0x88); //VRH
//****VCOM offset**///
LCD_WR_REG(0x23,0x00); //SEL_VCM
LCD_WR_REG(0x24,0xEE); //VCM
LCD_WR_REG(0x25,0x15); //VDV
LCD_WR_REG(0x2D,0x03); //NOW[2:0]=011
//Power on Setting
LCD_WR_REG(0x18,0x1E); //Frame rate 72Hz
LCD_WR_REG(0x19,0x01); //OSC_EN='1', start Osc
LCD_WR_REG(0x01,0x00); //DP_STB='0', out deep sleep
LCD_WR_REG(0x1F,0x88); //STB=0
Delayms(5);
LCD_WR_REG(0x1F,0x80); //DK=0
Delayms(5);
LCD_WR_REG(0x1F,0x90); //PON=1
Delayms(5);
LCD_WR_REG(0x1F,0xD0); //VCOMG=1
Delayms(5);
LCD_WR_REG(0x2F,0x00);
//262k/65k color selection
LCD_WR_REG(0x17,0x05); //default 0x06 262k color // 0x05 65k color
//SET PANEL
LCD_WR_REG(0x16,0xA0);
LCD_WR_REG(0x36,0x09); //REV_P, SM_P, GS_P, BGR_P, SS_P
LCD_WR_REG(0x29,0x31); //400 lines
LCD_WR_REG(0x71,0x1A); //RTN
//Gamma 2.2 Setting
LCD_WR_REG(0x40,0x01);
LCD_WR_REG(0x41,0x08);
LCD_WR_REG(0x42,0x04);
LCD_WR_REG(0x43,0x2D);
LCD_WR_REG(0x44,0x30);
LCD_WR_REG(0x45,0x3E);
LCD_WR_REG(0x46,0x02);
LCD_WR_REG(0x47,0x69);
LCD_WR_REG(0x48,0x07);
LCD_WR_REG(0x49,0x0E);
LCD_WR_REG(0x4A,0x12);
LCD_WR_REG(0x4B,0x14);
LCD_WR_REG(0x4C,0x17);
LCD_WR_REG(0x50,0x01);
LCD_WR_REG(0x51,0x0F);
LCD_WR_REG(0x52,0x12);
LCD_WR_REG(0x53,0x3B);
LCD_WR_REG(0x54,0x37);
LCD_WR_REG(0x55,0x3E);
LCD_WR_REG(0x56,0x16);
LCD_WR_REG(0x57,0x7D);
LCD_WR_REG(0x58,0x08);
LCD_WR_REG(0x59,0x0B);
LCD_WR_REG(0x5A,0x0D);
LCD_WR_REG(0x5B,0x11);
LCD_WR_REG(0x5C,0x18);
LCD_WR_REG(0x5D,0xFF);
LCD_WR_REG(0x1B,0x001a); //VRH
LCD_WR_REG(0x25,0x0055); //NVRH
LCD_WR_REG(0x1A,0x0010); //BT
LCD_WR_REG(0x1E,0x0038); //FS1
//Display ON Setting
LCD_WR_REG(0x28,0x38); //GON=1, DTE=1, D=10
Delayms(40);
LCD_WR_REG(0x28,0x3C); //GON=1, DTE=1, D=11
WriteComm(0x22); //Start GRAM write
}
/*************************************************
函数名:Lcd光标起点定位函数
功能:指定320240液晶上的一点作为写数据的起始点
入口参数:x 坐标 0~239
y 坐标 0~319
返回值:无
*************************************************/
void Lcd_SetCursor(u16 x,u16 y)
{
LCD_WriteRegIndex(0x20);
LCD_WriteData(x);//水平坐标
LCD_WriteRegIndex(0x21);
LCD_WriteData(y);//垂直坐标
}
void SPILCD_SetWindow(unsigned short xstat,unsigned short xend,unsigned short ystat,unsigned short yend)
{
//Set GRAM Area
LCD_WR_REG(0x02,xstat>>8);
LCD_WR_REG(0x03,xstat&0xff); //Column Start
LCD_WR_REG(0x04,xend>>8);
LCD_WR_REG(0x05,xend&0xff); //Column End
LCD_WR_REG(0x06,ystat>>8);
LCD_WR_REG(0x07,ystat&0xff); //Row Start
LCD_WR_REG(0x08,yend>>8);
LCD_WR_REG(0x09,yend&0xff); //Row End
WriteComm(0x22);
}
void SPILCD_Fill(unsigned short xsta,unsigned short ysta,unsigned short xend,unsigned short yend,unsigned short color)
{
unsigned short i,j;
//设置窗口
SPILCD_SetWindow(xsta,xend-1,ysta,yend-1);
for(i=xsta;i<=xend;i++)
for(j=ysta;j<=yend;j++)
{
LCD_WriteData(color); //显示所填充的颜色.
}
}
/******************************************
函数名:Lcd图像填充100*100
功能:向Lcd指定位置填充图像
入口参数:
******************************************/
void LCD_Fill_Pic(u16 x, u16 y,u16 pic_H, u16 pic_V, const unsigned char* pic)
{
unsigned long i,j;
j=pic_H*pic_V*2;
SPILCD_SetWindow(x,x+pic_H-1,y,y+pic_V-1);
for (i = 0; i < j; i++)
{
LCD_WriteByteSPI(pic[i]);
}
}
//=============== 在x,y 坐标上打一个颜色为Color的点 ===============
void DrawPixel(u16 x, u16 y, int Color)
{
SPILCD_SetWindow(x,x,y,y);
LCD_WriteData(Color);
}
//------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------
//8*16字体 ASCII码 显示
//函数名:SPILCD_ShowChar
//参 数:
//(x,y):
//num:要显示的字符:" "--->"~"
//flag:有背景色(1)无背景色(0)
void SPILCD_ShowChar(unsigned short x,unsigned short y,unsigned char num, unsigned int fColor, unsigned int bColor,unsigned char flag)
{
unsigned char temp;
unsigned int pos,i,j;
num=num-' ';//得到偏移后的值
i=num*16;
for(pos=0;pos<16;pos++)
{
temp=nAsciiDot[i+pos]; //调通调用ASCII字体
for(j=0;j<8;j++)
{
if(temp&0x80)
DrawPixel(x+j,y,fColor);
else
if(flag) DrawPixel(x+j,y,bColor); //如果背景色标志flag为1
temp<<=1;
}
y++;
}
}
//写一个16x16的汉字
void PutGB1616(unsigned short x, unsigned short y, unsigned char c[2], unsigned int fColor,unsigned int bColor,unsigned char flag)
{
unsigned int i,j,k;
unsigned short m;
for (k=0;k<64;k++) { //64标示自建汉字库中的个数,循环查询内码
if ((codeGB_16[k].Index[0]==c[0])&&(codeGB_16[k].Index[1]==c[1]))
{
for(i=0;i<32;i++)
{
m=codeGB_16[k].Msk[i];
for(j=0;j<8;j++)
{
if((m&0x80)==0x80) {
DrawPixel(x+j,y,fColor);
}
else {
if(flag) DrawPixel(x+j,y,bColor);
}
m=m<<1;
}
if(i%2){y++;x=x-8;}
else x=x+8;
}
}
}
}
//显示一串字
void LCD_PutString(unsigned short x, unsigned short y, char *s, unsigned int fColor, unsigned int bColor,unsigned char flag)
{
unsigned char l=0;
while(*s)
{
if( *s < (char)0x80)
{
SPILCD_ShowChar(x+l*8,y,*s,fColor,bColor,flag);
s++;l++;
}
else
{
PutGB1616(x+l*8,y,(unsigned char*)s,fColor,bColor,flag);
s+=2;l+=2;
}
}
}