51系列单片机是很古老的单片机了。虽然古老,但在测使用上还是有一定优势的。我在买了电子模块时,一般首选ESP8266,使用ARduino开发环境进行测试。但有时候也会选用51单片机编程测试。主要是自己用51单片机很多年,51单片机的IO口控制指令很简单,不像Arm芯片那样,需要配置很多东西。这不最近和显示屏杠上了,买了很多显示屏玩,有OLED的,LCD的,也有TFT的。有I2C接口的,有SPI接口的,也有RGB并口的。买来了肯定是要测试的,玩的同时,也算是积累经验吧。
以下是一款1.3寸的240*240的显示屏,SPI接口:
接口定义如下:
驱动芯片是ST7789
程序使用IO口模拟SPI方式:
//1.3寸TFT_ST7735液晶驱动 #include<reg52.h> #include<absacc.h> #include<intrins.h> #include<string.h> #include<font.h> #include <I2C.h> //I2C协议 #include <Delay.h> //延时模块 #include <debug.h> //延时模块 #define uchar unsigned char #define uint unsigned int #define LEDS P2 //测试硬件平台:IAP15W4K58S4 //主频:11.0594MHZ //单片机IO推挽输出设置定义 //#define USE_LANDSCAPE//测试程序横竖屏切换,横屏请开启此宏,竖屏请屏蔽 //---------------------------液晶屏接线说明-------------------------------------// //接线前请参考液晶屏说明书第10页引脚定义 sbit bl =P1^4;//接模块BL引脚,背光可以采用IO控制或者PWM控制,也可以直接接到高电平常亮 sbit scl =P1^0;//接模块CLK引脚,接裸屏Pin9_SCL sbit sda =P1^1;//接模块DIN/MOSI引脚,接裸屏Pin8_SDA sbit rs =P1^3;//接模块D/C引脚,接裸屏Pin7_A0 sbit cs =P1^7;//接模块CE引脚,接裸屏Pin12_CS sbit reset =P1^2;//接模块RST引脚,接裸屏Pin6_RES //---------------------------End of液晶屏接线---------------------------------// //定义常用颜色 #define RED 0xf800 #define GREEN0x07e0 #define BLUE 0x001f #define WHITE0xffff #define BLACK0x0000 #define YELLOW 0xFFE0 #define GRAY0 0xEF7D #define GRAY1 0x8410 #define GRAY2 0x4208 void Contrast_Adjust(); code typFNT_GBK16 hz16[]; void Output_Pixel(uint x,uint y); void delay_ms(uint time) { uint i,j; for(i=0;i<time;i++) for(j=0;j<250;j++); } //向SPI总线传输一个8位数据 void SPI_WriteData(uchar Data) { unsigned char i=0; for(i=8;i>0;i--) { if(Data&0x80) sda=1; //输出数据 else sda=0; scl=0; scl=1; Data<<=1; } } //向液晶屏写一个8位指令 void Lcd_WriteIndex(uchar Data) { cs=0; rs=0; SPI_WriteData(Data); cs=1; } //向液晶屏写一个8位数据 void Lcd_WriteData(uchar Data) { unsigned char i=0; cs=0; rs=1; SPI_WriteData(Data); cs=1; } //向液晶屏写一个16位数据 void LCD_WriteData_16Bit(unsigned int Data) { unsigned char i=0; cs=0; rs=1; SPI_WriteData(Data>>8); //写入高8位数据 SPI_WriteData(Data); //写入低8位数据 cs=1; } void Reset() { reset=0; delay_ms(100); reset=1; delay_ms(100); } ////////////////////////////////////////////////////////////////////////////////////////////// //液晶屏初始化 for S6D02A1 void lcd_initial() { Reset();//Reset before LCD Init. //Lcd_WriteIndex(0x11);//Sleep exit delay_ms (120); Lcd_WriteIndex(0x36); Lcd_WriteData(0x00); Lcd_WriteIndex(0x3A); Lcd_WriteData(0x05); Lcd_WriteIndex(0xB2); Lcd_WriteData(0x0C); Lcd_WriteData(0x0C); Lcd_WriteData(0x00); Lcd_WriteData(0x33); Lcd_WriteData(0x33); Lcd_WriteIndex(0xB7); Lcd_WriteData(0x35); Lcd_WriteIndex(0xBB); Lcd_WriteData(0x19); Lcd_WriteIndex(0xC0); Lcd_WriteData(0x2C); Lcd_WriteIndex(0xC2); Lcd_WriteData(0x01); Lcd_WriteIndex(0xC3); Lcd_WriteData(0x12); Lcd_WriteIndex(0xC4); Lcd_WriteData(0x20); Lcd_WriteIndex(0xC6); Lcd_WriteData(0x0F); Lcd_WriteIndex(0xD0); Lcd_WriteData(0xA4); Lcd_WriteData(0xA1); Lcd_WriteIndex(0xE0); Lcd_WriteData(0xD0); Lcd_WriteData(0x04); Lcd_WriteData(0x0D); Lcd_WriteData(0x11); Lcd_WriteData(0x13); Lcd_WriteData(0x2B); Lcd_WriteData(0x3F); Lcd_WriteData(0x54); Lcd_WriteData(0x4C); Lcd_WriteData(0x18); Lcd_WriteData(0x0D); Lcd_WriteData(0x0B); Lcd_WriteData(0x1F); Lcd_WriteData(0x23); Lcd_WriteIndex(0xE1); Lcd_WriteData(0xD0); Lcd_WriteData(0x04); Lcd_WriteData(0x0C); Lcd_WriteData(0x11); Lcd_WriteData(0x13); Lcd_WriteData(0x2C); Lcd_WriteData(0x3F); Lcd_WriteData(0x44); Lcd_WriteData(0x51); Lcd_WriteData(0x2F); Lcd_WriteData(0x1F); Lcd_WriteData(0x1F); Lcd_WriteData(0x20); Lcd_WriteData(0x23); Lcd_WriteIndex(0x21); Lcd_WriteIndex(0x11); Lcd_WriteIndex(0x29); } /************************************************* 函数名:LCD_Set_Region 功能:设置lcd显示区域,在此区域写点数据自动换行 入口参数:xy起点和终点 返回值:无 *************************************************/ void Lcd_SetRegion(unsigned int x_start,unsigned int y_start,unsigned int x_end,unsigned int y_end) { Lcd_WriteIndex(0x2a); Lcd_WriteData(0x00); Lcd_WriteData(x_start); Lcd_WriteData(0x00); Lcd_WriteData(x_end); Lcd_WriteIndex(0x2b); Lcd_WriteData(0x00); Lcd_WriteData(y_start); Lcd_WriteData(0x00); Lcd_WriteData(y_end); Lcd_WriteIndex(0x2c); } void PutPixel(uint x_start,uint y_start,uint color) { Lcd_SetRegion(x_start,y_start,x_start+1,y_start+1); LCD_WriteData_16Bit(color); } void dsp_single_colour(int color) { uchar i,j; Lcd_SetRegion(0,0,240-1,240-1); for (i=0;i<240;i++) for (j=0;j<240;j++) LCD_WriteData_16Bit(color); } //采用设置窗口方法填充字库数据,相比Gui_DrawFont_GBK16更快速 //x:水平方向上的坐标 //y:垂直方向上的坐标 void Fast_DrawFont_GBK16(uint x, uint y, uint fc, uint bc, uchar *s) { unsigned char i,j; unsigned short k; uint HZnum; HZnum=sizeof(hz16)/sizeof(typFNT_GBK16); while(*s) { if((*s) >= 128) { for (k=0;k<HZnum;k++) { if ((hz16[k].Index[0]==*(s))&&(hz16[k].Index[1]==*(s+1))) { Lcd_SetRegion(x,y,x+16-1,y+16-1); for(i=0;i<16*2;i++) { for(j=0;j<8;j++) { if(hz16[k].Msk[i]&(0x80>>j)) LCD_WriteData_16Bit(fc); else { if (fc!=bc) LCD_WriteData_16Bit(bc); } } } } } s+=2;x+=16; } else { s+=1; } } } //此方法描绘汉字较慢 void Gui_DrawFont_GBK16(uint x, uint y, uint fc, uint bc, uchar *s) { unsigned char i,j; unsigned short k,x0; x0=x; while(*s) { if((*s) >= 128) { for (k=0;k<hz16_num;k++) { if ((hz16[k].Index[0]==*(s))&&(hz16[k].Index[1]==*(s+1))) { for(i=0;i<16;i++) { for(j=0;j<8;j++) { if(hz16[k].Msk[i*2]&(0x80>>j)) PutPixel(x+j,y+i,fc); else if (fc!=bc) PutPixel(x+j,y+i,bc); } for(j=0;j<8;j++) { if(hz16[k].Msk[i*2+1]&(0x80>>j)) PutPixel(x+j+8,y+i,fc); else if (fc!=bc) PutPixel(x+j+8,y+i,bc); } } } } s+=2;x+=16; } else { s+=1; } } } //清屏函数 //Color:要清屏的填充色 void LCD_Clear(uint Color) { uint i,j; Lcd_SetRegion(0,0,240-1,240-1); for(i=0;i<240;i++) { for (j=0;j<240;j++) { LCD_WriteData_16Bit(Color); } } } main() { lcd_initial(); bl=1; LCD_Clear(BLACK); //清屏 Fast_DrawFont_GBK16(8,10, BLUE, WHITE,"中文测试"); delay_ms(5000); while(1) { } }
显示效果(文字很小):