一个OLED的采坑之旅
最近在做某项目,拿到的一块oled屏幕 128*64
mcu 是 f103RC 512kb 的核
本来显彩色的 LCD 是直接 画对应的 像素点就行了
可是这个 OLED 屏幕的 设置却是下边的样子
1 OLED_DrawBMP(0,0,128,8, BMP3y); 2 3 OLED_ShowChar(10,1,( unsigned char *)"HelTecAutomation",1); 4 5 OLED_ShowChar(10,2,( unsigned char *)"HOLLEWORLD",1); 6 OLED_ShowChar(10,4,( unsigned char *)"Voltage:",1); 7 OLED_ShowChar(64,4,( unsigned char *)"20V ",1); 8 OLED_ShowChar(34,6,( unsigned char *)"2020-09-08",1);
这就给我们设置带来了很多问题
图片总是偏移了几个像素
直到我自己画图
转换 下边的设置很重要 不然图形显示是乱的
最后 发现 还是有一条亮边,真奇怪
只能修改 总宽度 感觉是没刷新这列导致的。于是
大功告成,显示完美
下边是代码,感觉还是不完美,比如我想自己画条线,但是画的是 | | | | 这种。很奇怪
#ifndef __OLED_H__ #define __OLED_H__ #include "stdint.h" #define OLED_CS PBout(6) #define OLED_DC PBout(7) #define Brightness 0xCF #define X_WIDTH 129 // 132 //0.96(SSD1306) is 128 ,1.30(SH1106) is 132 #define Y_WIDTH 64 #define Page 32 #define IIC_SPI_TYPE 1 //1 is the spi,0 is the i2c #define CHIP_IS_SSD1306 0 //1 - SSD1306; 0 -- SH1106 //#define INCH 0 // 0 is 0.96 inch & 0.91 inch & 1.3 inch & 1.54 inch,1 is 0.49 inch (This Macro definition is for IIC with SSD1306) void OLED_WrDat(uint8_t dat); void OLED_WrCmd(uint8_t cmd); void OLED_SetPos(unsigned char x, unsigned char y); void OLED_Fill(unsigned char bmp_dat); void OLED_CLS(void); void OLED_ON(void); void OLED_OFF(void); void OLED_Init(void); //void OLED_DrawPoint(unsigned char x,unsigned char y,unsigned char t); //void OLED_Char(unsigned char x, unsigned char y, unsigned char ch); void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize); void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N); void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]); void OLED_DrawBMP(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t BMPx[]); void OLED_Set_Pos(uint8_t x, uint8_t y); //汉字显示,设置显示坐标 void OLED_DrawLine(uint8_t x1,uint8_t y1,uint8_t x2,uint8_t y2,uint8_t mode); void OLED_DrawPoint(uint8_t x,uint8_t y,uint8_t t); void OLED_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); // OLED_Fill(0xFF);//屏幕全亮 void OLED_Refresh(void); /* for(i=0; i<8; i++) { OLED_ShowCN(i*16,0,i); //行,列,第几个汉字 OLED_ShowCN(i*16,2,i+8); } */ #endif
View Code
#include "spi.h" #include "OLED.h" #include "codetab.h" #include "delay.h" #include "sys.h" #include "delay.h" uint8_t OLED_GRAM[144][8]; void OLED_WrCmd(uint8_t cmd) { OLED_DC = 0; SPI3_ReadWriteByte(cmd); } void OLED_WrDat(uint8_t dat) { OLED_DC = 1; SPI3_ReadWriteByte(dat); } void OLED_SetPos(unsigned char x, unsigned char y) { OLED_WrCmd(0xb0+y); OLED_WrCmd(((x&0xf0)>>4)|0x10); OLED_WrCmd((x&0x0f)|0x01); } void OLED_Fill(unsigned char bmp_dat) { unsigned char y,x; for(y=0;y<Page;y++) { OLED_WrCmd(0xb0+y); OLED_WrCmd(0x01); OLED_WrCmd(0x10); for(x=0;x<X_WIDTH;x++) OLED_WrDat(bmp_dat); } } void OLED_CLS(void) { OLED_Fill(0x00); } void OLED_ON(void) { OLED_WrCmd(0X8D); OLED_WrCmd(0X14); OLED_WrCmd(0XAF); } void OLED_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );//PORTB时钟使能 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz GPIO_Init(GPIOB, &GPIO_InitStructure); //配置 GPIO_SetBits(GPIOB,GPIO_Pin_6 | GPIO_Pin_7); SPI3_Init(); OLED_CS = 0; delay_ms(100); #if CHIP_IS_SSD1306 OLED_WrCmd(0xae);//--turn off oled panel OLED_WrCmd(0x00);//---set low column address OLED_WrCmd(0x10);//---set high column address OLED_WrCmd(0x40);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F) OLED_WrCmd(0x81);//--set contrast control register OLED_WrCmd(Brightness); // Set SEG Output Current Brightness OLED_WrCmd(0xa1);//--Set SEG/Column Mapping OLED_WrCmd(0xc8);//Set COM/Row Scan Direction OLED_WrCmd(0xa6);//--set normal display OLED_WrCmd(0xa8);//--set multiplex ratio(1 to 64) OLED_WrCmd(0x3f);//--1/64 duty OLED_WrCmd(0xd3);//-set display offset Shift Mapping RAM Counter (0x00~0x3F) OLED_WrCmd(0x00);//-not offset OLED_WrCmd(0xd5);//--set display clock divide ratio/oscillator frequency OLED_WrCmd(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec OLED_WrCmd(0xd9);//--set pre-charge period OLED_WrCmd(0xf1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock OLED_WrCmd(0xda);//--set com pins hardware configuration OLED_WrCmd(0x12); OLED_WrCmd(0xdb);//--set vcomh OLED_WrCmd(0x40);//Set VCOM Deselect Level OLED_WrCmd(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02) OLED_WrCmd(0x02);// OLED_WrCmd(0x8d);//--set Charge Pump enable/disable OLED_WrCmd(0x14);//--set(0x10) disable OLED_WrCmd(0xa4);// Disable Entire Display On (0xa4/0xa5) OLED_WrCmd(0xa6);// Disable Inverse Display On (0xa6/a7) OLED_WrCmd(0xaf);//--turn on oled panel #else //1106 OLED_WrCmd(0xAE); /*display off*/ OLED_WrCmd(0x02); /*set lower column address*/ OLED_WrCmd(0x10); /*set higher column address*/ OLED_WrCmd(0x40); /*set display start line*/ OLED_WrCmd(0xB0); /*set page address*/ OLED_WrCmd(0x81); /*contract control*/ OLED_WrCmd(Brightness); /*128*/ OLED_WrCmd(0xA1); /*set segment remap*/ OLED_WrCmd(0xA6); /*normal / reverse*/ OLED_WrCmd(0xA8); /*multiplex ratio*/ OLED_WrCmd(0x3F); /*duty = 1/32*/ OLED_WrCmd(0xad); /*set charge pump enable*/ OLED_WrCmd(0x8b); /* 0x8a ??VCC */ OLED_WrCmd(0x30); /*0X30---0X33 set VPP 9V liangdu!!!!*/ OLED_WrCmd(0xC8); /*Com scan direction*/ OLED_WrCmd(0xD3); /*set display offset*/ OLED_WrCmd(0x00); /* 0x20 */ OLED_WrCmd(0xD5); /*set osc division*/ OLED_WrCmd(0x80); OLED_WrCmd(0xD9); /*set pre-charge period*/ OLED_WrCmd(0x1f); /*0x22*/ OLED_WrCmd(0xDA); /*set COM pins*/ OLED_WrCmd(0x12); //0x02 -- duanhang xianshi,0x12 -- lianxuhang xianshi!!!!!!!!! OLED_WrCmd(0xdb); /*set vcomh*/ OLED_WrCmd(0x40); OLED_WrCmd(0xAF); /*display ON*/ #endif OLED_Fill(0x00); OLED_SetPos(0,0); } //显示英文字符, void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize) { unsigned char c = 0,i = 0,j = 0; switch(TextSize) { case 1: { while(ch[j] != \'\0\') { c = ch[j] - 32; if(x > 126) { x = 0; y++; } OLED_SetPos(x,y); for(i=0;i<6;i++) OLED_WrDat(F6x8[c][i]); x += 6; j++; } }break; case 2: { while(ch[j] != \'\0\') { c = ch[j] - 32; if(x > 120) { x = 0; y++; } OLED_SetPos(x,y); for(i=0;i<8;i++) OLED_WrDat(F8X16[c*16+i]); OLED_SetPos(x,y+1); for(i=0;i<8;i++) OLED_WrDat(F8X16[c*16+i+8]); x += 8; j++; } }break; } } void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N) { unsigned char wm=0; unsigned int adder=32*N; OLED_SetPos(x , y); for(wm = 0;wm < 16;wm++) { OLED_WrDat(F16x16[adder]); adder += 1; } OLED_SetPos(x,y + 1); for(wm = 0;wm < 16;wm++) { OLED_WrDat(F16x16[adder]); adder += 1; } } //void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]) //{ // unsigned int j=0; // unsigned char x,y; // if(y1%8==0) // y = y1/8; // else // y = y1/8 + 1; // for(y=y0;y<y1;y++) // { // OLED_SetPos(x0,y); // for(x=x0;x<x1;x++) // { // OLED_WrDat(BMP[j++]); // } // } //} //显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7 void OLED_DrawBMP(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t BMPx[]) { u16 j = 0; uint8_t x, y; // if(y1 % 8 == 0) y = y1 / 8; // else y = y1 / 8 + 1; // for(y = y0; y < y1; y++) // { // OLED_SetPos(x0, y); // for(x = x0; x < x1; x++) // { // OLED_WrDat(BMPx[j++]); // } // } // if(y1 % Page == 0) y = y1 / Page; else y = y1 / Page + 1; for(y = y0; y < y1; y++) { OLED_SetPos(x0, y); for(x = x0; x < x1; x++) { OLED_WrDat(BMPx[j++]); } } } //更新显存到OLED void OLED_Refresh(void) { // for(y = 0; y < sizeof( OLED_GRAM[0]); y++) // { // OLED_SetPos(x0, y); // for(x = x0; x < x1; x++) // { // OLED_WrDat(OLED_GRAM[x,y]); // } // } //OLED_DrawBMP(0,0,127,7,OLED_GRAM); // u8 i,n; // for(i=0;i<8;i++) // { // OLED_WrDat(0xb0+i,OLED_CMD); //设置行起始地址 // OLED_WR_Byte(0x00,OLED_CMD); //设置低列起始地址 // OLED_WR_Byte(0x10,OLED_CMD); //设置高列起始地址 // for(n=0;n<128;n++) // OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA); // } } //画点 //x:0~127 //y:0~63 //t:1 填充 0,清空 void OLED_DrawPoint(uint8_t x,uint8_t y,uint8_t t) { uint8_t i,m,n; i=y/8; m=y%8; n=1<<m; if(t){ OLED_GRAM[x][i]|=n; OLED_SetPos(x, y); OLED_WrDat(0xff); } else { OLED_GRAM[x][i]=~OLED_GRAM[x][i]; OLED_GRAM[x][i]|=n; OLED_GRAM[x][i]=~OLED_GRAM[x][i]; } } //画线 //x1,y1:起点坐标 //x2,y2:结束坐标 void OLED_DrawLine(uint8_t x1,uint8_t y1,uint8_t x2,uint8_t y2,uint8_t mode) { u16 t; int xerr=0,yerr=0,delta_x,delta_y,distance; int incx,incy,uRow,uCol; 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_x;} if(delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 else distance=delta_y; for(t=0;t<distance+1;t++) { OLED_DrawPoint(uRow,uCol,mode);//画点 xerr+=delta_x; yerr+=delta_y; if(xerr>distance) { xerr-=distance; uRow+=incx; } if(yerr>distance) { yerr-=distance; uCol+=incy; } } } void OLED_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { OLED_DrawLine(x1,y1,x2,y1,0); OLED_DrawLine(x1,y1,x1,y2,0); OLED_DrawLine(x1,y2,x2,y2,1); OLED_DrawLine(x2,y1,x2,y2,1); } void OLED_Set_Pos(uint8_t x, uint8_t y) //汉字显示,设置显示坐标 { // OLED_WriteCmd(0xb0 + y); // OLED_WriteCmd(((x & 0xf0) >> 4) | 0x10); // OLED_WriteCmd((x & 0x0f) | 0x01); } void OLED_WriteData(uint8_t dat) //写一字节数据 { // uint8_t i = 8; // OLED_DC = 1; // OLED_SCL = 0; // for(i = 0; i < 8; i++) // { // if(dat & 0x80) // OLED_SDA = 1; // else // OLED_SDA = 0; // OLED_SCL = 1; // OLED_SCL = 0; // dat <<= 1; // } }
View Code
下面文章貌似解决了这个问题
https://blog.csdn.net/lagran/article/details/98893270
https://blog.csdn.net/qq_39492932/article/details/87097988