
這種OLED的液晶屏似乎很受電子愛好者的歡迎,原因大概是:
①這種屏小巧玲瓏,同樣是128*64點陣的液晶屏,這種屏的體積比以前那種LCD12864小了四分之一,作為DIY手表的屏幕剛剛好。
②功耗低,由于OLED是有機發光材料制作成的,沒有使用背光,所以功耗比使用LED作為背光的液晶屏,功耗要低很多。所以這塊液晶屏適合用于手表之類的手持設備。
③可以選擇的接口很多。接口和使用的液晶屏驅動芯片有關,大多數OLED12864使用的驅動芯片是SSD1306,這款驅動芯片提供給MCU的接口有5種,如下圖。本文使用I2C接口來驅動OLED,主要是因為I2C占用MCU的IO少,當然用SPI接口驅動OLED的也很多。
使用I2C接口時,D0腳作為I2C的SCLK時鐘信號線,D1,D2作為SDA數據信號線。D/C#引腳做為地址設定引腳,該引腳接地,OLED器件地址為0x78,該引腳上拉,OLED器件地址為0x7A。

當使用I2C時,SCLK和SDA引腳要加上拉電阻,關于上拉電阻要注意:
①如果I2C的速度很低,使用10K的上拉電阻是可以的,這個低速大概是100KHz
②如果I2C的速度很高,要達到300KHz左右,這個上拉電阻的阻值應該為4.7K
在淘寶上買的OLED模塊,有的直接焊接了10K的上拉電阻,這樣對于需要I2C高速通信的用戶來說,很不方便,不查看電路還以為是程序出了問題,很浪費時間。今天我就遇到了這個問題,查找了好長時間,手頭上又沒4.7K的電阻,只好又并了個10K的電阻。

上圖是SSD1306的顯存分布,y軸范圍是0~7,分為8個頁,x軸坐標是0~127.


上圖是對OLED寫入地址的設定.
SSD1306也有一些控制命令,詳情請查看SSD1306的數據手冊。
由于我的STM8L-DISCOVERY的芯片燒壞掉了,所以沒辦法再繼續用STM8L來寫程序了。去淘寶買了塊STM8S103F3的最小系統板,使用STM8L-DISCOVERY上的SWIM進行仿真調試。

第一次遇到,超過2000字不能發表的情況,大概是程序太長了。我把程序上傳到GitHub了,剛剛摸索著使用這個國外的網站進行代碼托管,由于是全英文的網站,還不是很會用。
- /*硬件連接*/
- // PB4--SCL PB5--SDA
- /****************************************************************************************
- *開發環境:IAR for stm8 v6.5.3
- *硬件平臺:STM8S103F3
- *功能說明:通過硬件I2C等待的方法,
- *作 者:茗風
- ****************************************************************************************/
- #include"iostm8s103f3.h"
- #include"stdbool.h"
- #include"stdint.h"
- /******************************************************************************************************
- * 名 稱: uint8_t I2C_ReadOneByteDataFromSlave(uint8_t address)
- * 功 能:從I2C從設備中讀取一字節的數據
- * 入口參數:address:讀取數據的寄存器地址
- * 出口參數:返回一個從I2C從設備指定地址讀到的數據
- * 說 明:
- * 范 例:無
- ******************************************************************************************************/
- uint8_t I2C_ReadOneByteDataFromSlave(uint8_t slave_address,uint8_t address)
- {
- volatile uint8_t t;
- //----------I2C起始信號--------------
- I2C_CR2_START=1;//產生一個起始條件
- while(!(I2C_SR1_SB==1));//讀SR1寄存器,清除SB標志位
- // _5NOPS;//根據數據手冊,檢測到標志位后,需插入5個NOP進行延時
-
- //-------發送寫I2C從器件地址---------
- I2C_DR=slave_address;//發送從設備地址
- while(!(I2C_SR1_ADDR==1));//讀SR1寄存器,清除ADDR標志位
- // _5NOPS;//根據數據手冊,檢測到標志位后,需插入5個NOP進行延時
- if(I2C_SR3_TRA==0)return 1;//讀SR3寄存器,清除ADDR標志位
- // 0: Data bytes received
- // 1: Data bytes transmitted
-
- //-----寫I2C從器件寄存器地址--------
- I2C_DR=address;
- while(!(I2C_SR1_BTF==1));//等待地址發送完成
- // _5NOPS;//根據數據手冊,檢測到標志位后,需插入5個NOP進行延時
-
- //--------I2C重復起始信號-----------
- I2C_CR2_START=1;//重復產生一個起始條件
- while(!(I2C_SR1_SB==1));//讀SR1寄存器,清除SB標志位
- // _5NOPS;//根據數據手冊,檢測到標志位后,需插入5個NOP進行延時
-
- //-------發送讀I2C從器件地址---------
- I2C_DR=0xD1;//發送從設備地址
- while(!(I2C_SR1_ADDR==1));//讀SR1寄存器,清除ADDR標志位
- // _5NOPS;//根據數據手冊,檢測到標志位后,需插入5個NOP進行延時
- if(I2C_SR3_TRA==1)return 1;//讀SR3寄存器,清除ADDR標志位
-
- //-------------停止信號-------------
- I2C_CR2_ACK=0;//ACK位控制著ACK信號,此位為0可以產生一個NOACK信號
- I2C_CR2_STOP=1;
-
- //-------------等待接收到數據-------------
- while(!(I2C_SR1_RXNE==1));//等待地址發送完成
-
- //-------------讀取數據-------------
- t=I2C_DR;
-
- return t;
- }
- /******************************************************************************************************
- * 名 稱:void I2C_WriteOneByteDataToSlave(uint8_t address,uint8_t dat)
- * 功 能:寫入一字節的數據到I2C設備中
- * 入口參數:address:寫入的數據存儲地址 dat:待寫入的數據
- * 出口參數:無
- * 說 明: 通過MSTM8L硬件寫入I2C設備一個字節的數據
- * 范 例:無
- ******************************************************************************************************/
- uint8_t I2C_WriteOneByteDataToSlave(uint8_t slave_address,uint8_t address,uint8_t dat)
- {
- volatile uint8_t t;
- I2C_CR2_ACK=1;
- //----------I2C起始信號--------------
- I2C_CR2_START=1;//產生一個起始條件
- while(!(I2C_SR1_SB==1));
- // _5NOPS;//根據數據手冊,檢測到標志位后,需插入5個NOP進行延時
- I2C_DR=slave_address;
-
- //--------寫I2C從器件地址-----------
- while(!(I2C_SR1_ADDR==1));
- // _5NOPS;//根據數據手冊,檢測到標志位后,需插入5個NOP進行延時
- if(I2C_SR3_TRA==0)return 1;//讀SR3寄存器,清除ADDR標志位
-
- //-----寫I2C從器件寄存器地址--------
- while(!(I2C_SR1_TXE==1));
- I2C_DR=address;
-
- //-------寫I2C數據到寄存器中--------
- while(!(I2C_SR1_TXE==1));
- I2C_DR=dat;
- while(!(I2C_SR1_TXE==1));
- while(!(I2C_SR1_BTF==1));
- // _5NOPS;//根據數據手冊,檢測到標志位后,需插入5個NOP進行延時
-
- //-------------停止信號-------------
- I2C_CR2_STOP=1;
- return 0;
- }
- /******************************************************************************************************
- * 功 能:從I2C從設備讀取多個字節數據
- * 入口函數:
- * 出口函數:
- * 說 明:
- * 范 例:
- * 日 期:
- ******************************************************************************************************/
- uint8_t I2C_ReadMultiBytesFromSlave(uint8_t slave_address,uint8_t address,uint8_t *rxbuf,uint8_t len)
- {
- volatile uint8_t i=0;
-
- if(len==0)return 1;//如果寫入字節長度為0退出
-
- I2C_CR2_ACK=1;
- //----------I2C起始信號--------------
- I2C_CR2_START=1;//產生一個起始條件
- while(!(I2C_SR1_SB==1));//讀SR1寄存器,清除SB標志位
-
- //-------發送寫I2C從器件地址---------
- I2C_DR=slave_address;//發送從設備地址
- while(!(I2C_SR1_ADDR==1));//讀SR1寄存器,清除ADDR標志位
- if(I2C_SR3_TRA==0)return 1;//讀SR3寄存器,清除ADDR標志位
- // 0: Data bytes received
- // 1: Data bytes transmitted
-
- //-----寫I2C從器件寄存器地址--------
- I2C_DR=address;
- while(!(I2C_SR1_BTF==1));//等待地址發送完成
-
- //--------I2C重復起始信號-----------
- I2C_CR2_START=1;//重復產生一個起始條件
- while(!(I2C_SR1_SB==1));//讀SR1寄存器,清除SB標志位
-
- //-------發送讀I2C從器件地址---------
- I2C_DR=0xD1;//發送從設備地址
- while(!(I2C_SR1_ADDR==1));//讀SR1寄存器,清除ADDR標志位
- if(I2C_SR3_TRA==1)return 1;//讀SR3寄存器,清除ADDR標志位
- //-------------讀取數據-------------
- if(len>1)
- {
- for( i=len;i>1;i-- )
- {
- while(!(I2C_SR1_RXNE==1));//等待I2C_DR接收到數
- *rxbuf++ = I2C_DR;
- }
- }
- //-------------停止信號-------------
- I2C_CR2_ACK=0;//ACK位控制著ACK信號,此位為0可以產生一個NOACK信號
- I2C_CR2_STOP=1;
-
- while(!(I2C_SR1_RXNE==1));//等待I2C_DR接收到數
- *rxbuf++ = I2C_DR;
-
- return 0;
- }
- /******************************************************************************************************
- * 名 稱:IIC_init()
- * 功 能:初始化I2C,系統主頻位8MHz,I2C通信速度333KHz
- * 入口 參數:無
- * 出口 參數:無
- * 說 明:PB4--SCL PB5--SDA
- * 范 例:無
- ******************************************************************************************************/
- void I2C_Init(void)
- {
- //----打開IIC外設時鐘----
- I2C_CR1_PE=0;
- I2C_CR2_ACK=1;
-
- //----I2C輸入時鐘頻率選擇----
- I2C_FREQR_FREQ=0x08;//8MHz
- /* The allowed range is between 1 MHz and 16 MHz
- 000000: not allowed
- 000001: 1 MHz
- 000010: 2 MHz
- ...
- 010000: 16 MHz */
-
- //----配置時鐘控制寄存器----
- I2C_CCRH=0;
- I2C_CCRH_F_S=1; //Fast mode I2C
- I2C_CCRH_DUTY=0;
- /* If DUTY = 0:
- Period(I2C) = 3* CCR * tMASTER
- thigh = CCR * tMASTER
- tlow = 2 * CCR * tMASTER*/
- I2C_CCRL=7; //SCL高電平時間配置
- //I2C的SCK時鐘設置為400KHz,則SCK周期為2.5us 2.5us/0.125/3=7
- //因為I2C_FREQR_FREQ=0x08,即I2C輸入時鐘頻率為8M,周期為0.125us
- //CCR=7時,SCK的低電平時間為2*tlow=2*7*0.125us=1.75us,SCk高電平時間為thigh=7*0.125us=0.875us
- //所以CCR=7時,SCK輸出頻率為380KHz
-
- //----配置上升時間寄存器----
- I2C_TRISER_TRISE=5;//in standard mode, the maximum allowed SCL rise time is 1000 ns.
- //1 us / 0.125 us = 8
- //+1
- I2C_CR1_PE=1;//
- }
- #define Write_CMD_TO_OLED12864(byte) I2C_WriteOneByteDataToSlave(0x78,0x00,byte)
- #define Write_DAT_TO_OLED12864(byte) I2C_WriteOneByteDataToSlave(0x78,0x40,byte)
- /************************************6*8的點陣************************************/
- const uint8_t ASCII_6X8[92][6] = //水平尋址
- {
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // sp
- { 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00 }, // !
- { 0x00, 0x00, 0x07, 0x00, 0x07, 0x00 }, // "
- { 0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14 }, // #
- { 0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12 }, // $
- { 0x00, 0x62, 0x64, 0x08, 0x13, 0x23 }, // %
- { 0x00, 0x36, 0x49, 0x55, 0x22, 0x50 }, // &
- { 0x00, 0x00, 0x05, 0x03, 0x00, 0x00 }, // '
- { 0x00, 0x00, 0x1c, 0x22, 0x41, 0x00 }, // (
- { 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00 }, // )
- { 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14 }, // *
- { 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08 }, // +
- { 0x00, 0x00, 0x00, 0xA0, 0x60, 0x00 }, // ,
- { 0x00, 0x08, 0x08, 0x08, 0x08, 0x08 }, // -
- { 0x00, 0x00, 0x60, 0x60, 0x00, 0x00 }, // .
- { 0x00, 0x20, 0x10, 0x08, 0x04, 0x02 }, // /
- { 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E }, // 0
- { 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00 }, // 1
- { 0x00, 0x42, 0x61, 0x51, 0x49, 0x46 }, // 2
- { 0x00, 0x21, 0x41, 0x45, 0x4B, 0x31 }, // 3
- { 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10 }, // 4
- { 0x00, 0x27, 0x45, 0x45, 0x45, 0x39 }, // 5
- { 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30 }, // 6
- { 0x00, 0x01, 0x71, 0x09, 0x05, 0x03 }, // 7
- { 0x00, 0x36, 0x49, 0x49, 0x49, 0x36 }, // 8
- { 0x00, 0x06, 0x49, 0x49, 0x29, 0x1E }, // 9
- { 0x00, 0x00, 0x36, 0x36, 0x00, 0x00 }, // :
- { 0x00, 0x00, 0x56, 0x36, 0x00, 0x00 }, // ;
- { 0x00, 0x08, 0x14, 0x22, 0x41, 0x00 }, // <
- { 0x00, 0x14, 0x14, 0x14, 0x14, 0x14 }, // =
- { 0x00, 0x00, 0x41, 0x22, 0x14, 0x08 }, // >
- { 0x00, 0x02, 0x01, 0x51, 0x09, 0x06 }, // ?
- { 0x00, 0x32, 0x49, 0x59, 0x51, 0x3E }, // @
- { 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C }, // A
- { 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36 }, // B
- { 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22 }, // C
- { 0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C }, // D
- { 0x00, 0x7F, 0x49, 0x49, 0x49, 0x41 }, // E
- { 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01 }, // F
- { 0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A }, // G
- { 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F }, // H
- { 0x00, 0x00, 0x41, 0x7F, 0x41, 0x00 }, // I
- { 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01 }, // J
- { 0x00, 0x7F, 0x08, 0x14, 0x22, 0x41 }, // K
- { 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40 }, // L
- { 0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F }, // M
- { 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F }, // N
- { 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E }, // O
- { 0x00, 0x7F, 0x09, 0x09, 0x09, 0x06 }, // P
- { 0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E }, // Q
- { 0x00, 0x7F, 0x09, 0x19, 0x29, 0x46 }, // R
- { 0x00, 0x46, 0x49, 0x49, 0x49, 0x31 }, // S
- { 0x00, 0x01, 0x01, 0x7F, 0x01, 0x01 }, // T
- { 0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F }, // U
- { 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F }, // V
- { 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F }, // W
- { 0x00, 0x63, 0x14, 0x08, 0x14, 0x63 }, // X
- { 0x00, 0x07, 0x08, 0x70, 0x08, 0x07 }, // Y
- { 0x00, 0x61, 0x51, 0x49, 0x45, 0x43 }, // Z
- { 0x00, 0x00, 0x7F, 0x41, 0x41, 0x00 }, // [
- { 0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55 }, // 55
- { 0x00, 0x00, 0x41, 0x41, 0x7F, 0x00 }, // ]
- { 0x00, 0x04, 0x02, 0x01, 0x02, 0x04 }, // ^
- { 0x00, 0x40, 0x40, 0x40, 0x40, 0x40 }, // _
- { 0x00, 0x00, 0x01, 0x02, 0x04, 0x00 }, // '
- { 0x00, 0x20, 0x54, 0x54, 0x54, 0x78 }, // a
- { 0x00, 0x7F, 0x48, 0x44, 0x44, 0x38 }, // b
- { 0x00, 0x38, 0x44, 0x44, 0x44, 0x20 }, // c
- { 0x00, 0x38, 0x44, 0x44, 0x48, 0x7F }, // d
- { 0x00, 0x38, 0x54, 0x54, 0x54, 0x18 }, // e
- { 0x00, 0x08, 0x7E, 0x09, 0x01, 0x02 }, // f
- { 0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C }, // g
- { 0x00, 0x7F, 0x08, 0x04, 0x04, 0x78 }, // h
- { 0x00, 0x00, 0x44, 0x7D, 0x40, 0x00 }, // i
- { 0x00, 0x40, 0x80, 0x84, 0x7D, 0x00 }, // j
- { 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00 }, // k
- { 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00 }, // l
- { 0x00, 0x7C, 0x04, 0x18, 0x04, 0x78 }, // m
- { 0x00, 0x7C, 0x08, 0x04, 0x04, 0x78 }, // n
- { 0x00, 0x38, 0x44, 0x44, 0x44, 0x38 }, // o
- { 0x00, 0xFC, 0x24, 0x24, 0x24, 0x18 }, // p
- { 0x00, 0x18, 0x24, 0x24, 0x18, 0xFC }, // q
- { 0x00, 0x7C, 0x08, 0x04, 0x04, 0x08 }, // r
- { 0x00, 0x48, 0x54, 0x54, 0x54, 0x20 }, // s
- { 0x00, 0x04, 0x3F, 0x44, 0x40, 0x20 }, // t
- { 0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C }, // u
- { 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C }, // v
- { 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C }, // w
- { 0x00, 0x44, 0x28, 0x10, 0x28, 0x44 }, // x
- { 0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C }, // y
- { 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44 }, // z
- { 0x14, 0x14, 0x14, 0x14, 0x14, 0x14 } // horiz lines
- };
- //漢字 “楠楠,我愛你!”先掃描這串漢字的上半部分,再掃描下半部分
- uint8_t Hzk1[]= //本數據由PCtoLCD取模軟件產生,手動改了一下漢字下半部分數據位置
- {
- //楠楠,我愛你!
- 0x84,0x64,0xFF,0x24,0xFA,0x0A,0x5A,0xEF,0x5A,0x0A,0xFA,0x00,/*"楠",0up*/
- 0x84,0x64,0xFF,0x24,0xFA,0x0A,0x5A,0xEF,0x5A,0x0A,0xFA,0x00,/*"楠",1up*/
- 0x00,0x00,0x00,0x00,0x00,0x00,/*",",2up*/
- 0x10,0x12,0x12,0xFF,0x91,0x10,0xFF,0x10,0x90,0x52,0x14,0x00,/*"我",3up*/
- 0x32,0x56,0x5A,0xD2,0x76,0x5A,0x51,0x51,0x59,0x55,0x31,0x00,/*"愛",4up*/
- 0x20,0x10,0xFC,0x03,0x10,0xCF,0x04,0xF4,0x04,0x54,0x8C,0x00,/*"你",5up*/
- 0x00,0x00,0x7C,0x00,0x00,0x00,/*"!",6up*/
- 0x00,0x00,0x0F,0x00,0x0F,0x01,0x01,0x07,0x01,0x09,0x0F,0x00,/*"楠",0*/
- 0x00,0x00,0x0F,0x00,0x0F,0x01,0x01,0x07,0x01,0x09,0x0F,0x00,/*"楠",1*/
-
- 0x04,0x03,0x00,0x00,0x00,0x00,/*",",2*/
- 0x02,0x02,0x09,0x0F,0x00,0x04,0x02,0x03,0x04,0x08,0x0E,0x00,/*"我",3*/
- 0x08,0x04,0x0A,0x09,0x0B,0x05,0x05,0x05,0x0B,0x08,0x08,0x00,/*"愛",4*/
- 0x00,0x00,0x0F,0x00,0x02,0x01,0x08,0x0F,0x00,0x00,0x03,0x00,/*"你",5*/
- 0x00,0x00,0x02,0x00,0x00,0x00/*"!",6*/
- };
- /******************************************************************************************************
- * 功 能:清屏
- * 入口函數:
- * 出口函數:
- * 說 明:
- * 范 例:
- * 日 期:2016年11月1日
- ******************************************************************************************************/
- void OLED12864_Clear(void)
- {
- uint8_t x,y;
- for(y=0;y<8;y++)
- {
- //設置地址
- Write_CMD_TO_OLED12864(0xB0+y);
- Write_CMD_TO_OLED12864(0x00);
- Write_CMD_TO_OLED12864(0x10);
- for(x=0;x<128;x++)
- {
- Write_DAT_TO_OLED12864(0x00);
- }
- }
- }
- /******************************************************************************************************
- * 功 能:OLED12864初始化配置
- * 入口函數:
- * 出口函數:
- * 說 明:設置顯示坐標
- * 作 者:茗風
- * 日 期:2016年11月1日
- ******************************************************************************************************/
- void OLED_Set_Pos(uint8_t x, uint8_t y)
- {
- if(y>7)return 1;//y軸
- Write_CMD_TO_OLED12864(0xB0+y);//y軸坐標,0xB0為y軸起始地址
- Write_CMD_TO_OLED12864((x&0x0F)+0x00);//x軸坐標低位
- Write_CMD_TO_OLED12864(((x&0xF0)>>4)+0x10);//x軸坐標高位
- }
- ///******************************************************************************************************
- //* 功 能 :向OLED12864寫一串字符函數
- //* 入口參數 :x x軸坐標,取值范圍(0~127)
- //* y y軸坐標,取值范圍(0~7)
- //* *s 一串字符
- //* 出口參數 :無
- //* 說 明 :顯示6*8一組標準ASCII字符串,顯示的坐標(x,y),y為頁范圍0~7
- //* 編寫日期 :2016年11月1日
- //* 作 者 :茗風
- //******************************************************************************************************/
- uint8_t OLED12864_Display_Char(uint8_t _char)
- {
- uint8_t i=0;
-
- _char -= 32;//計算ASCII字符在F6x8[][]數組中的位置
-
- for(i=0; i<6; i++)
- {
- Write_DAT_TO_OLED12864(ASCII_6X8[_char][i]);
- }
- return 0;
- }
- ///******************************************************************************************************
- //* 功 能 :向OLED12864寫一串字符函數
- //* 入口參數 :x x軸坐標,取值范圍(0~127)
- //* y y軸坐標,取值范圍(0~7),一共兩行
- //* *s 一串字符
- //* 出口參數 :無
- //* 說 明 :顯示6*8一組標準ASCII字符串,顯示的坐標(x,y),y為頁范圍0~7
- //* 編寫日期 :2016年11月1日
- //* 作 者 :茗風
- //******************************************************************************************************/
- uint8_t OLED12864_Display_String(uint8_t x,uint8_t y,uint8_t *s)
- {
- // uint8_t c=0, i=0;
- OLED_Set_Pos(x,y);
- while (*s != '\0')
- {
- // c = *s-32;//計算ASCII字符在F6x8[][]數組中的位置
- // if(x>126) {x=0; y++;}
- OLED12864_Display_Char(*s++);
- // x += 6;
- // s++;//指向字符串的指針自增,指向下一個字符
- }
- return 0;
- }
- ///******************************************************************************************************
- //* 功 能 :OLED12864顯示一個uint16_t類型的數據
- //* 入口參數 :x x軸坐標,取值范圍(0~127)
- //* y y軸坐標,取值范圍(0~7),一共兩行
- //* number 寫入的字符
- //* 出口參數 :無
- //* 說 明 :
- //* 編寫日期 :2016年10月22日
- //* 作 者 :茗風
- //******************************************************************************************************/
- void LCD1602_Display_Number(uint8_t x,uint8_t y,uint32_t _number)
- {
- // uint8_t tmp=0;
- OLED_Set_Pos(x,y);
-
- if(_number<10) //9
- {
- OLED12864_Display_Char(_number%10+48);
- }
- else if(_number<100) //98
- {
- OLED12864_Display_Char(_number/10+48);
- OLED12864_Display_Char(_number%10+48);
- }
- else if(_number<1000) //988
- {
- OLED12864_Display_Char(_number/100+48);
- OLED12864_Display_Char(_number%100/10+48);
- OLED12864_Display_Char(_number%10+48);
- }
- else if(_number<10000) //9999
- {
- OLED12864_Display_Char(_number/1000+48);
- OLED12864_Display_Char(_number%1000/100+48);
- OLED12864_Display_Char(_number%100/10+48);
- OLED12864_Display_Char(_number%10+48);
- }
- else if(_number<100000) //99999
- {
- OLED12864_Display_Char(_number/10000+48);
- OLED12864_Display_Char(_number%10000/1000+48);
- OLED12864_Display_Char(_number%1000/100+48);
- OLED12864_Display_Char(_number%100/10+48);
- OLED12864_Display_Char(_number%10+48);
- }
- else if(_number<1000000) //999999
- {
- OLED12864_Display_Char(_number/100000+48);
- OLED12864_Display_Char(_number%100000/10000+48);
- OLED12864_Display_Char(_number%10000/1000+48);
- OLED12864_Display_Char(_number%1000/100+48);
- OLED12864_Display_Char(_number%100/10+48);
- OLED12864_Display_Char(_number%10+48);
- }
- else if(_number<10000000) //999999
- {
- OLED12864_Display_Char(_number/1000000+48);
- OLED12864_Display_Char(_number%1000000/100000+48);
- OLED12864_Display_Char(_number%100000/10000+48);
- OLED12864_Display_Char(_number%10000/1000+48);
- OLED12864_Display_Char(_number%1000/100+48);
- OLED12864_Display_Char(_number%100/10+48);
- OLED12864_Display_Char(_number%10+48);
- }
- }
- ///******************************************************************************************************
- //* 功 能 :顯示一行漢字,漢字大小為12*12,先寫上半部分8個像素,再寫下半部分4個像素
- //* 入口參數 :x,y:漢字寫入的地址坐標 s:寫的漢字數組 len:漢字數組中的數據個數
- //* 出口參數 : 0:寫字串成功 1:坐標越界 2:字符越界
- //* 說 明 :注意,本函數暫時只能一次寫小于一行的漢字,多行需要分開寫
- //* 范 例 :無
- //* 日 期:2016年10月31日
- //******************************************************************************************************/
- uint8_t OLED12864_Display_SimplifiedChinese(uint8_t x,uint8_t y,uint8_t *s,uint16_t len)
- {
- static uint8_t i=0;
-
- len=len/2;//分上半部分和下半部分寫入
- //先寫上半部分8個像素
- OLED_Set_Pos(x,y);
- for(i=0;i<len;i++)
- {
- Write_DAT_TO_OLED12864(*s++);
- }
- //再寫下半部分4個像素
- OLED_Set_Pos(x,y+1);
- for(i=0;i<len;i++)
- {
- Write_DAT_TO_OLED12864(*s++);
- }
- return 0;
- }
- /******************************************************************************************************
- * 功 能:draw one picture
- * 入口函數:
- * 出口函數:
- * 說 明:
- * 范 例:
- * 日 期:2016年10月31日
- ******************************************************************************************************/
- //void OLED12864_Draw_One_Picture(void)
- //{
- // uint8_t x,y;
- // uint16_t i=0;
- // for(y=0;y<8;y++)
- // {
- // Write_CMD_TO_OLED12864(0xb0+y);
- // Write_CMD_TO_OLED12864(0x00);
- // Write_CMD_TO_OLED12864(0x10);
- // for(x=0;x<128;x++)
- // {
- // Write_DAT_TO_OLED12864(0x00);
- // }
- // }
- // for(y=0;y<8;y++)
- // {
- // Write_CMD_TO_OLED12864(0xb0+y);
- // Write_CMD_TO_OLED12864(0x00);
- // Write_CMD_TO_OLED12864(0x10);
- // for(x=0;x<128;x++)
- // {
- // Write_DAT_TO_OLED12864(show1[i++]);
- // delay_100us(1000);
- // }
- // }
- //}
- /******************************************************************************************************
- * 名 稱:void delay_100us(uint8_t x_us)
- * 功 能:延時100us
- * 入口參數:無
- * 出口參數:無
- * 說 明:
- * 范 例:無
- ******************************************************************************************************/
- void delay_100us(uint16_t x_us)
- {
- uint8_t j;
- while(x_us--)
- {
- for(j=0;j<33;j++);//2*40個指令周期
- }
- //delay_10ms共消耗 x_ms*2*255+2*x_ms個指令周期
- //*2*40+2*x_ms=80us+
- //16M/8/2=1M 一個指令周期為1us
- }
- /******************************************************************************************************
- * 功 能:OLED12864初始化配置
- * 入口函數:
- * 出口函數:
- * 說 明:
- * 范 例:
- * 日 期:2016年10月31日
- ******************************************************************************************************/
- void OLED12864_Init(void)
- {
- delay_100us(100);
- Write_CMD_TO_OLED12864(0xAE); //display off
- Write_CMD_TO_OLED12864(0x20); //Set Memory Addressing Mode
- Write_CMD_TO_OLED12864(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
- Write_CMD_TO_OLED12864(0xB0); //Set Page Start Address for Page Addressing Mode,0-7
- Write_CMD_TO_OLED12864(0xC8); //Set COM Output Scan Direction
- Write_CMD_TO_OLED12864(0x00);//---set low column address
- Write_CMD_TO_OLED12864(0x10);//---set high column address
- Write_CMD_TO_OLED12864(0x40);//--set start line address
- Write_CMD_TO_OLED12864(0x81);//--set contrast control register
- Write_CMD_TO_OLED12864(0x7F);
- Write_CMD_TO_OLED12864(0xA1);//--set segment re-map 0 to 127
- Write_CMD_TO_OLED12864(0xA6);//--set normal display
- Write_CMD_TO_OLED12864(0xA8);//--set multiplex ratio(1 to 64)
- Write_CMD_TO_OLED12864(0x3F);//
- Write_CMD_TO_OLED12864(0xA4);//0xa4,Output follows RAM content;0xa5,Output ignores RAM content
- Write_CMD_TO_OLED12864(0xD3);//-set display offset
- Write_CMD_TO_OLED12864(0x00);//-not offset
- Write_CMD_TO_OLED12864(0xD5);//--set display clock divide ratio/oscillator frequency
- Write_CMD_TO_OLED12864(0xF0);//--set divide ratio
- Write_CMD_TO_OLED12864(0xD9);//--set pre-charge period
- Write_CMD_TO_OLED12864(0x22); //
- Write_CMD_TO_OLED12864(0xDA);//--set com pins hardware configuration
- Write_CMD_TO_OLED12864(0x12);
- Write_CMD_TO_OLED12864(0xDB);//--set vcomh
- Write_CMD_TO_OLED12864(0x20);//0x20,0.77xVcc
- Write_CMD_TO_OLED12864(0x8D);//--set DC-DC enable
- Write_CMD_TO_OLED12864(0x14);//
- Write_CMD_TO_OLED12864(0xAF);//--turn on oled panel
- OLED12864_Clear();//清屏操作
- OLED12864_Display_String(0,3,"nan nan 5201314!");
- OLED12864_Display_SimplifiedChinese(30,0,Hzk1,sizeof(Hzk1));//楠楠,我愛你!
- // LCD1602_Display_Number(30,5,5201314);
- }
- void main(void)
- {
- CLK_CKDIVR =0x01; //16M/2^1=8M
- I2C_Init();
- OLED12864_Init();
- while(1)
- {
- //asm("wfi");
- }
- }
復制代碼
|