STM32 | IIC 驱动OLED显示字符
I2C(IIC,Inter-Integrated Circuit),两线式串行总线,由PHILIPS公司开发用于连接微控制器及其外围设备。
硬件连接图:
它是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,高速IIC总线一般可达400kbps。
【串口】只能做点对点------115200bps
【 IIC 】 可以一对多------400kbps(比串口更快),但是半双工通信
OLED模块
TB上选的一个支持IIC通信的OLED模块
在STM32上的准备
需要加入I2C通信,直接使用STM32带有的库就好,当然也可根据IIC的时序自己来写模拟IIC
代码
GPIO口配置
对GPIO进行复用配置
还需要对IIC进行配置(I2C 总线的时钟频率)
void I2C_Configuration(void)
{
I2C_InitTypeDefI2C_InitStructure;
GPIO_InitTypeDefGPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
// 初始化GPIO的设置
/*STM32硬件I2C: PB10 -- SCL; PB11 -- SDA */
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;//I2C必须开漏输出
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 对I2C2进行配置
I2C_DeInit(I2C2);//使用I2C2
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x30;//主机的I2C地址,随便写的
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 400000;//400K
I2C_Cmd(I2C2, ENABLE);
I2C_Init(I2C2, &I2C_InitStructure);
}
IIC写操作函数
目的是写一个字节数据到寄存器中,采用阻塞式设计,会等待每个操作完成后再继续下一步,确保数据正确传输。
接收两个参数,addr代表寄存器地址,data代表数据
先写入设备地址,用于选中总线上的IIC设备
再写入寄存器地址
最后写入要写的寄存器的值
void I2C_WriteByte(uint8_t addr,uint8_t data)
{
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
I2C_GenerateSTART(I2C1, ENABLE);//开启I2C1
// 等待事件(EV5,主模式),确认起始信号已成功发送。
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C1, OLED_ADDRESS, I2C_Direction_Transmitter);//发送器件地址(选中从设备)
// 等待事件,确认设备已响应并进入发送模式。
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(I2C1, addr);//发送寄存器地址
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_SendData(I2C1, data);//发送数据
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTOP(I2C1, ENABLE);//关闭I2C1总线
}
OLED写数据接口封装
用于写命令(写到寄存器地址0x00)和写数据(写到寄存器地址0x40)
void WriteCmd(unsigned char I2C_Command)//写命令
{
I2C_WriteByte(0x00, I2C_Command);
}
void WriteDat(unsigned char I2C_Data)//写数据
{
I2C_WriteByte(0x40, I2C_Data);
}
OLED_Init() OLED的初始化
也是调用底层的IIC操作接口所封装而成:
void OLED_Init(void)
{
delay_ms(100);
printf("OLED_Init()\r\n");
WriteCmd(0xAE); //display off
WriteCmd(0x20); //Set Memory Addressing Mode
WriteCmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
WriteCmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7
WriteCmd(0xc8); //Set COM Output Scan Direction
WriteCmd(0x00); //---set low column address
WriteCmd(0x10); //---set high column address
WriteCmd(0x40); //--set start line address
WriteCmd(0x81); //--set contrast control register
WriteCmd(0xff); //亮度调节 0x00~0xff
WriteCmd(0xa1); //--set segment re-map 0 to 127
WriteCmd(0xa6); //--set normal display
WriteCmd(0xa8); //--set multiplex ratio(1 to 64)
WriteCmd(0x3F); //
WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
WriteCmd(0xd3); //-set display offset
WriteCmd(0x00); //-not offset
WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency
WriteCmd(0xf0); //--set divide ratio
WriteCmd(0xd9); //--set pre-charge period
WriteCmd(0x22); //
WriteCmd(0xda); //--set com pins hardware configuration
WriteCmd(0x12);
WriteCmd(0xdb); //--set vcomh
WriteCmd(0x20); //0x20,0.77xVcc
WriteCmd(0x8d); //--set DC-DC enable
WriteCmd(0x14); //
WriteCmd(0xaf); //--turn on oled panel
}
OLED一些基础函数的封装
也是通过写命令 WriteCmd() 和写数据 WriteDat() 来实现
void OLED_SetPos(unsigned char x, unsigned char y) //设置起始点坐标
{
WriteCmd(0xb0+y);
WriteCmd(((x&0xf0)>>4)|0x10);
WriteCmd((x&0x0f)|0x01);
}
void OLED_Fill(unsigned char fill_Data)//全屏填充
{
unsigned char m,n;
for(m=0;m<8;m++)
{
WriteCmd(0xb0+m); //page0-page1
WriteCmd(0x00); //low column start address
WriteCmd(0x10); //high column start address
for(n=0;n<128;n++)
{
WriteDat(fill_Data);
}
}
}
void OLED_CLS(void)//清屏
{
OLED_Fill(0x00);
}
//--------------------------------------------------------------
// Prototype : void OLED_ON(void)
// Calls :
// Parameters : none
// Description : 将OLED从休眠中唤醒
//--------------------------------------------------------------
void OLED_ON(void)
{
WriteCmd(0X8D);//设置电荷泵
WriteCmd(0X14);//开启电荷泵
WriteCmd(0XAF);//OLED唤醒
}
//--------------------------------------------------------------
// Prototype : void OLED_OFF(void)
// Calls :
// Parameters : none
// Description : 让OLED休眠 -- 休眠模式下,OLED功耗不到10uA
//--------------------------------------------------------------
void OLED_OFF(void)
{
WriteCmd(0X8D);//设置电荷泵
WriteCmd(0X10);//关闭电荷泵
WriteCmd(0XAE);//OLED休眠
}
OLED_ShowStr() 显示字符串
接收四个参数,分别是:
x:起始点横坐标 (0~127)
y:起始点纵坐标 (0~7)
ch:要显示的字符串
TextSize -- 字符大小选择 (1:6*8 ; 2:8*16)
//--------------------------------------------------------------
// Prototype : void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
// Calls :
// Parameters : x,y -- 起始点坐标(x:0~127, y:0~7); ch[] -- 要显示的字符串; TextSize -- 字符大小(1:6*8 ; 2:8*16)
// Description : 显示codetab.h中的ASCII字符,有6*8和8*16可选择
//--------------------------------------------------------------
void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
{
unsigned char c = 0,i = 0,j = 0;
switch(TextSize)
{
case 1:
{
while(ch != '\0')
{
c = ch - 32;
if(x > 126)
{
x = 0;
y++;
}
OLED_SetPos(x,y);
for(i=0;i<6;i++)
WriteDat(F6x8);
x += 6;
j++;
}
}break;
case 2:
{
while(ch != '\0')
{
c = ch - 32;
if(x > 120)
{
x = 0;
y++;
}
OLED_SetPos(x,y);
for(i=0;i<8;i++)
WriteDat(F8X16);
OLED_SetPos(x,y+1);
for(i=0;i<8;i++)
WriteDat(F8X16);
x += 8;
j++;
}
}break;
}
}
主函数调用:
void task1_task(void *pvParameters)
{
unsigned char i;
I2C_Configuration(); /*I2C: PB10 -- SCL; PB11 -- SDA */
OLED_Init();
while(1)
{
OLED_Fill(0xFF);//全屏点亮
delay_ms(2000);
OLED_Fill(0x00);//全屏灭
delay_ms(2000);
delay_ms(2000);
OLED_ShowStr(0,3,"asdfasdfasY",2);
OLED_ShowStr(0,6,"1997 1998 2025 07 08",1);
delay_ms(2000);
OLED_CLS();//清屏
OLED_OFF();//测试OLED休眠
delay_ms(2000);
OLED_ON();//测试OLED休眠后唤醒
delay_ms(2000);
}
}
显示中文:
这个可以通过取模软件的出来,在软件中输入汉字,就可以得到这些对应的数组内容
/***************************16*16的点阵字体取模方式:共阴——列行式——逆向输出*********/
unsigned char F16x16[] =
{
0x00,0x40,0x20,0x1E,0x10,0x10,0x10,0xFF,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,
0x02,0x02,0x02,0x02,0x02,0x02,0x02,0xFF,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00,/*"牛",0*/
0x40,0x40,0x42,0xCC,0x00,0x82,0xBA,0xAA,0xAA,0xAA,0xAA,0xAA,0xBA,0x82,0x00,0x00,
0x00,0x40,0x20,0x1F,0x20,0x5F,0x4A,0x4A,0x4A,0x4F,0x4A,0x4A,0x4A,0x5F,0x40,0x00,/*"逼",1*/
0xFC,0x04,0xFC,0x00,0xFE,0x42,0xBE,0x00,0xF2,0x12,0xF2,0x02,0xFE,0x02,0x00,0x00,
0x0F,0x04,0x0F,0x00,0xFF,0x10,0x0F,0x00,0x0F,0x04,0x4F,0x80,0x7F,0x00,0x00,0x00,/*"啊",2*/
};
//--------------------------------------------------------------
// Prototype : void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
// Calls :
// Parameters : x,y -- 起始点坐标(x:0~127, y:0~7); N:汉字在codetab.h中的索引
// Description : 显示codetab.h中的汉字,16*16点阵
//--------------------------------------------------------------
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
{
unsigned char wm=0;
unsigned intadder=32*N;
OLED_SetPos(x , y);
for(wm = 0;wm < 16;wm++)
{
WriteDat(F16x16);
adder += 1;
}
OLED_SetPos(x,y + 1);
for(wm = 0;wm < 16;wm++)
{
WriteDat(F16x16);
adder += 1;
}
}
// 调用,一般打横显示,注意每个字符之间的大小间距
{
for(i=0; i<CharNum; i++)
{
OLED_ShowCN(22+i*16,0,i);//测试显示中文
}
}
————————————————
版权声明:本文为CSDN博主「扣篮发型不乱」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/KawhiLeo/article/details/149140065
页:
[1]