//-----------------OLED端口預定義----------------
#define OLED_SCL_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_0) //CLK SCL 置0
#define OLED_SCL_Set() GPIO_SetBits(GPIOA,GPIO_Pin_0)
#define OLED_SDA_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_1) //MOSI SDA 置0
#define OLED_SDA_Set() GPIO_SetBits(GPIOA,GPIO_Pin_1)
#define OLED_RES_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_2) //RES 復位 置0
#define OLED_RES_Set() GPIO_SetBits(GPIOA,GPIO_Pin_2)
#define OLED_DC_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_3) //DC 數據/命令選擇 置0
#define OLED_DC_Set() GPIO_SetBits(GPIOA,GPIO_Pin_3)
#define OLED_CS_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_4) //CS 片選 置0
#define OLED_CS_Set() GPIO_SetBits(GPIOA,GPIO_Pin_4)
//使用STM32 的PA0、PA1、PA2、PA3、PA4的IO口
//OLED模塊只支持向模塊寫數據不能讀數據,所以只需要寫SPI發送 MOSI SDA即可
#define OLED_CMD 0 //寫命令
#define OLED_DATA 1 //寫數據
//*** 自定義的 24*24 ASICII字庫 ******************************************************
const unsigned char asc2_2412[ ][36]={
{0x00,0x00,0x80,0xC0,0x60,0x20,0x20,0x60,0xC0,0x80,0x00,0x00,0x00,0xFE,0xFF,0x01,0x00,0x00,0x00,
0x00,0x01,0xFF,0xFE,0x00,0x00,0x01,0x07,0x0E,0x18,0x10,0x10,0x18,0x0E,0x07,0x01,0x00},// "0" 0
{0x00,0x00,0x80,0x80,0x80,0xC0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x1F,0x1F,0x10,0x10,0x10,0x00,0x00},// "1" 1
{0x00,0x80,0x40,0x20,0x20,0x20,0x20,0x60,0xC0,0x80,0x00,0x00,0x00,0x03,0x03,0x00,0x80,0x40,0x20,
0x38,0x1F,0x07,0x00,0x00,0x00,0x1C,0x1A,0x19,0x18,0x18,0x18,0x18,0x18,0x1F,0x00,0x00},//"2" 2
{0x00,0x00,0x00,0x00,0x80,0xE0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x7C,0x43,0x40,0x47,
0x7F,0xF8,0x80,0x00,0x00,0x10,0x18,0x1F,0x10,0x00,0x00,0x00,0x00,0x13,0x1F,0x1C,0x10}, //"A" 4
{0x20,0xE0,0xE0,0x20,0x20,0x20,0x20,0x60,0xC0,0x80,0x00,0x00,0x00,0xFF,0xFF,0x10,0x10,0x10,0x10,
0x18,0x2F,0xE7,0x80,0x00,0x10,0x1F,0x1F,0x10,0x10,0x10,0x10,0x10,0x18,0x0F,0x07,0x00},//"B" 5
{0x00,0x00,0x80,0xC0,0x40,0x20,0x20,0x20,0x20,0x60,0xE0,0x00,0x00,0xFC,0xFF,0x01,0x00,0x00,0x00,
0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x07,0x0E,0x18,0x10,0x10,0x10,0x08,0x04,0x03,0x00},//"C" 6
}
//**** 自定義的漢字庫Hzk [ ][32] *****************************
//字庫代碼用取模軟件 PCtoLCD等生成字母、漢字、圖片等生成。
const unsigned char Hzk [ ][32] = {
{0x00,0x80,0x60,0xF8,0x07,0x40,0x20,0x18,0x0F,0x08,0xC8,0x08,0x08,0x28,0x18,0x00,0x01,0x00,0x00,
0xFF,0x00,0x10,0x0C,0x03,0x40,0x80,0x7F,0x00,0x01,0x06,0x18,0x00}, //"你" 0
{0x10,0x10,0xF0,0x1F,0x10,0xF0,0x00,0x80,0x82,0x82,0xE2,0x92,0x8A,0x86,0x80,0x00,0x40,0x22,0x15,
0x08,0x16,0x61,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00}, //"好" 1
}
//***************************************************************************************************
//*** OLED的初始化 *****************************************************************************
void OLED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE); //使能A端口時鍾
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA
GPIO_SetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_15);
//初始IO置1
OLED_RES_Clr(); //復位拉低
delay_ms(200); //延時
OLED_RES_Set(); //復位結束拉高
OLED_WR_Byte(0xAE,OLED_CMD); //亮屏滅屏指令 OFF/ON: AE/AF)
OLED_WR_Byte(0x00,OLED_CMD); //設起始列地址指令,用8位中低4位
OLED_WR_Byte(0x10,OLED_CMD); //設起始列地址指令,用8位中高4位
OLED_WR_Byte(0x40,OLED_CMD); //設起始行地址指令
OLED_WR_Byte(0x81,OLED_CMD); // 81對比度設置指令,接着發送一個值來設置
OLED_WR_Byte(0xCF,OLED_CMD); // 屏幕對比度值(0X00--0XFF),FF最大
OLED_WR_Byte(0xA1,OLED_CMD); //--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
OLED_WR_Byte(0xC8,OLED_CMD); //Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
OLED_WR_Byte(0xA8,OLED_CMD); //設置驅動路數指令 (1 to 64)
OLED_WR_Byte(0x3f,OLED_CMD); // 默認0X3F(1/64) duty
OLED_WR_Byte(0xD3,OLED_CMD); //設置顯示偏移指令 (0x00~0x3F)
OLED_WR_Byte(0x00,OLED_CMD); //-00 不偏移
OLED_WR_Byte(0xd5,OLED_CMD); //設置時鍾分頻因子,震盪頻率指令
OLED_WR_Byte(0x80,OLED_CMD); //[3:0],分頻因子;[7:4],震盪頻率t Clock as 100 Frames/Sec
OLED_WR_Byte(0xD9,OLED_CMD); //設置預充電周期指令,下面跟值
OLED_WR_Byte(0xF1,OLED_CMD); //預充15時鍾/放電1時鍾 [3:0],PHASE 1;[7:4],PHASE 2;
OLED_WR_Byte(0xDA,OLED_CMD); //設置COM硬件引腳配置 下面跟值
OLED_WR_Byte(0x12,OLED_CMD); //[5:4]配置
OLED_WR_Byte(0xDB,OLED_CMD); //設置VCOMH 電壓倍率指令,下面跟值
OLED_WR_Byte(0x40,OLED_CMD); //40 Deselect Level,[6:4] 000,0.65*vcc;001,011,0.83*vcc;
OLED_WR_Byte(0x20,OLED_CMD); //設置內存地址模式 (0x00/0x01/0x02) 下面跟值
OLED_WR_Byte(0x02,OLED_CMD); //[1:0],00/列地址模式,01/行地址模式,10/頁地址模式,默認10;
OLED_WR_Byte(0x8D,OLED_CMD); //電荷泵的指令,下面跟值
OLED_WR_Byte(0x14,OLED_CMD); //bit2,開啟/關閉(0為關閉,1為開啟)(0x10) disable
OLED_WR_Byte(0xA4,OLED_CMD); //全局顯示開啟,bit0: 1/開啟,0/關閉;(白屏/黑屏) (0xa4/0xa5)
OLED_WR_Byte(0xA6,OLED_CMD); //設置正常顯示方式;bit0:0/A6,全屏黑底藍字;反相顯示bit0:1/A7,黑字藍底
OLED_Clear();
OLED_WR_Byte(0xAF,OLED_CMD);// 亮屏
}
//***** 寫字節函數 ****************************************************************************
void OLED_WR_Byte(u8 dat,u8 cmd) // 數據/命令標志, 0表示命令,1表示數據
{
u8 i;
if(cmd) //如果cmd=1,是命令
OLED_DC_Set(); //DC置1
else
OLED_DC_Clr(); //cmd=0,是數據DC置0
OLED_CS_Clr(); //CS置0 芯片使能
for(i=0;i<8;i++) //8位數據循環移位
{
OLED_SCL_Clr(); //SCL置0
if(dat&0x80) //數據和0x80與,判斷數據最高位是否=1
OLED_SDA_Set(); //最高位=1,MOSI SDA輸出1
else
OLED_SDA_Clr(); //最高位=0,MOSI SDA 輸出0
OLED_SCL_Set(); //CLK置1
dat<<=1; //最高移位移走,次高位頂上
}
OLED_CS_Set(); //發送完畢,片選置1 失能
OLED_DC_Set(); //命令數據選擇重置1
}
//*** 更新OLED顯存 (1屏126*64點) ************************************************
void OLED_Refresh(void)
{
u8 i,n;
for(i=0;i<8;i++) //i為屏映射數組的行/頁,上下共8頁,每行/頁8位*128位/列
{
OLED_WR_Byte(0xb0+i,OLED_CMD); //設置行起始地址,實際用該字節低3位 0-8頁就夠了
OLED_WR_Byte(0x00,OLED_CMD); //設置低8位,實際用該字節低4位 列起始地址
OLED_WR_Byte(0x10,OLED_CMD); //設置高8位,實際用該字節高4位 0-127列就夠了
for(n=0;n<128;n++) //n為屏映射數組的列,左右共128列,1行1列是8位
// for(n=0;n<130;n++) //屏邊框亮條可修改此值
OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA); //OLED_DATA預定義為1/數據
} //用i頁n列取屏映射數組GRAM內對應的數據,該數據刷OLED對應的點
} //OLED收到數據刷新屏幕對應點后,按設置的刷新模式(頁地址模式),
//OLED行不動列地址自動加1,等待再次接收數據。
//*** 清屏函數 ****************************************************************************************************
void OLED_Clear(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
for(n=0;n<128;n++)
{
OLED_GRAM[n][i]=0; //清除所有數據數組
}
}
OLED_Refresh(); //空數組刷新顯示
}
//*** 畫點 *********************************************************
//x:0~127 y:0~63 t:1填充 /0清空
void OLED_DrawPoint(u8 x,u8 y,u8 t)
{
u8 i,m,n;
i=y/8; //輸入的Y坐標要除以8,以定位到要改變的那個點的相應字節,因為是以字節形式來寫入的
m=y%8; // 該點在該字節中的位置
n=1<<m; //屏坐標和數組是上下相反,要把該點y坐標左移寫入n
if(t)
{OLED_GRAM[x][i]|=n;} //t=1,就把該點寫1
else
{
OLED_GRAM[x][i]=~OLED_GRAM[x][i];
OLED_GRAM[x][i]|=n;
OLED_GRAM[x][i]=~OLED_GRAM[x][i];
}
}
//*** 在指定位置顯示一個字符,包括部分字符 ***********************************************
//x:0~127
//y:0~63
//size1:選擇字體 6x8/6x12/8x16/12x24
//mode:0,反色顯示;1,正常顯示
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size1,u8 mode)
{
u8 i,m,temp,size2,chr1;
u8 x0=x,y0=y;
if(size1==8)size2=6;
else size2=(size1/8+((size1%8)?1:0))*(size1/2); //得到字體一個字符對應點陣集所占的字節數
chr1=chr-' '; //計算偏移后的值
for(i=0;i<size2;i++)
{
if(size1==8)
{temp=asc2_0806[chr1][i];} //調用0806字體
else if(size1==12)
{temp=asc2_1206[chr1][i];} //調用1206字體
else if(size1==16)
{temp=asc2_1608[chr1][i];} //調用1608字體
else if(size1==24)
{temp=asc2_2412[chr1][i];} //調用2412字體
else return;
for(m=0;m<8;m++)
{
if(temp&0x01)OLED_DrawPoint(x,y,mode);
else OLED_DrawPoint(x,y,!mode);
temp>>=1;
y++;
}
x++;
if((size1!=8)&&((x-x0)==size1/2))
{ x=x0;y0=y0+8;}
y=y0;
}
}