Bonjour chers lecteurs. Dans mes développements sur les microcontrôleurs STM32, pour afficher des informations significatives, j'utilise des écrans OLED sur la puce SSD1306. La dernière fois qu'un écran de 1,3 "m'est venu à un prix démocratique - environ 200 roubles. La première chose qui a attiré mon attention a été l'inscription SH1106 au lieu de SSD1306, une recherche sur Internet a clairement montré que c'était presque le même, il ne restait que le seul mode d'adressage de page, et il est limité à une ligne et j'essaierai d'expliquer comment l'utiliser dans cette publication.
Il y a environ un an, j'ai commencé à manquer les capacités de la pilule bleue (STM32F103) et la carte de développement chinoise STM32F407VE a été commandée. Pour le débogage, souvent, deux LED ne suffisent pas, donc dans chaque projet je connecte le SSD OLED1306 via le bus I2C pour afficher des informations, dont je suis tombé amoureux depuis l'époque d'Arduino. Comme je n'y affiche pas de graphiques, principalement des chiffres et du texte, et que la taille des bibliothèques finies et leur contenu ont étonné mon imagination, une petite bibliothèque a été écrite, que j'ai légèrement adaptée pour SH1106 et je souhaite partager avec vous le processus de rédaction. L'affichage est arrivé SPI 7 broches:
J'ai une telle carte développeur, mais rien ne vous empêchera de vous connecter à une autre, même sur STM32F103, pour laquelle HAL a été inventé (n'est-ce pas?):
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.
.