Halo para pembaca yang budiman. Dalam perkembangan saya pada mikrokontroler STM32, untuk menampilkan informasi yang berarti, saya menggunakan layar OLED pada chip SSD1306. Terakhir kali layar 1,3 "datang kepada saya dengan harga yang demokratis - sekitar 200 rubel. Hal pertama yang menarik perhatian saya adalah tulisan SH1106, bukan SSD1306, pencarian di Internet memperjelas bahwa ini hampir sama, hanya satu-satunya mode pengalamatan halaman yang tersisa, dan ini terbatas pada satu baris. Saya akan mencoba menjelaskan cara mengatasinya dalam publikasi ini.
Sekitar setahun yang lalu, saya mulai merindukan kemampuan pil biru (STM32F103) dan papan pengembangan China STM32F407VE dipesan. Untuk debugging, seringkali, dua LED tidak cukup, jadi di setiap proyek saya menghubungkan OLED SSD1306 melalui bus I2C untuk menampilkan informasi, yang saya sukai sejak zaman Arduino. Karena saya tidak menampilkan grafik di atasnya, terutama angka dan teks, dan ukuran pustaka yang telah selesai serta isinya membuat takjub imajinasi saya, sebuah perpustakaan kecil telah ditulis, yang saya sesuaikan sedikit untuk SH1106 dan saya ingin berbagi dengan Anda proses penulisannya. Tampilan tiba 7pin SPI:

Saya memiliki papan pengembang seperti itu, tetapi tidak ada yang akan menghalangi Anda untuk terhubung ke yang lain, bahkan di STM32F103, di mana HAL diciptakan (bukan?):

CubeMX STM32F407VE , , UART1. Clock Configuration 8MHz 168MHz HSE. PA6 PA7, D2 D3 ( ยซ0ยป) :

SPI1 NRF24L01 ESP-PSRAM64H, SPI3. DMA , :

DC (/), RESET ( ) CS ( ) :

:
SH1106 โ STM32F407- GND โ GND
- VDD โ 3V3
- SCK โ PC10
- SDA โ PC12
- RES โ PD0
- DC โ PC11
- CS โ PA15
Heap Stack 2 Atollic, . , . Src File->Source File, spi1106.c File->Header File spi1106.h. Src Inc , #define ic1306_H_ #endif /* ic1306_H_ */ CD, RESET CS :
#define SPI1106_H_
#include "main.h"
void sh1106Init (uint8_t contrast, uint8_t bright, uint8_t mirror);
#define SH_Command HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_RESET)
#define SH_Data HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_SET)
#define SH_ResHi HAL_GPIO_WritePin(RES_GPIO_Port, RES_Pin, GPIO_PIN_SET)
#define SH_ResLo HAL_GPIO_WritePin(RES_GPIO_Port, RES_Pin, GPIO_PIN_RESET)
#define SH_CsHi HAL_GPIO_WritePin(GPIOA, CS_Pin, GPIO_PIN_SET)
#define SH_CsLo HAL_GPIO_WritePin(GPIOA, CS_Pin, GPIO_PIN_RESET)
#endif /* SPI1106_H_ */spi1106.c , main.h, SPI :
#include "main.h"
#include <spi1106.h>
extern SPI_HandleTypeDef hspi3;SPI HAL:
void SH1106_WC (uint8_t comm)
{
uint8_t temp[1];
SH_Command;
SH_CsLo;
temp[0]=comm;
HAL_SPI_Transmit(&hspi3,&temp,1,1);
SH_CsHi;
}:
void sh1106Init (uint8_t contrast, uint8_t bright,uint8_t mirror)
{
SH_ResLo;
HAL_Delay(1);
SH_ResHi;
HAL_Delay(1);
SH1106_WC(0xAE); //display off
SH1106_WC(0xA8); //--set multiplex ratio(1 to 64)
SH1106_WC(0x3F); //
SH1106_WC(0x81); //--set contrast control register
SH1106_WC(contrast);
if (mirror) {SH1106_WC(0xA0);
SH1106_WC(0xC0);}
else {SH1106_WC(0xA1);
SH1106_WC(0xC8); }
SH1106_WC(0xDA);
SH1106_WC(0x12);
SH1106_WC(0xD3);
SH1106_WC(0x00);
SH1106_WC(0x40);
SH1106_WC(0xD9); //--set pre-charge period
SH1106_WC(bright);
SH1106_WC(0xAF); //--turn on SSD1306 panel
}, , โ (0-255), โ ( , 0xX0 0x0X ), โ (0/1). ยซ . 1. OLED 0.96ยป (12864) SSD1306" SSD1306.
main.c :
/* USER CODE BEGIN 2 */
sh1106Init (40,0x22,0);
/* USER CODE END 2 */:

spi1106.h โ , :
void sh1106Clear(uint8_t start, uint8_t stop);
void sh1106SmallPrint(uint8_t posx, uint8_t posy, uint8_t *str);
void sh1106MediumPrint(uint8_t posx, uint8_t posy,uint8_t *str);spi1106.c 0- 7- 0xB0...0xB7 :
void sh1106Clear(uint8_t start, uint8_t stop)
{ uint32_t *adrclear;
uint32_t timep,timec;
uint8_t dt[128];
adrclear=(uint32_t *)dt;
for(uint8_t i=0;i<32;i++) {*adrclear++=0x00;}
for (uint8_t m = start; m <= stop; m++)
{
SH1106_WC(0xB0+m);
SH1106_WC(2);
SH1106_WC(0x10);
SH_Data;
SH_CsLo;
HAL_SPI_Transmit_DMA(&hspi3,dt,128);
timec=HAL_GetTick();
timep=timec+50;
while ((HAL_SPI_GetState(&hspi3) != HAL_SPI_STATE_READY)&&(timec<timep))
{timec=HAL_GetTick();}
SH_CsHi;
}
}main.c, , :
sh1106Clear(0,7);, , , spi1106.c DefaultFonts.c ( - ). , ( SSD1306/SH1106). 4- . , , :
const uint8_t SmallFont[] = // SmallFont
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 001) 0x20=032
0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, // 002) 0x21=033 !
0x00, 0x00, 0x07, 0x00, 0x07, 0x00, // 003) 0x22=034 "
0x00, 0x14, 0x7F, 0x14, 0x7F, 0x14, // 004) 0x23=035 #
0x00, 0x24, 0x2A, 0x7F, 0x2A, 0x12, // 005) 0x24=036 $
0x00, 0x23, 0x13, 0x08, 0x64, 0x62, // 006) 0x25=037 %
0x00, 0x36, 0x49, 0x55, 0x22, 0x50, // 007) 0x26=038 &
0x00, 0x00, 0x05, 0x03, 0x00, 0x00, // 008) 0x27=039 '
0x00, 0x00, 0x1C, 0x22, 0x41, 0x00, // 009) 0x28=040 (
0x00, 0x00, 0x41, 0x22, 0x1C, 0x00, // 010) 0x29=041 )
0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, // 011) 0x2A=042 *
0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, // 012) 0x2B=043 +
0x00, 0x00, 0x00, 0xA0, 0x60, 0x00, // 013) 0x2C=044 ,
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, // 014) 0x2D=045-
0x00, 0x00, 0x60, 0x60, 0x00, 0x00, // 015) 0x2E=046 .
0x00, 0x20, 0x10, 0x08, 0x04, 0x02, // 016) 0x2F=047 /
//
0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, // 017) 0x30=048 0
0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, // 018) 0x31=049 1
0x00, 0x42, 0x61, 0x51, 0x49, 0x46, // 019) 0x32=050 2
0x00, 0x21, 0x41, 0x45, 0x4B, 0x31, // 020) 0x33=051 3
0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, // 021) 0x34=052 4
0x00, 0x27, 0x45, 0x45, 0x45, 0x39, // 022) 0x35=053 5
0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, // 023) 0x36=054 6
0x00, 0x01, 0x71, 0x09, 0x05, 0x03, // 024) 0x37=055 7
0x00, 0x36, 0x49, 0x49, 0x49, 0x36, // 025) 0x38=056 8
0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, // 026) 0x39=057 9
0x00, 0x00, 0x36, 0x36, 0x00, 0x00, // 027) 0x3A=058 :
0x00, 0x00, 0x56, 0x36, 0x00, 0x00, // 028) 0x3B=059 ;
0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // 029) 0x3C=060 <
0x00, 0x14, 0x14, 0x14, 0x14, 0x14, // 030) 0x3D=061 =
0x00, 0x00, 0x41, 0x22, 0x14, 0x08, // 031) 0x3E=062 >
0x00, 0x02, 0x01, 0x51, 0x09, 0x06, // 032) 0x3F=063 ?
//
0x00, 0x32, 0x49, 0x59, 0x51, 0x3E, // 033) 0x40=064 @
0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, // 034) 0x41=065 A
0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, // 035) 0x42=066 B
// ...
}( 6, 8 ), posx , 6 , posy (0 โ , 7 โ ):
void sh1106SmallPrint(uint8_t posx, uint8_t posy, uint8_t *str)
{
uint8_t dt[128];
uint16_t posfont, posscr;
uint32_t *adrclr;
uint16_t *adrdst,*adrsrc;
uint32_t timer,timec;
adrclr=(uint32_t *)&dt;
uint8_t code;
code=*str++;
for(uint8_t i=0;i<32;i++) { *adrclr++=0; }
posscr=posx*6;
while (code>31)
{
if(code==32) {posscr+=2;}
else
{posfont=6*(code-32);
adrdst=(uint16_t *)&dt[posscr];
adrsrc=(uint16_t *)&SmallFont[posfont];
*(adrdst++)=*(adrsrc++);
*(adrdst++)=*(adrsrc++);
*(adrdst++)=*(adrsrc++);
posscr+=6;
}
code=*str++;
if (posscr>122) break;
}
SH1106_WC(0xB0+posy);
SH1106_WC(2);
SH1106_WC(0x10);
SH_Data;
SH_CsLo;
HAL_SPI_Transmit_DMA(&hspi3,dt,128);
timec=HAL_GetTick();
timer=timec+50;
while ((HAL_SPI_GetState(&hspi3) != HAL_SPI_STATE_READY)&&(timec<timer))
{timec=HAL_GetTick();}
SH_CsHi;
}, spi1106.c ( 16, 12 ) DefaultFonts.c ( 4 ) , posx , 12 , posy :
void sh1106MediumPrint(uint8_t posx, uint8_t posy, uint8_t *str)
{
uint8_t dt[256];
uint16_t posfont, posscr;
uint32_t *adrdst, *adrsrc;
uint32_t timer,timec;
adrdst=(uint32_t *)&dt;
uint8_t code;
code=*str++;
for(uint8_t i=0;i<64;i++) { *adrdst++=0; }
posscr=posx*12;
while (code>31)
{posfont=24*(code-32);
adrsrc=(uint32_t *)&MediumFont[posfont];
adrdst=(uint32_t *)&dt[posscr];
*(adrdst++)=*(adrsrc++);
*(adrdst++)=*(adrsrc++);
*(adrdst++)=*(adrsrc++);
adrsrc=(uint32_t *)&MediumFont[posfont+12];
adrdst=(uint32_t *)&dt[posscr+128];
*(adrdst++)=*(adrsrc++);
*(adrdst++)=*(adrsrc++);
*(adrdst++)=*(adrsrc++);
code=*str++;
posscr+=12;
if (posscr>116) break;
}
SH1106_WC(0xB0+posy);
SH1106_WC(2);
SH1106_WC(0x10);
SH_Data;
SH_CsLo;
HAL_SPI_Transmit_DMA(&hspi3,dt,128);
timec=HAL_GetTick();
timer=timec+50;
while ((HAL_SPI_GetState(&hspi3) != HAL_SPI_STATE_READY)&&(timec<timer))
{timec=HAL_GetTick();}
SH1106_WC(0xB0+posy+1);
SH1106_WC(2);
SH1106_WC(0x10);
SH_Data;
SH_CsLo;
HAL_SPI_Transmit_DMA(&hspi3,dt+128,128);
timec=HAL_GetTick();
timer=timec+50;
while ((HAL_SPI_GetState(&hspi3) != HAL_SPI_STATE_READY)&&(timec<timer))
{timec=HAL_GetTick();}
SH_CsHi;
}main.c :
sh1106SmallPrint(0,0,(uint8_t *) "Hello SH1106_1234567890");
sh1106MediumPrint(0,1,(uint8_t *) "Hi SH1106");
sh1106MediumPrint(0,3,(uint8_t *) "Hello SH1106");
, , HardFault . , , , .
, , 7 :
/* Infinite loop */
/* USER CODE BEGIN WHILE */
uint8_t buf[128*8];
char str[32];
uint16_t count;
uint8_t x,y,b;
uint32_t timep,timec;
while (1)
{
count++;
b=count&0x07;
x=(count>>3)&0x7f;
y=(count>>10)&0x07;
buf[y*128+x]=buf[y*128+x]|(1<<b);
timec=HAL_GetTick();
for (uint8_t m = 0; m < 7; m++)
{SH1106_WC(0xB0+m);
SH1106_WC(2);
SH1106_WC(0x10);
SH_Data;
SH_CsLo;
HAL_SPI_Transmit_DMA(&hspi3,buf+m*128,128);
while ((HAL_SPI_GetState(&hspi3) != HAL_SPI_STATE_READY))
{__NOP();}
SH_CsHi;
}
timep=HAL_GetTick();
sprintf(str, "%d", timep-timec);
sh1106SmallPrint(0,7,str);
/* USER CODE END WHILE */
โ "0" "1" , 1ms, .. 1000fps. , , . SPI SPI DMA.
.