使用GPIO模拟SPI是单片机开发中常用的一种手段,GPIO还可以模拟IIC等总线的时序,可以用在没有相应外设的处理器上,节省成本。 下面的代码是软模SPI写LCD5110的程序: - void WriteByte(unsigned char byte,unsigned char dc)
- {
- int i;
- CE(0);
- DC(dc);
- for(i=0;i<8;i++)
- {
- if(byte & 0x80)
- DIN(1);
- else
- DIN(0);
- CLK(0);
- // usleep(10);//LCD5110的响应速度很快,不加延时也行!!!
- CLK(1);
- // usleep(10);
- byte <<= 1;
- }
- CE(1);
- }
[color=rgb(51, 102, 153) !important]复制代码
下面的代码是刷新LCD的两个函数,第一个是使用84*48点阵的数组,第二个是使用84*6点阵的数组:
- int LCD_Buffer[48 * 84] =
- { 0x00,};
- void LCD_Refresh()
- {
- unsigned int i,j,k;
- unsigned char data;
- WriteByte(0x40,0);
- WriteByte(0x80,0);
- for(i=0;i<6;i++)
- {
- for(j=0;j<84;j++)
- {
- for(k=0;k<8;k++)
- {
- data >>= 1;
- if( LCD_Buffer[ ( (i<<3) + k ) * 84 + j ] )
- data |= 0x80;
- }
- // printf("%X ",data);
- WriteByte(data,1);
- }
- // printf("\r\n");
- }
- }
- unsigned char nBitmapDot[] = // 数据表
- {
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0xE0,0xE0,0xE0,
- 0xE0,0xE0,0xE0,0xE0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x06,0x0F,0x0F,0x07,0x0F,0x0E,0x1E,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
- 0x01,0x01,0x00,0x00,0x80,0xC0,0xE0,0xF0,0xFF,0x7F,0x1F,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x3C,0x7E,0x7C,0x70,0x70,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0xE0,
- 0xC0,0x30,0x78,0x78,0x78,0x7C,0x7E,0x7F,0x77,0x77,0xF3,0xF1,0xF0,0xF0,0x70,0x70,
- 0x70,0xF0,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0xF0,0xE0,0xE0,0xC0,0x80,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,
- 0xFF,0xFF,0x7F,0x01,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0xE0,0xF8,0xFF,0x3F,0x0F,
- 0x03,0x03,0x03,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x01,0x01,0x07,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0xC0,0xE0,
- 0xF8,0x7E,0x3F,0x1F,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x07,0x07,0x03,
- 0x01,0x80,0xC0,0xE0,0xF0,0xF8,0x7C,0x3E,0x0F,0x8F,0xC7,0x80,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,
- 0x03,0x03,0x03,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x03,0x01,0x00,0x00,0x00,0x00,0x07,0x0F,0x0F,
- 0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0F,0x07,0x07,0x07,0x07,0x03,0x03,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
- };
- void LCD_Refresh2(unsigned char *buff)
- {
- unsigned int i,j;
- WriteByte(0x40,0);
- WriteByte(0x80,0);
- // for(i=0;i<6;i++)
- // {
- // for(j=0;j<84;j++)
- // {
- // WriteByte(buff[i*84 + j],1);
- // }
- // }
- for(i=0;i<6*84;i++)
- {
- WriteByte(buff,1);
- }
- }
[color=rgb(51, 102, 153) !important]复制代码
初始化GPIO以及LCD5110代码:
- GPIO_Init();
- GPIO_ConfigPin(PC,0,OUT); //CLK
- GPIO_ConfigPin(PC,1,OUT); //DC
- GPIO_ConfigPin(PC,2,OUT); //DIN
- GPIO_ConfigPin(PC,3,OUT); //CE
- GPIO_ConfigPin(PA,15,OUT); //LED
- while(i--)
- {
- GPIO_SetPin(PA,15,1);
- usleep(50000);
- GPIO_SetPin(PA,15,0);
- usleep(50000);
- }
- unsigned int data;
- WriteByte(0x21,0);
- WriteByte(0xc8,0);
- WriteByte(0x06,0);
- WriteByte(0x13,0);
- WriteByte(0x20,0);
- WriteByte(0x0c,0);
- WriteByte(0x40,0);
- WriteByte(0x80,0);
[color=rgb(51, 102, 153) !important]复制代码
初始化LCD之后调用LCD_Refresh或者LCD_Refresh2即可看到图片显示。 在此基础上需要添加屏幕绘点的函数:
- void LCD_DrawDot(int x,int y,int onoff)
- {
- int a = y / 8,b = y % 8;
- if(onoff)
- {
- LCD_Buffer[a * 84 + x] |= (0x01 << b);
- }
- else
- {
- LCD_Buffer[a * 84 + x] &= ~(0x01 << b);
- }
- WriteByte(0x80 | x,0);
- WriteByte(0x40 | a,0);
- WriteByte(LCD_Buffer[a * 84 + x],1);
- }
[color=rgb(51, 102, 153) !important]复制代码
使用的缓冲区是84*6的,所以这里的LCD_DrawDot函数是在84*6的数组中进行绘制点,绘点不会影响与该像素点在同一个字节中的其他7个像素,使用的是或操作和与操作。有了这个绘点的基础函数就可以进行画线、画圆等函数,同样的也可以进行绘制汉字和ASCII码。 在绘制汉字和ASCII码之前需要了解一下GB2312和ASCII码表的编码规范,首先ASCII码比较简单,我制作的ASCII码字库是从‘ ’到‘~’的,全部字符如下: !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~,使用的是8*16点阵,有点浪费空间其实6*12就够了貌似,但是为了配合汉字的16*16还是使用了8*16点阵。ASCII字库一共使用了1520字节的空间,存储在字库文件的前1520字节,后面的空间用于存储GB2312字库空间。GB2312的内容 太多了,网上一大把的就不贴出来了,但是这里要说说GB2312的编码规则。 ASCII码规定每个字符使用一个字节表示,并且该字节的范围为0x00到0x7F,所以当一个字符在0x00到0x7f之间的时候标志这个字符是一个ASCII字符,要从ASCII码库中提取对应的点阵数据显示。当一个字符的编码大于0xA0时则表示这个字符不是ASCII码字符了,是GB2312或者其他编码的字符例如UTF8等。程序中的汉字可能是GB2312编码也可能是其他编码格式,需要手动调节编辑器的编码方式,例如使用Notepad++时选择格式-》中文-》GB2312,这样才能保证程序中的中文是以GB2312的编码格式存储在字符串中的。GB2312编码规定一个字符是有两个字节组成的,两个字节的范围都是A1A1-FEFE,所以可以通过范围来判断是否是GB2312字符。GB2312的编码标准中有区码和位码,前者用于表示汉字所在的区,后者用于表示汉字所在区中的偏移量, 具体的编码规范可以参考:http://tools.jb51.net/table/gb2312 和 http://www.qqxiuzi.cn/zh/hanzi-gb2312-bianma.php两篇文章。 程序上有三个关于绘制字符的函数,第一个是绘制ASCII字符函数,第二个是绘制GB2312字符函数,最后一用于整合前面两个函数。 - void LCD_DrawAscii(int x,int y,unsigned short offset)
- {
- unsigned int i,j;
- for(i=0;i<16;i++)
- {
- for(j=0;j<8;j++)
- {
- if(FontData[offset*16 + i] & (0x80 >> j))
- LCD_DrawDot(x + j, y + i,1);
- else
- LCD_DrawDot(x + j,y + i,0);
- }
- }
- }
- void LCD_DrawHanzi(int x,int y,unsigned short offset)
- {
- unsigned int i,j;
- for(i=0;i<16;i++)
- {
- for(j=0;j<16;j++)
- {
- if(FontData[offset*32 + 0x5f0 + i*2 + j/8] & (0x80 >> j%8))
- LCD_DrawDot(x + j, y + i,1);
- else
- LCD_DrawDot(x + j,y + i,0);
- }
- }
- }
- void LCD_DrawText(int x,int y,char *text)
- {
- unsigned int i,j;
- for(i=0;text!='\0';i++)
- {
- if(text < 0xA0) //ASCII
- {
- LCD_DrawAscii(x,y,text - ' ');
- x += 8;
- }
- else //chinese
- {
- LCD_DrawHanzi(x,y,(text-0xA1)*94 + (text[++i] - 0xA1)); //这里i要自加1个因为汉子占用两个字节
- x += 16;
- }
- }
- }
[color=rgb(51, 102, 153) !important]复制代码
LCD_DrawText函数的具体功能是在x、y像素位置绘制一个字符串text,这个函数会根据字符的类型调用LCD_DrawAscii和LCD_DrawHanzi函数实现字符绘制功能,主函数测试程序如下: - int fd;
- struct stat file_stat;
- if((fd = open("ASCII+GB2312.bin",O_RDWR)) < 0)
- {
- printf("open gb2312 failed\r\n");
- goto close;
- }
- if(stat("ASCII+GB2312.bin",&file_stat) < 0)
- {
- printf("stat failed\r\n");
- goto close;
- }
- printf("filesize:%d\r\n",file_stat.st_size);
- FontData = (unsigned char *)malloc(file_stat.st_size);
- if(FontData == NULL)
- {
- printf("malloc failed\r\n");
- goto close;
- }
- read(fd,FontData,file_stat.st_size);
- LCD_DrawText(0,0,"汤权1994");
- LCD_DrawText(0,16,"123我是谁");
- LCD_DrawText(0,32,"中华人民");
[color=rgb(51, 102, 153) !important]复制代码
程序的执行效果如下:
转载自网络,版权归原作所有。
|