日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

基于SPI的OLED温湿度显示

發布時間:2024/3/12 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于SPI的OLED温湿度显示 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文首先會簡單介紹SPI通信協議,然后后面的實驗分為兩個板塊,一個是OLED屏的使用,另一個是在此基礎上,結合上次實驗(結尾會附上鏈接),用OLED屏顯示溫濕度信息。
實驗器材:STM32F103C8T6、0.96寸OLED屏、AHT20溫濕度傳感器、杜邦線若干
實驗環境:Keil μVision5、PCtoLCD2002


文章目錄

  • 一、SPI協議
    • 1. SPI簡介
  • 二、OLED屏的簡單應用
    • 1. OLED原理
    • 2. OLED顯示文字
      • 2.1 部分代碼實現思想
      • 2.2 完整代碼
        • `oled.h`
        • `oled.c`
        • `gui.h`
        • `gui.c`
        • `spi.h`
        • `spi.c`
        • `main.c`
      • 2.3 實驗效果
  • 三、OLED屏的溫濕度顯示
    • 1. 部分代碼實現思想
    • 2. 完整代碼
    • 3. 實驗效果
  • 四、OLED屏的滾動顯示
    • 1. 部分代碼實現思想
    • 2. 完整代碼
    • 3. 實驗效果
  • 五、實驗總結
  • 六、參考資料

一、SPI協議

1. SPI簡介

SPI 是英語Serial Peripheral interface的縮寫,顧名思義就是串行外圍設備接口。是Motorola首先在其MC68HCXX系列處理器上定義的。

SPI,是一種高速的,全雙工,同步的通信總線,并且在芯片的管腳上只占用四根線,節約了芯片的管腳,同時為PCB的布局上節省空間,提供方便,主要應用在 EEPROM,FLASH,實時時鐘,AD轉換器,還有數字信號處理器和數字信號解碼器之間。

SPI內部結構簡明圖

SPI接口一般使用4條線通信:

MISO 主設備數據輸入,從設備數據輸出。

MOSI 主設備數據輸出,從設備數據輸入。

SCLK時鐘信號,由主設備產生。

CS從設備片選信號,由主設備控制。

在stm32f103系列芯片中,引腳對應關系如下

STM32F10x的SPI引腳

這些引腳信息也可以在數據手冊查詢到,這里是一個整理

在STM32中文參考手冊中給出了SPI的框圖

SPI框圖

通常SPI通過4個引腳與外部器件相連:

①硬件上為4根線。
②主機和從機都有一個串行移位寄存器,主機通過向它的SPI串行寄存器寫入一個字節來發起一次傳輸。
③串行移位寄存器通過MOSI信號線將字節傳送給從機,從機也將自己的串行移位寄存器中的內容通過MISO信號線返回給主機。這樣,兩個移位寄存器中的內容就被交換。
④外設的寫操作和讀操作是同步完成的。如果只進行寫操作,主機只需忽略接收到的字節;反之,若主機要讀取從機的一個字節,就必須發送一個空字節來引發從機的傳輸。

GPIO口的配置如下圖

表22 SPI

在STM32中文參考手冊及其他廠商的參考資料、開發手冊介紹的已經非常詳細,介于篇幅限制,本文不在詳細敘述。

二、OLED屏的簡單應用

1. OLED原理

OLED(Organic Light-Emitting Diode),又稱為有機電激光顯示、有機發光半導體(Organic Electroluminescence Display,OLED)。OLED屬于一種電流型的有機發光器件,是通過載流子的注入和復合而致發光的現象,發光強度與注入的電流成正比。OLED在電場的作用下,陽極產生的空穴和陰極產生的電子就會發生移動,分別向空穴傳輸層和電子傳輸層注入,遷移到發光層。當二者在發光層相遇時,產生能量激子,從而激發發光分子最終產生可見光

本次實驗采用7針0.96英寸SPI OLED屏,屏幕如下圖

0.96英寸SPI OLED屏

其中七個引腳的配置如下:

引腳說明

所以根據上述引腳說明,OLED的引腳連接如下表

OLED模塊STM32單片機
VCC5V/3.3V
GNDGND
D0PB13
D1PB15
RESPB12
DCPB10
CSPB11

由于本次實驗采用軟件模擬SPI通信,所以引腳的選擇相對比較自由。

2. OLED顯示文字

2.1 部分代碼實現思想

首先是對引腳的GPIO配置

void OLED_Init_GPIO(void) {GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能B端口時鐘GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_15; //GPIOB10,11,12,13,15 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHzGPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOB10、11、12、13、15GPIO_SetBits(GPIOB,GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_15); }

然后是對OLED屏的初始化

void OLED_Init(void) {OLED_Init_GPIO(); //初始化GPIOdelay_ms(200);OLED_Reset(); //復位OLED/**************初始化SSD1306*****************/ OLED_WR_Byte(0xAE,OLED_CMD); /*display off*/OLED_WR_Byte(0x00,OLED_CMD); /*set lower column address*/OLED_WR_Byte(0x10,OLED_CMD); /*set higher column address*/OLED_WR_Byte(0x40,OLED_CMD); /*set display start line*/ OLED_WR_Byte(0xB0,OLED_CMD); /*set page address*/OLED_WR_Byte(0x81,OLED_CMD); /*contract control*/ OLED_WR_Byte(0xFF,OLED_CMD); /*128*/OLED_WR_Byte(0xA1,OLED_CMD); /*set segment remap*/ OLED_WR_Byte(0xA6,OLED_CMD); /*normal / reverse*/OLED_WR_Byte(0xA8,OLED_CMD); /*multiplex ratio*/ OLED_WR_Byte(0x3F,OLED_CMD); /*duty = 1/64*/OLED_WR_Byte(0xC8,OLED_CMD); /*Com scan direction*/OLED_WR_Byte(0xD3,OLED_CMD); /*set display offset*/ OLED_WR_Byte(0x00,OLED_CMD);OLED_WR_Byte(0xD5,OLED_CMD); /*set osc division*/ OLED_WR_Byte(0x80,OLED_CMD);OLED_WR_Byte(0xD9,OLED_CMD); /*set pre-charge period*/ OLED_WR_Byte(0XF1,OLED_CMD);OLED_WR_Byte(0xDA,OLED_CMD); /*set COM pins*/ OLED_WR_Byte(0x12,OLED_CMD);OLED_WR_Byte(0xDB,OLED_CMD); /*set vcomh*/ OLED_WR_Byte(0x30,OLED_CMD);OLED_WR_Byte(0x8D,OLED_CMD); /*set charge pump disable*/ OLED_WR_Byte(0x14,OLED_CMD);OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/ }

一般廠家會給出相應的代碼,我們只需要使用就可以了,具體代碼如何實現請自行查看

本次實驗需要顯示漢字和數字,其中數字已經包含在const unsigned char F6x8[][8]數組中,無需設置。顯示的文字需要通過PCtoLCD2002這款軟件實現,比如愛我中華

在文本框中輸入文字后,在選項中設置格式為C51格式,輸出數制為十六進制數

PCtoLCD2002選項

點擊生成字模按鈕

然后將下面生成的字模復制粘貼到代碼中

注意:不同代碼字模的格式不一定相同,請根據代碼自行更改相應的格式

2.2 完整代碼

其中delay.c和delay.h可以參考筆者之前的博客,由于篇幅限制,參考代碼中刪除了部分注釋代碼

oled.h

#ifndef __OLED_H #define __OLED_H //--------------OLED參數定義--------------------- #define PAGE_SIZE 8 #define XLevelL 0x00 #define XLevelH 0x10 #define YLevel 0xB0 #define Brightness 0xFF #define WIDTH 128 #define HEIGHT 64 //-------------寫命令和數據定義------------------- #define OLED_CMD 0 //寫命令 #define OLED_DATA 1 //寫數據 //-----------------OLED端口定義---------------- #define OLED_CS GPIO_Pin_11 //片選信號 PB11 #define OLED_DC GPIO_Pin_10 //數據/命令控制信號 PB10 #define OLED_RST GPIO_Pin_12 //復位信號 PB12//-----------------OLED端口操作定義---------------- #define OLED_CS_Clr() GPIO_ResetBits(GPIOB,OLED_CS) #define OLED_CS_Set() GPIO_SetBits(GPIOB,OLED_CS)#define OLED_DC_Clr() GPIO_ResetBits(GPIOB,OLED_DC) #define OLED_DC_Set() GPIO_SetBits(GPIOB,OLED_DC)#define OLED_RST_Clr() GPIO_ResetBits(GPIOB,OLED_RST) #define OLED_RST_Set() GPIO_SetBits(GPIOB,OLED_RST)//OLED控制用函數 void OLED_WR_Byte(unsigned dat,unsigned cmd); void OLED_Display_On(void); void OLED_Display_Off(void); void OLED_Set_Pos(unsigned char x, unsigned char y); void OLED_Reset(void); void OLED_Init_GPIO(void); void OLED_Init(void); void OLED_Set_Pixel(unsigned char x, unsigned char y,unsigned char color); void OLED_Display(void); void OLED_Clear(unsigned dat); #endif

oled.c

#include "oled.h" #include "stdlib.h" #include "string.h" #include "delay.h" #include "spi.h" //OLED顯存總共分為8頁 //每頁8行,一行128個像素點 //OLED的顯存 //存放格式如下. //[0]0 1 2 3 ... 127 (0~7)行 //[1]0 1 2 3 ... 127 (8~15)行 //[2]0 1 2 3 ... 127 (16~23)行 //[3]0 1 2 3 ... 127 (24~31)行 //[4]0 1 2 3 ... 127 (32~39)行 //[5]0 1 2 3 ... 127 (40~47)行 //[6]0 1 2 3 ... 127 (48~55)行 //[7]0 1 2 3 ... 127 (56~63)行 //數組每個bit存儲OLED每個像素點的顏色值(1-亮(白色),0-滅(黑色)) //每個數組元素表示1列8個像素點,一共128列 static unsigned char OLED_buffer[1024] = {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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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, };/******************************************************************** @name :void OLED_WR_Byte(unsigned dat,unsigned cmd)* @date :2018-08-27* @function :Write a byte of content to the OLED screen* @parameters :dat:Content to be writtencmd:0-write command1-write data* @retvalue :None ********************************************************************/ void OLED_WR_Byte(unsigned dat,unsigned cmd) {if(cmd){OLED_DC_Set();}else{OLED_DC_Clr();}OLED_CS_Clr();SPI_WriteByte(dat);OLED_CS_Set(); }/******************************************************************** @name :void OLED_Set_Pos(unsigned char x, unsigned char y) * @date :2018-08-27* @function :Set coordinates in the OLED screen* @parameters :x:x coordinatesy:y coordinates* @retvalue :None ********************************************************************/ void OLED_Set_Pos(unsigned char x, unsigned char y) {OLED_WR_Byte(YLevel+y/PAGE_SIZE,OLED_CMD);OLED_WR_Byte((((x+2)&0xf0)>>4)|0x10,OLED_CMD);OLED_WR_Byte(((x+2)&0x0f),OLED_CMD); } /******************************************************************** @name :void OLED_Display_On(void) * @date :2018-08-27* @function :Turn on OLED display* @parameters :None* @retvalue :None ********************************************************************/ void OLED_Display_On(void) {OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令OLED_WR_Byte(0X14,OLED_CMD); //DCDC ONOLED_WR_Byte(0XAF,OLED_CMD); //DISPLAY ON }/******************************************************************** @name :void OLED_Display_Off(void)* @date :2018-08-27* @function :Turn off OLED display* @parameters :None* @retvalue :None ********************************************************************/ void OLED_Display_Off(void) {OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFFOLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF }/******************************************************************** @name :void OLED_Set_Pixel(unsigned char x, unsigned char y,unsigned char color)* @date :2018-08-27* @function :set the value of pixel to RAM* @parameters :x:the x coordinates of pixely:the y coordinates of pixelcolor:the color value of the point1-white0-black* @retvalue :None ********************************************************************/ void OLED_Set_Pixel(unsigned char x, unsigned char y,unsigned char color) {if(color){OLED_buffer[(y/PAGE_SIZE)*WIDTH+x]|= (1<<(y%PAGE_SIZE))&0xff;}else{OLED_buffer[(y/PAGE_SIZE)*WIDTH+x]&= ~((1<<(y%PAGE_SIZE))&0xff);} } /******************************************************************** @name :void OLED_Display(void)* @date :2018-08-27* @function :Display in OLED screen* @parameters :None* @retvalue :None ********************************************************************/ void OLED_Display(void) {u8 i,n; for(i=0;i<PAGE_SIZE;i++) { OLED_WR_Byte (YLevel+i,OLED_CMD); //設置頁地址(0~7)OLED_WR_Byte (XLevelL,OLED_CMD); //設置顯示位置—列低地址OLED_WR_Byte (XLevelH,OLED_CMD); //設置顯示位置—列高地址 for(n=0;n<WIDTH;n++){OLED_WR_Byte(OLED_buffer[i*WIDTH+n],OLED_DATA); }} //更新顯示 }/******************************************************************** @name :void OLED_Clear(unsigned dat) * @date :2018-08-27* @function :clear OLED screen* @parameters :dat:0-Display full black1-Display full white* @retvalue :None ********************************************************************/ void OLED_Clear(unsigned dat) { if(dat){memset(OLED_buffer,0xff,sizeof(OLED_buffer));}else{memset(OLED_buffer,0,sizeof(OLED_buffer));}OLED_Display(); }/******************************************************************** @name :void OLED_Reset(void) * @date :2018-08-27* @function :Reset OLED screen* @parameters :dat:0-Display full black1-Display full white* @retvalue :None ********************************************************************/ void OLED_Reset(void) {OLED_RST_Set();delay_ms(100);OLED_RST_Clr();delay_ms(100);OLED_RST_Set(); } /******************************************************************** @name :void OLED_Init_GPIO(void)* @date :2018-08-27* @function :Reset OLED screen* @parameters :None* @retvalue :None ********************************************************************/ void OLED_Init_GPIO(void) {GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能B端口時鐘GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_15; //GPIOB10,11,12,13,15 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHzGPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOB10、11、12、13、15GPIO_SetBits(GPIOB,GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_15); }/******************************************************************** @name :void OLED_Init(void)* @date :2018-08-27* @function :initialise OLED SH1106 control IC* @parameters :None* @retvalue :None ********************************************************************/ void OLED_Init(void) {OLED_Init_GPIO(); //初始化GPIOdelay_ms(200);OLED_Reset(); //復位OLED/**************初始化SSD1306*****************/ OLED_WR_Byte(0xAE,OLED_CMD); /*display off*/OLED_WR_Byte(0x00,OLED_CMD); /*set lower column address*/OLED_WR_Byte(0x10,OLED_CMD); /*set higher column address*/OLED_WR_Byte(0x40,OLED_CMD); /*set display start line*/ OLED_WR_Byte(0xB0,OLED_CMD); /*set page address*/OLED_WR_Byte(0x81,OLED_CMD); /*contract control*/ OLED_WR_Byte(0xFF,OLED_CMD); /*128*/OLED_WR_Byte(0xA1,OLED_CMD); /*set segment remap*/ OLED_WR_Byte(0xA6,OLED_CMD); /*normal / reverse*/OLED_WR_Byte(0xA8,OLED_CMD); /*multiplex ratio*/ OLED_WR_Byte(0x3F,OLED_CMD); /*duty = 1/64*/OLED_WR_Byte(0xC8,OLED_CMD); /*Com scan direction*/OLED_WR_Byte(0xD3,OLED_CMD); /*set display offset*/ OLED_WR_Byte(0x00,OLED_CMD);OLED_WR_Byte(0xD5,OLED_CMD); /*set osc division*/ OLED_WR_Byte(0x80,OLED_CMD);OLED_WR_Byte(0xD9,OLED_CMD); /*set pre-charge period*/ OLED_WR_Byte(0XF1,OLED_CMD);OLED_WR_Byte(0xDA,OLED_CMD); /*set COM pins*/ OLED_WR_Byte(0x12,OLED_CMD);OLED_WR_Byte(0xDB,OLED_CMD); /*set vcomh*/ OLED_WR_Byte(0x30,OLED_CMD);OLED_WR_Byte(0x8D,OLED_CMD); /*set charge pump disable*/ OLED_WR_Byte(0x14,OLED_CMD);OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/ }

gui.h

#ifndef __GUI_H__ #define __GUI_H__void GUI_DrawPoint(u8 x, u8 y, u8 color); void GUI_Fill(u8 sx,u8 sy,u8 ex,u8 ey,u8 color); void GUI_DrawLine(u8 x1, u8 y1, u8 x2, u8 y2,u8 color); void GUI_DrawRectangle(u8 x1, u8 y1, u8 x2, u8 y2,u8 color); void GUI_FillRectangle(u8 x1, u8 y1, u8 x2, u8 y2,u8 color); void GUI_DrawCircle(u8 xc, u8 yc, u8 color, u8 r); void GUI_FillCircle(u8 xc, u8 yc, u8 color, u8 r); void GUI_DrawTriangel(u8 x0,u8 y0,u8 x1,u8 y1,u8 x2,u8 y2,u8 color); void GUI_FillTriangel(u8 x0,u8 y0,u8 x1,u8 y1,u8 x2,u8 y2,u8 color); void GUI_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size,u8 mode); void GUI_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 Size,u8 mode); void GUI_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size,u8 mode); void GUI_ShowFont16(u8 x,u8 y,u8 *s,u8 mode); void GUI_ShowFont24(u8 x,u8 y,u8 *s,u8 mode); void GUI_ShowFont32(u8 x,u8 y,u8 *s,u8 mode); void GUI_ShowChinese(u8 x,u8 y,u8 hsize,u8 *str,u8 mode); void GUI_DrawBMP(u8 x,u8 y,u8 width, u8 height, u8 BMP[], u8 mode); #endif

gui.c

#include "oled.h" #include "string.h" #include "oledfont.h" #include "delay.h" #include "gui.h"/******************************************************************** @name :void GUI_DrawPoint(u8 x,u8 y,u8 color)* @date :2018-08-27* @function :draw a point in LCD screen* @parameters :x:the x coordinate of the pointy:the y coordinate of the pointcolor:the color value of the point1-white0-black* @retvalue :None ********************************************************************/ void GUI_DrawPoint(u8 x,u8 y,u8 color) {OLED_Set_Pixel(x,y,color);OLED_Display(); }/******************************************************************** @name :void GUI_Fill(u8 sx,u8 sy,u8 ex,u8 ey,u8 color)* @date :2018-08-27 * @function :fill the specified area* @parameters :sx:the bebinning x coordinate of the specified areasy:the bebinning y coordinate of the specified areaex:the ending x coordinate of the specified areaey:the ending y coordinate of the specified areacolor:the color value of the the specified area1-white0-black* @retvalue :None ********************************************************************/ void GUI_Fill(u8 sx,u8 sy,u8 ex,u8 ey,u8 color) { u8 i,j; u8 width=ex-sx+1; //得到填充的寬度u8 height=ey-sy+1; //高度for(i=0;i<height;i++){for(j=0;j<width;j++){OLED_Set_Pixel(sx+j, sy+i,color);} }OLED_Display(); }/******************************************************************** @name :void GUI_DrawLine(u8 x1, u8 y1, u8 x2, u8 y2,u8 color)* @date :2018-08-27 * @function :Draw a line between two points* @parameters :x1:the bebinning x coordinate of the liney1:the bebinning y coordinate of the linex2:the ending x coordinate of the liney2:the ending y coordinate of the linecolor:the color value of the line1-white0-black* @retvalue :None ********************************************************************/ void GUI_DrawLine(u8 x1, u8 y1, u8 x2, u8 y2,u8 color) {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_y;} if( delta_x>delta_y)distance=delta_x; //選取基本增量坐標軸 else distance=delta_y; for(t=0;t<=distance+1;t++ )//畫線輸出 { OLED_Set_Pixel(uRow,uCol,color);xerr+=delta_x ; yerr+=delta_y ; if(xerr>distance) { xerr-=distance; uRow+=incx; } if(yerr>distance) { yerr-=distance; uCol+=incy; } } OLED_Display(); } /****************************************************************************** @name :void GUI_DrawRectangle(u8 x1, u8 y1, u8 x2, u8 y2,u8 color)* @date :2018-08-27 * @function :Draw a rectangle* @parameters :x1:the bebinning x coordinate of the rectangley1:the bebinning y coordinate of the rectanglex2:the ending x coordinate of the rectangley2:the ending y coordinate of the rectanglecolor:the color value of the rectangle1-white0-black * @retvalue :None ******************************************************************************/ void GUI_DrawRectangle(u8 x1, u8 y1, u8 x2, u8 y2,u8 color) {GUI_DrawLine(x1,y1,x2,y1,color);GUI_DrawLine(x1,y1,x1,y2,color);GUI_DrawLine(x1,y2,x2,y2,color);GUI_DrawLine(x2,y1,x2,y2,color); } /****************************************************************************** @name :void GUI_FillRectangle(u8 x1, u8 y1, u8 x2, u8 y2,u8 color)* @date :2018-08-27* @function :Filled a rectangle* @parameters :x1:the bebinning x coordinate of the filled rectangley1:the bebinning y coordinate of the filled rectanglex2:the ending x coordinate of the filled rectangley2:the ending y coordinate of the filled rectanglecolor:the color value of the rectangle1-white0-black * @retvalue :None ******************************************************************************/ void GUI_FillRectangle(u8 x1, u8 y1, u8 x2, u8 y2,u8 color) {GUI_Fill(x1,y1,x2,y2,color); }/****************************************************************************** @name :static void _draw_circle_8(u8 xc, u8 yc, u8 x, u8 y, u8 color)* @date :2018-08-27 * @function :8 symmetry circle drawing algorithm (internal call)* @parameters :xc:the x coordinate of the Circular center yc:the y coordinate of the Circular center x:the x coordinate relative to the Circular center y:the y coordinate relative to the Circular center color:the color value of the rectangle1-white0-black * @retvalue :None ******************************************************************************/ static void _draw_circle_8(u8 xc, u8 yc, u8 x, u8 y, u8 color) {OLED_Set_Pixel(xc + x, yc + y, color);OLED_Set_Pixel(xc - x, yc + y, color);OLED_Set_Pixel(xc + x, yc - y, color);OLED_Set_Pixel(xc - x, yc - y, color);OLED_Set_Pixel(xc + y, yc + x, color);OLED_Set_Pixel(xc - y, yc + x, color);OLED_Set_Pixel(xc + y, yc - x, color);OLED_Set_Pixel(xc - y, yc - x, color); }/****************************************************************************** @name :void GUI_DrawCircle(u8 xc, u8 yc, u8 color, u8 r)* @date :2018-08-27* @function :Draw a circle of specified size at a specified location* @parameters :xc:the x coordinate of the Circular center yc:the y coordinate of the Circular center r:Circular radiuscolor:the color value of the rectangle1-white0-black * @retvalue :None ******************************************************************************/ void GUI_DrawCircle(u8 xc, u8 yc, u8 color, u8 r) {int x = 0, y = r,d;d = 3 - 2 * r;while (x <= y) {_draw_circle_8(xc, yc, x, y, color);if (d < 0) {d = d + 4 * x + 6;}else {d = d + 4 * (x - y) + 10;y--;}x++;}OLED_Display(); }/****************************************************************************** @name :void GUI_FillCircle(u8 xc, u8 yc, u8 color, u8 r)* @date :2018-08-27* @function :Fill a circle of specified size at a specified location* @parameters :xc:the x coordinate of the Circular center yc:the y coordinate of the Circular center r:Circular radiuscolor:the color value of the rectangle1-white0-black * @retvalue :None ******************************************************************************/ void GUI_FillCircle(u8 xc, u8 yc, u8 color, u8 r) {int x = 0, y = r, yi, d;d = 3 - 2 * r;while (x <= y) {for (yi = x; yi <= y; yi++){_draw_circle_8(xc, yc, x, yi, color);}if (d < 0) {d = d + 4 * x + 6;} else {d = d + 4 * (x - y) + 10;y--;}x++;}OLED_Display(); }/*********************************************************************************** @name :void GUI_DrawTriangel(u8 x0,u8 y0,u8 x1,u8 y1,u8 x2,u8 y2,u8 color)* @date :2018-08-27 * @function :Draw a triangle at a specified position* @parameters :x0:the bebinning x coordinate of the triangular edge y0:the bebinning y coordinate of the triangular edge x1:the vertex x coordinate of the triangulary1:the vertex y coordinate of the triangularx2:the ending x coordinate of the triangular edge y2:the ending y coordinate of the triangular edge color:the color value of the rectangle1-white0-black * @retvalue :None ***********************************************************************************/ void GUI_DrawTriangel(u8 x0,u8 y0,u8 x1,u8 y1,u8 x2,u8 y2,u8 color) {GUI_DrawLine(x0,y0,x1,y1,color);GUI_DrawLine(x1,y1,x2,y2,color);GUI_DrawLine(x2,y2,x0,y0,color); }/****************************************************************************** @name :static void _swap(u8 *a, u8 *b)* @date :2018-08-27* @function :Exchange two numbers(internal call)* @parameters :a:the address of the first number b:the address of the second number* @retvalue :None ******************************************************************************/ static void _swap(u8 *a, u8 *b) {u16 tmp;tmp = *a;*a = *b;*b = tmp; }/****************************************************************************** @name :static void _draw_h_line(u8 x0,u8 x1,u8 y,u8 color)* @date :2018-08-27* @function :draw a horizontal line in RAM(internal call)* @parameters :x0:the bebinning x coordinate of the horizontal linex1:the ending x coordinate of the horizontal liney:the y coordinate of the horizontal linecolor:the color value of the rectangle1-white0-black * @retvalue :None ******************************************************************************/ static void _draw_h_line(u8 x0,u8 x1,u8 y,u8 color) {u8 i=0;for(i=x0;i<=x1;i++){OLED_Set_Pixel(i, y, color);} }/****************************************************************************** @name :void GUI_FillTriangel(u8 x0,u8 y0,u8 x1,u8 y1,u8 x2,u8 y2,u8 color)* @date :2018-08-27 * @function :filling a triangle at a specified position* @parameters :x0:the bebinning x coordinate of the triangular edge y0:the bebinning y coordinate of the triangular edge x1:the vertex x coordinate of the triangulary1:the vertex y coordinate of the triangularx2:the ending x coordinate of the triangular edge y2:the ending y coordinate of the triangular edge color:the color value of the rectangle1-white0-black * @retvalue :None ******************************************************************************/ void GUI_FillTriangel(u8 x0,u8 y0,u8 x1,u8 y1,u8 x2,u8 y2,u8 color) {u8 a, b, y, last;int dx01, dy01, dx02, dy02, dx12, dy12;long sa = 0;long sb = 0;if (y0 > y1) {_swap(&y0,&y1); _swap(&x0,&x1);}if (y1 > y2) {_swap(&y2,&y1); _swap(&x2,&x1);}if (y0 > y1) {_swap(&y0,&y1); _swap(&x0,&x1);}if(y0 == y2) { a = b = x0;if(x1 < a){a = x1;}else if(x1 > b){b = x1;}if(x2 < a){a = x2;}else if(x2 > b){b = x2;}_draw_h_line(a,b,y0,color);return;}dx01 = x1 - x0;dy01 = y1 - y0;dx02 = x2 - x0;dy02 = y2 - y0;dx12 = x2 - x1;dy12 = y2 - y1;if(y1 == y2){last = y1; }else{last = y1-1; }for(y=y0; y<=last; y++) {a = x0 + sa / dy01;b = x0 + sb / dy02;sa += dx01;sb += dx02;if(a > b){_swap(&a,&b);}_draw_h_line(a,b,y,color);}sa = dx12 * (y - y1);sb = dx02 * (y - y0);for(; y<=y2; y++) {a = x1 + sa / dy12;b = x0 + sb / dy02;sa += dx12;sb += dx02;if(a > b){_swap(&a,&b);}_draw_h_line(a,b,y,color);}OLED_Display(); }/****************************************************************************** @name :void GUI_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size,u8 mode)* @date :2018-08-27 * @function :Display a single English character* @parameters :x:the bebinning x coordinate of the Character display positiony:the bebinning y coordinate of the Character display positionchr:the ascii code of display character(0~94)Char_Size:the size of display character(8,16)mode:0-white background and black character1-black background and white character* @retvalue :None ******************************************************************************/ void GUI_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size,u8 mode) { unsigned char c=0,i=0,tmp,j=0; c=chr-' ';//得到偏移后的值 if(x>WIDTH-1){x=0;y=y+2;}if(Char_Size ==16){for(i=0;i<16;i++){if(mode){tmp = F8X16[c*16+i];}else{tmp = ~(F8X16[c*16+i]);}for(j=0;j<8;j++){if(tmp&(0x80>>j)){OLED_Set_Pixel(x+j, y+i,1);}else{OLED_Set_Pixel(x+j, y+i,0);}}}}else if(Char_Size==8){ for(i=0;i<8;i++){if(mode){tmp = F6x8[c][i];}else{tmp = ~(F6x8[c][i]);}for(j=0;j<8;j++){if(tmp&(0x80>>j)){OLED_Set_Pixel(x+j, y+i,1);}else{OLED_Set_Pixel(x+j, y+i,0);}}}}else{return;}OLED_Display(); }/****************************************************************************** @name :void GUI_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size,u8 mode)* @date :2018-08-27 * @function :Display English string* @parameters :x:the bebinning x coordinate of the English stringy:the bebinning y coordinate of the English stringchr:the start address of the English stringChar_Size:the size of display charactermode:0-white background and black character1-black background and white character* @retvalue :None ******************************************************************************/ void GUI_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size,u8 mode) {unsigned char j=0,csize;if(Char_Size == 16){csize = Char_Size/2;}else if(Char_Size == 8){csize = Char_Size/2+2;}else{return;}while (chr[j]!='\0'){ GUI_ShowChar(x,y,chr[j],Char_Size,mode);x+=csize;if(x>120){x=0;y+=Char_Size;}j++;} }/****************************************************************************** @name :u32 mypow(u8 m,u8 n)* @date :2018-08-27 * @function :get the nth power of m (internal call)* @parameters :m:the multipliern:the power* @retvalue :the nth power of m ******************************************************************************/ static u32 mypow(u8 m,u8 n) {u32 result=1; while(n--)result*=m; return result; }/****************************************************************************** @name :void GUI_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 Size,u8 mode)* @date :2018-08-27 * @function :Display number* @parameters :x:the bebinning x coordinate of the numbery:the bebinning y coordinate of the numbernum:the number(0~4294967295)len:the length of the display numberSize:the size of display numbermode:0-white background and black character1-black background and white character* @retvalue :None ******************************************************************************/ void GUI_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 Size,u8 mode) { u8 t,temp;u8 enshow=0,csize;if(Size == 16){csize = Size/2;}else if(Size == 8){csize = Size/2+2;} else{return;}for(t=0;t<len;t++){temp=(num/mypow(10,len-t-1))%10;if(enshow==0&&t<(len-1)){if(temp==0){GUI_ShowChar(x+csize*t,y,' ',Size,mode);continue;}else enshow=1; }GUI_ShowChar(x+csize*t,y,temp+'0',Size,mode); } } /****************************************************************************** @name :void GUI_ShowFont16(u8 x,u8 y,u8 *s,u8 mode)* @date :2018-08-27 * @function :Display a single 16x16 Chinese character* @parameters :x:the bebinning x coordinate of the Chinese charactery:the bebinning y coordinate of the Chinese characters:the start address of the Chinese charactermode:0-white background and black character1-black background and white character* @retvalue :None ******************************************************************************/ void GUI_ShowFont16(u8 x,u8 y,u8 *s,u8 mode) {u8 i,j,k,tmp;u16 num;num = sizeof(cfont16)/sizeof(typFNT_GB16);for(i=0;i<num;i++){if((cfont16[i].Index[0]==*s)&&(cfont16[i].Index[1]==*(s+1))){for(j=0;j<32;j++){if(mode){tmp = cfont16[i].Msk[j];}else{tmp = ~(cfont16[i].Msk[j]);}for(k=0;k<8;k++){if(tmp&(0x80>>k)){OLED_Set_Pixel(x+(j%2)*8+k, y+j/2,1);}else{OLED_Set_Pixel(x+(j%2)*8+k, y+j/2,0);}}} break;} }OLED_Display(); }/****************************************************************************** @name :void GUI_ShowFont24(u8 x,u8 y,u8 *s,u8 mode)* @date :2018-08-27 * @function :Display a single 24x24 Chinese character* @parameters :x:the bebinning x coordinate of the Chinese charactery:the bebinning y coordinate of the Chinese characters:the start address of the Chinese charactermode:0-white background and black character1-black background and white character* @retvalue :None ******************************************************************************/ void GUI_ShowFont24(u8 x,u8 y,u8 *s,u8 mode) {u8 i,j,k,tmp;u16 num;num = sizeof(cfont24)/sizeof(typFNT_GB24);for(i=0;i<num;i++){if((cfont24[i].Index[0]==*s)&&(cfont24[i].Index[1]==*(s+1))){for(j=0;j<72;j++){if(mode){tmp = cfont24[i].Msk[j];}else{tmp = ~(cfont24[i].Msk[j]);}for(k=0;k<8;k++){if(tmp&(0x80>>k)){OLED_Set_Pixel(x+(j%3)*8+k, y+j/3,1);}else{OLED_Set_Pixel(x+(j%3)*8+k, y+j/3,0);}}} break;} }OLED_Display(); }/****************************************************************************** @name :void GUI_ShowFont32(u8 x,u8 y,u8 *s,u8 mode)* @date :2018-08-27 * @function :Display a single 32x32 Chinese character* @parameters :x:the bebinning x coordinate of the Chinese charactery:the bebinning y coordinate of the Chinese characters:the start address of the Chinese charactermode:0-white background and black character1-black background and white character* @retvalue :None ******************************************************************************/ void GUI_ShowFont32(u8 x,u8 y,u8 *s,u8 mode) {u8 i,j,k,tmp;u16 num;num = sizeof(cfont32)/sizeof(typFNT_GB32);for(i=0;i<num;i++){if((cfont32[i].Index[0]==*s)&&(cfont32[i].Index[1]==*(s+1))){for(j=0;j<128;j++){if(mode){tmp = cfont32[i].Msk[j];}else{tmp = ~(cfont32[i].Msk[j]);}for(k=0;k<8;k++){if(tmp&(0x80>>k)){OLED_Set_Pixel(x+(j%4)*8+k, y+j/4,1);}else{OLED_Set_Pixel(x+(j%4)*8+k, y+j/4,0);}}} break;} }OLED_Display(); }/****************************************************************************** @name :void GUI_ShowCHinese(u8 x,u8 y,u8 hsize,u8 *str,u8 mode)* @date :2018-08-27 * @function :Display Chinese strings* @parameters :x:the bebinning x coordinate of the Chinese stringsy:the bebinning y coordinate of the Chinese stringssize:the size of Chinese stringsstr:the start address of the Chinese stringsmode:0-white background and black character1-black background and white character* @retvalue :None ******************************************************************************/ void GUI_ShowChinese(u8 x,u8 y,u8 hsize,u8 *str,u8 mode) { while(*str!='\0'){if(hsize == 16){GUI_ShowFont16(x,y,str,mode);}else if(hsize == 24){GUI_ShowFont24(x,y,str,mode);}else if(hsize == 32){GUI_ShowFont32(x,y,str,mode);}else{return;}x+=hsize;if(x>WIDTH-hsize){x=0;y+=hsize;}str+=2;} }/****************************************************************************** @name :void GUI_DrawBMP(u8 x,u8 y,u8 width, u8 height, u8 BMP[], u8 mode)* @date :2018-08-27 * @function :Display a BMP monochromatic picture* @parameters :x:the bebinning x coordinate of the BMP monochromatic picturey:the bebinning y coordinate of the BMP monochromatic picturewidth:the width of BMP monochromatic pictureheight:the height of BMP monochromatic pictureBMP:the start address of BMP monochromatic picture arraymode:0-white background and black character1-black background and white character * @retvalue :None ******************************************************************************/ void GUI_DrawBMP(u8 x,u8 y,u8 width, u8 height, u8 BMP[], u8 mode) { u8 i,j,k;u8 tmp;for(i=0;i<height;i++){for(j=0;j<(width+7)/8;j++){if(mode){tmp = BMP[i*((width+7)/8)+j];}else{tmp = ~BMP[i*((width+7)/8)+j];}for(k=0;k<8;k++){if(tmp&(0x80>>k)){OLED_Set_Pixel(x+j*8+k, y+i,1);}else{OLED_Set_Pixel(x+j*8+k, y+i,0);}}}} OLED_Display(); }

spi.h

#ifndef _SPI_H_ #define _SPI_H_ #include "stm32f10x.h"//本測試程序使用的是軟件模擬SPI接口驅動 //SPI的數據引腳定義和時鐘引腳定義都可以任意修改 //修改引腳定義后,需要對應修改oled.c中OLED_Init_GPIO函數里面引腳初始化//--------------SPI總線引腳定義----------------------- #define OLED_MOSI GPIO_Pin_15 //OLED屏SPI寫數據信號 #define OLED_CLK GPIO_Pin_13 //OLED屏SPI時鐘信號//--------------SPI端口操作定義--------------------- #define OLED_MOSI_SET() GPIO_SetBits(GPIOB,OLED_MOSI) #define OLED_MOSI_CLR() GPIO_ResetBits(GPIOB,OLED_MOSI) #define OLED_CLK_SET() GPIO_SetBits(GPIOB,OLED_CLK) #define OLED_CLK_CLR() GPIO_ResetBits(GPIOB,OLED_CLK) //SPI寫數據函數 void SPI_WriteByte(u8 Data); #endif

spi.c

#include "spi.h"/****************************************************************************** @name :void SPI_WriteByte(u8 Data)* @date :2018-08-27 * @function :Write a byte of data using STM32's Software SPI* @parameters :Data:Data to be written* @retvalue :None ******************************************************************************/ void SPI_WriteByte(u8 Data) {unsigned char i=0;for(i=8;i>0;i--){if(Data&0x80) {OLED_MOSI_SET(); //寫數據1}else{OLED_MOSI_CLR(); //寫數據0}OLED_CLK_CLR(); //將時鐘拉低拉高 OLED_CLK_SET(); //發送1bit數據Data<<=1; } }

main.c

#include "stm32f10x.h" #include "delay.h" #include "oled.h" #include "gui.h"int main(void) { DELAY_Init(); //延時函數初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);OLED_Init(); //初始化OLED OLED_Clear(0); while(1) { GUI_ShowCHinese(28,20,16,"***",1);GUI_ShowString(4,48,"******",16,1);delay_ms(1500); delay_ms(1500);} }

其中還需要oledfont.h、bmp.h,分別為存儲字體和圖像的文件

2.3 實驗效果

圖 2.3實驗效果

三、OLED屏的溫濕度顯示

有關OLED屏的資料很多,如果有需要可以在各大廠家或賣家等獲取相關資料,或者也可以在其官方網站下載資料。

1. 部分代碼實現思想

結合上次的實驗基于I2C的溫濕度采集_江南煙濃雨的博客-CSDN博客,通過IIC讀取溫濕度信息后再通過OLED顯示出來,主要功能在主程序中實現。將iic.h中H1和T1設置為全局變量,在調用讀取函數時,H1和T1的值便會保存在H1和T1中,再通過上面的GUI函數實現。

注意:需要將原來的H1和T1設置為全局變量,在頭文件中通過extern聲明為全局變量

實驗電路(引腳接口)請參考本次實驗OLED屏及上次實驗AHT20的引腳接法

2. 完整代碼

main.c

#include "stm32f10x.h" #include "stdio.h" #include "stdlib.h" #include "bmp.h" #include "delay.h" #include "iic.h" #include "oled.h" #include "gui.h"uint32_t H1; //Humility uint32_t T1; //Temperatureint main(void) { DELAY_Init(); //延時函數初始化MyUSART_Init();IIC_Init();NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);OLED_Init(); //初始化OLED OLED_Clear(0); while(1) {read_AHT20_once();GUI_DrawLine(0, 10, WIDTH-1, 10,1);GUI_DrawLine(WIDTH/2-1,11,WIDTH/2-1,HEIGHT-1,1);GUI_DrawLine(WIDTH/2-1,10+(HEIGHT-10)/2-1,WIDTH-1,10+(HEIGHT-10)/2-1,1);GUI_ShowString(0,1,"2021-11-24",8,1);GUI_ShowString(70,1,"Wednesday",8,1);GUI_ShowString(14,HEIGHT-1-10,"Cloudy",8,1);GUI_ShowString(WIDTH/2+1,13,"TEMP",8,1); //顯示溫度GUI_DrawCircle(WIDTH-20, 25, 1,2);GUI_ShowString(WIDTH-15,20,"C",16,1);GUI_ShowNum(WIDTH/2+8,20,T1/10,2,16,1);GUI_ShowString(WIDTH-41,26,".",8,1);GUI_ShowNum(WIDTH-35,20,T1%10,1,16,1);GUI_ShowString(WIDTH/2+1,39,"HUM",8,1); //顯示濕度GUI_ShowNum(WIDTH/2+8,46,H1/10,2,16,1);GUI_ShowString(WIDTH-41,52,".",8,1);GUI_ShowNum(WIDTH-35,46,H1%10,1,16,1);GUI_ShowString(WIDTH-21,46,"%",16,1);GUI_DrawBMP(6,16,51,32, BMP5, 1);delay_ms(2000);} }

3. 實驗效果

在實驗過程中,用手捂住AHT20溫濕度傳感器,使其溫度升高,OLED屏幕上也會隨之而變化

四、OLED屏的滾動顯示

1. 部分代碼實現思想

OLED支持水平滾動、垂直并水平滾動兩種效果。在0.96OLED數據手冊第九章中給出了功能定義

Scrolling Command Table

第一個字節是26h/27h,26h:向右進行水平滾動;27h:向左進行水平滾動
第二個字節是空字節,建議發送00即可
第三個字節設置水平滾動的起始頁地址,頁0 ~頁7。
第四個字節設置滾動步長時間間隔,幀為單位。
第五個字節設置水平滾動的終止頁地址,頁0 ~頁7(終止頁地址必須要比起始頁地址要大)
第六個字節是空字節,建議發送00即可
第七個字節是空字節,建議發送FF即可

注意:設置滾動前,必須先發送2Eh命令停止滾動。

以上內容參考自如何使用OLED實現滾動效果_正點原子的博客-CSDN博客

知道了這些連續字節的含義,接下來就是水平滾動代碼的編寫。(更多資料請參考相關博客或數據手冊)

2. 完整代碼

注意:需要修改或添加oledfont.h的文字內容

main.c

#include "stm32f10x.h" #include "delay.h" #include "oled.h" #include "gui.h"int main(void) { DELAY_Init(); //延時函數初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);OLED_Init(); //初始化OLED OLED_Clear(0); OLED_WR_Byte(0x2E,OLED_CMD); //關閉滾動OLED_WR_Byte(0x26,OLED_CMD); //水平向左或者右滾動 26/27OLED_WR_Byte(0x00,OLED_CMD); //虛擬字節OLED_WR_Byte(0x00,OLED_CMD); //起始頁 0OLED_WR_Byte(0x07,OLED_CMD); //滾動時間間隔OLED_WR_Byte(0x07,OLED_CMD); //終止頁 7OLED_WR_Byte(0x00,OLED_CMD); //虛擬字節OLED_WR_Byte(0xFF,OLED_CMD); GUI_ShowChinese(0,20,16,"你說江南煙濃雨",1);OLED_WR_Byte(0x2F,OLED_CMD);delay_ms(1500); }

3. 實驗效果

五、實驗總結

本次實驗完成了對于OLED屏的一些操作,但是美中不足的是沒有實現硬件IIC和SPI,而是軟件模擬的方式實現了IIC和SPI協議。文中所附代碼大部分可能并沒有用到,請讀者自行斟酌,可以參考相關廠商的代碼進行改進

六、參考資料

SPI(SPI協議)_百度百科 (baidu.com)

OLED_百度百科 (baidu.com)

基于SPI通信方式的OLED顯示_不#曾&輕聽的博客-CSDN博客

如何使用OLED實現滾動效果_正點原子的博客-CSDN博客

0.96inch SPI OLED Module - LCD wiki

基于I2C的溫濕度采集_江南煙濃雨的博客-CSDN博客

STM32中文參考手冊.pdf

STM32F103數據手冊.pdf

0.96OLED顯示屏_驅動芯片手冊.pdf

總結

以上是生活随笔為你收集整理的基于SPI的OLED温湿度显示的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。