記事ディレクトリ
1. 4 ラインの 0.96 インチ OLED は IIC によって駆動され、ディスプレイを実現します。
序文
最近は、ハードウェアとソフトウェアをオープンソース化し、CSDN でオープンソース化するオープンソース ソリューションである Balance Car に取り組んでいます。今日の記事は主に、アナログ IIC 駆動方式を使用するボード上の OLED モジュールについて説明します。このドライバー方法はシンプルかつ効果的で、U8g2 ライブラリに適しています。
OLEDは有機発光ダイオード(Organic Light-Emitting Diode)の略で、有機エレクトロルミネッセンスディスプレイ(OELD)としても知られています。OLEDは、自己発光型、バックライト不要、高コントラスト、薄型、広視野角、速い応答速度、フレキシブルパネル、広い動作温度範囲、シンプルな構造と製造プロセスにより、最も先進的な技術とみなされています。次世代フラットパネルディスプレイの新たな応用技術。
OLEDディスプレイ技術は、非常に薄い有機材料コーティングとガラス基板を使用し、電流が流れるとこれらの有機材料が発光し、OLEDディスプレイ画面が広い視野角を持ち、電力を節約できる自己発光の特性を持っています。
1. 4ラインOLEDとは何ですか?
ピンの説明:
GND 共通グランド ピン
VCC 電源ピン、通常は 3.3V DC 電源
iic バスの SCL クロック ライン
iic バスの SDA データ ライン
2. IICの原理
1. 4 ラインの 0.96 インチ OLED はIICによって駆動され、ディスプレイを実現します。
iicバスプロトコル:
IIC (Inter-Integrated Circuit) プロトコルは、I2C (Inter-IC) プロトコルとも呼ばれ、集積回路 (IC) 間の通信に使用されるシリアル通信プロトコルです。これは、複数のチップ間の通信を簡素化するために、Philips Semiconductors (現在の NXP Semiconductors) によって 1982 年に開発されました。
IIC プロトコルは、通信にクロック ライン (SCL) とデータ ライン (SDA) の 2 本のワイヤを使用します。この 2 線式通信方式により、各デバイスを同じ線でバスに接続できるため、IIC プロトコルは複数のデバイスの接続に非常に適しています。
IIC プロトコルでは、通信はマスター デバイス (通常はマイクロコントローラーまたはプロセッサ) とスレーブ デバイスの間で行われます。マスター デバイスはバス上の通信を制御する責任を負い、スレーブ デバイスはマスター デバイスのコマンドまたは要求に受動的に応答します。
IIC プロトコルの通信プロセスは次のとおりです。
- マスター デバイスは開始信号 (Start) を送信します。マスター デバイスはクロック ラインを High に維持し、データ ラインに立ち下がりエッジを生成して、開始信号の開始を示します。
- マスターはデバイス アドレスと読み取り/書き込みビットを送信します。マスターは通信するスレーブのアドレスを送信し、読み取り (1) または書き込み (0) 操作を指定します。
- スレーブ応答: アドレスに一致するスレーブ デバイスがマスター デバイスに応答し、アドレスの受信を確認します。
- データ送信: マスター デバイスとスレーブ デバイス間のデータ送信。各データ バイトはデータ ライン上で送信され、クロックのエッジでサンプリングされます。
- 停止信号 (Stop): マスター デバイスは停止信号を送信します。つまり、クロック ラインが High のままである間に、データ ラインに立ち上がりエッジが生成されます。
IIC プロトコルには次の特徴があります。
- シンプル: 通信には 2 本のワイヤのみを使用します。
- マルチデバイスのサポート: 複数のデバイスを同じバス経由で接続できます。
- 柔軟な速度: ニーズに応じてさまざまなクロック周波数を選択できます。
- 双方向通信: マスターデバイスはスレーブデバイスにコマンドを送信し、スレーブデバイスからデータを読み取ることができます。
IIC プロトコルは、センサー、メモリ、ディスプレイ、その他の集積回路間の通信など、さまざまな分野で広く使用されています。そのシンプルさと柔軟性により広く採用されており、デバイス間の通信がより便利で信頼性の高いものになります。
下図に示すように、プロトコルでは、SCLK クロック信号が常に High レベルの場合、SDA ラインが High レベルから Low レベルにジャンプし、スタート信号を示すことが規定されています。このとき、SDAデータ線のレベルジャンプが完了しても、SCLK線はハイレベルのままであることに注意してください。IIC バスに接続されている周辺モジュールがこの信号を検出すると、データの送信が開始されることがわかります。終了信号も同様で、SCLK クロック信号が常に High レベルの場合、SDA ラインが Low レベルから High レベルにジャンプして終了信号を示すことがプロトコルで規定されています。
2. IICプロトコルを備えたOLEDスクリーン
私が使用する主な MCU は、以下に示すように STM32F103RCT6 です。
つまり、ピンを定義します。
IIC プロトコル (SSD1306) の OLED 動作原理:
- ssd1306 自体は、SPI やパラレル ポートを含むさまざまなバス ドライバー モードをサポートしています。チップの対応する IO ポートを Low および High にプルすることで、どのインターフェイスを選択できます。この例では、モジュールは抵抗器を介して対応する IO ポート構成を固定し、 I2C インターフェイス方式を使用しますが、購入した同じドライバー チップ モジュールが他のインターフェイスを使用する可能性があります。
- I2C インターフェイスを使用する場合、SSD1306 は最大 2 つの 7 ビット I2C アドレスを許可し、対応する IO ポートを Low にプルして High にプルすることで切り替えることもできます。デフォルトは 0x3c です。画面モジュールの背面に、次のように表示されます。 I2C アドレス切り替えプロンプトモジュールの I2C アドレスを変更する必要がある場合は、プロンプトの位置にある抵抗を取り外し、もう一方の端にはんだ付けするだけです。ボード上の I2C アドレスは、0 番目の読み取りおよび書き込みビットを追加した後の値であることに注意してください。
0x78 = 0x3c<<1
0x7A = 0x3d<<1
3. STM32ドライバーコード
/*引脚初始化*/
void OLED_I2C_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_Init(GPIOC, &GPIO_InitStructure);
OLED_W_SCL(1);
OLED_W_SDA(1);
}
4.IIC使用コード
/**
* @brief I2C开始
* @param 无
* @retval 无
*/
void OLED_I2C_Start(void)
{
OLED_W_SDA(1);
OLED_W_SCL(1);
OLED_W_SDA(0);
OLED_W_SCL(0);
}
/**
* @brief I2C停止
* @param 无
* @retval 无
*/
void OLED_I2C_Stop(void)
{
OLED_W_SDA(0);
OLED_W_SCL(1);
OLED_W_SDA(1);
}
/**
* @brief I2C发送一个字节
* @param Byte 要发送的一个字节
* @retval 无
*/
void OLED_I2C_SendByte(uint8_t Byte)
{
uint8_t i;
for (i = 0; i < 8; i++)
{
OLED_W_SDA(Byte & (0x80 >> i));
OLED_W_SCL(1);
OLED_W_SCL(0);
}
OLED_W_SCL(1); //额外的一个时钟,不处理应答信号
OLED_W_SCL(0);
}
/**
* @brief OLED写命令
* @param Command 要写入的命令
* @retval 无
*/
void OLED_WriteCommand(uint8_t Command)
{
OLED_I2C_Start();
OLED_I2C_SendByte(0x78); //从机地址
OLED_I2C_SendByte(0x00); //写命令
OLED_I2C_SendByte(Command);
OLED_I2C_Stop();
}
/**
* @brief OLED写数据
* @param Data 要写入的数据
* @retval 无
*/
void OLED_WriteData(uint8_t Data)
{
OLED_I2C_Start();
OLED_I2C_SendByte(0x78); //从机地址
OLED_I2C_SendByte(0x40); //写数据
OLED_I2C_SendByte(Data);
OLED_I2C_Stop();
}
/**
* @brief OLED设置光标位置
* @param Y 以左上角为原点,向下方向的坐标,范围:0~7
* @param X 以左上角为原点,向右方向的坐标,范围:0~127
* @retval 无
*/
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
OLED_WriteCommand(0xB0 | Y); //设置Y位置
OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4)); //设置X位置低4位
OLED_WriteCommand(0x00 | (X & 0x0F)); //设置X位置高4位
}
/**
* @brief OLED清屏
* @param 无
* @retval 无
*/
void OLED_Clear(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
} //更新显示
}
/**
* @brief OLED显示一个字符
* @param Line 行位置,范围:1~4
* @param Column 列位置,范围:1~16
* @param Char 要显示的一个字符,范围:ASCII可见字符
* @retval 无
*/
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{
uint8_t i;
OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8); //设置光标位置在上半部分
for (i = 0; i < 8; i++)
{
OLED_WriteData(OLED_F8x16[Char - ' '][i]); //显示上半部分内容
}
OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8); //设置光标位置在下半部分
for (i = 0; i < 8; i++)
{
OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]); //显示下半部分内容
}
}
/**
* @brief OLED显示字符串
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param String 要显示的字符串,范围:ASCII可见字符
* @retval 无
*/
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
uint8_t i;
for (i = 0; String[i] != '\0'; i++)
{
OLED_ShowChar(Line, Column + i, String[i]);
}
}
void OLED_WR_Byte(unsigned dat,unsigned cmd)
{
if(cmd)
{
OLED_WriteData(dat);
}
else {
OLED_WriteCommand(dat);
}
}
//坐标设置
void OLED_Set_Pos(unsigned char x, unsigned char y)
{ OLED_WR_Byte(0xb0+y,OLED_CMD);
OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
OLED_WR_Byte((x&0x0f),OLED_CMD);
}
//显示汉字
void OLED_ShowCHinese(u8 x,u8 y,u8 no)
{
u8 t,adder=0;
OLED_Set_Pos(x,y);
for(t=0;t<16;t++)
{
OLED_WR_Byte(Hzk[2*no][t],OLED_DATA);
adder+=1;
}
OLED_Set_Pos(x,y+1);
for(t=0;t<16;t++)
{
OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA);
adder+=1;
}
}
/***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
{
unsigned int j=0;
unsigned char x,y;
if(y1%8==0) y=y1/8;
else y=y1/8+1;
for(y=y0;y<y1;y++)
{
OLED_Set_Pos(x0,y);
for(x=x0;x<x1;x++)
{
OLED_WR_Byte(BMP[j++],OLED_DATA);
}
}
}
/**
* @brief OLED次方函数
* @retval 返回值等于X的Y次方
*/
uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{
uint32_t Result = 1;
while (Y--)
{
Result *= X;
}
return Result;
}
/**
* @brief OLED显示数字(十进制,正数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~4294967295
* @param Length 要显示数字的长度,范围:1~10
* @retval 无
*/
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i++)
{
OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
}
}
/**
* @brief OLED显示数字(十进制,带符号数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:-2147483648~2147483647
* @param Length 要显示数字的长度,范围:1~10
* @retval 无
*/
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{
uint8_t i;
uint32_t Number1;
if (Number >= 0)
{
OLED_ShowChar(Line, Column, '+');
Number1 = Number;
}
else
{
OLED_ShowChar(Line, Column, '-');
Number1 = -Number;
}
for (i = 0; i < Length; i++)
{
OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
}
}
/**
* @brief OLED显示数字(十六进制,正数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~0xFFFFFFFF
* @param Length 要显示数字的长度,范围:1~8
* @retval 无
*/
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
uint8_t i, SingleNumber;
for (i = 0; i < Length; i++)
{
SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
if (SingleNumber < 10)
{
OLED_ShowChar(Line, Column + i, SingleNumber + '0');
}
else
{
OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
}
}
}
/**
* @brief OLED显示数字(二进制,正数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~1111 1111 1111 1111
* @param Length 要显示数字的长度,范围:1~16
* @retval 无
*/
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i++)
{
OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
}
}
/**
* @brief OLED初始化
* @param 无
* @retval 无
*/
void OLED_Init(void)
{
uint32_t i, j;
for (i = 0; i < 1000; i++) //上电延时
{
for (j = 0; j < 1000; j++);
}
OLED_I2C_Init(); //端口初始化
OLED_WriteCommand(0xAE); //关闭显示
OLED_WriteCommand(0xD5); //设置显示时钟分频比/振荡器频率
OLED_WriteCommand(0x80);
OLED_WriteCommand(0xA8); //设置多路复用率
OLED_WriteCommand(0x3F);
OLED_WriteCommand(0xD3); //设置显示偏移
OLED_WriteCommand(0x00);
OLED_WriteCommand(0x40); //设置显示开始行
OLED_WriteCommand(0xA1); //设置左右方向,0xA1正常 0xA0左右反置
OLED_WriteCommand(0xC8); //设置上下方向,0xC8正常 0xC0上下反置
OLED_WriteCommand(0xDA); //设置COM引脚硬件配置
OLED_WriteCommand(0x12);
OLED_WriteCommand(0x81); //设置对比度控制
OLED_WriteCommand(0xCF);
OLED_WriteCommand(0xD9); //设置预充电周期
OLED_WriteCommand(0xF1);
OLED_WriteCommand(0xDB); //设置VCOMH取消选择级别
OLED_WriteCommand(0x30);
OLED_WriteCommand(0xA4); //设置整个显示打开/关闭
OLED_WriteCommand(0xA6); //设置正常/倒转显示
OLED_WriteCommand(0x8D); //设置充电泵
OLED_WriteCommand(0x14);
OLED_WriteCommand(0xAF); //开启显示
OLED_Clear(); //OLED清屏
}
要約する
基本的な使い方は上記のコードに記載してありますので、参考にしてください。また、IIC の説明はあまり専門的ではありません。某サイトにあるさまざまな教育ビデオが参考になります。教材が多すぎるので、この部分は省略します。詳しくは紹介されません。
エンジニアリングリンク: OLED
努力に代わるものはない