stm32使用OLED屏(4脚,iic通信,12864)

采用的OLED屏使用的IIC(Inter-Integrated Circuit)通信协议是一种串行通信协议,通常用于连接低速度外设,如EEPROM、ADC、DAC等。IIC通信协议通常有起始信号、停止信号、数据传输、应答信号和非应答信号等,具体原理如下:

起始信号(SDA低电平): 当SDA线从高电平跳变到低电平时,表示一个数据传输的开始(图2.1)。

停止信号(SDA高电平): 当SDA线从低电平跳变到高电平时,表示一个数据传输的结束(图2.2)。

数据传输: 在IIC通信中,数据传输是通过SDA线上的高低电平变化来实现的。数据传输时,发送方将数据位放在SDA线上,然后通过SCL线上的时钟信号将数据位发送给接收方。接收方通过检测SDA线上的电平变化来接收数据。

应答信号(ACK): 在数据传输过程中,接收方需要在接收到每个数据位后发送一个应答信号(ACK),表示数据已被正确接收。应答信号是一个低电平,在SDA线上持续一段时间,然后恢复高电平(图2.3)。

非应答信号(NACK): 在数据传输过程中,如果接收方无法正确接收数据,会发送一个非应答信号(NACK),表示数据未被正确接收。非应答信号是一个高电平,在SDA线上持续一段时间,然后恢复低电平(图2.3)。

IIC通信的时钟信号(SCL)是由发送方产生的,通常频率为10KHz~100KHz。IIC通信的波特率由时钟信号的频率决定。

IIC通信的优点是简单、易于实现,缺点是速度较慢,通常用于低速度外设的通信。

图2.1 起始信号

图2.2 停止信号

图2.3 应答与非应答信号

图2.4 IIC协议时序

2.2.2 OLED屏原理

此次项目采用的是0.96寸OLED屏幕,规格为128X64,即在横向上有128个像素点,竖向上有64个像素点,向外部引出4个引脚,分别是VCC(电源)、GND(底线)、SCL(时钟线)、SDA(信号线),其原理图如下(图2.5 OLED模块原理图)。

OLED屏的工作原理是通过点亮各个像素点来实现可视化界面,需要从单片机输入一组模拟信号来告诉它该点亮那些区域,这就要求在单片机上要预先设定好字体,数字的字模,在需要使用到OLED屏时,就将字模通过IIC协议传递给它,从而实现功能。

图2.5 OLED模块原理图

IIC通信按我自己的理解就是先在发送数据端(32单片机)将时钟线scl和数据线sda上给一定持续时间的高电平,然后将sda线的电平拉低,会检测到一个下降沿,然后将scl线也拉低,两条线的低电平持续一定的时间就可以了,告诉接收数据端(oled)准备发数据了,然后oled检测到以后就发送一个应答信号给单片机(sda低电平,scl为高电平持续一段时间),收到应答信号以后就开始发送数据,IIC信号在数据传输过程中,当SCL=1高电平时,数据线SDA必须保持稳定状态,不允许有电平跳变,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。SCL=1时 数据线SDA的任何电平变换会看做是总线的起始信号或者停止信号。也就是在IIC传输数据的过程中,SCL时钟线会频繁的转换电平,以保证数据的传输,后面接着传终止信号等。就可以将数据完整的传递过去,看一下初始化:

#include "i2c.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

I2C_HandleTypeDef hi2c1;

/* I2C1 init function */
void MX_I2C1_Init(void)
{

  /* USER CODE BEGIN I2C1_Init 0 */

  /* USER CODE END I2C1_Init 0 */

  /* USER CODE BEGIN I2C1_Init 1 */

  /* USER CODE END I2C1_Init 1 */
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C1_Init 2 */

  /* USER CODE END I2C1_Init 2 */

}

void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(i2cHandle->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspInit 0 */

  /* USER CODE END I2C1_MspInit 0 */

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**I2C1 GPIO Configuration
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* I2C1 clock enable */
    __HAL_RCC_I2C1_CLK_ENABLE();
  /* USER CODE BEGIN I2C1_MspInit 1 */

  /* USER CODE END I2C1_MspInit 1 */
  }
}

void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle)
{

  if(i2cHandle->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspDeInit 0 */

  /* USER CODE END I2C1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_I2C1_CLK_DISABLE();

    /**I2C1 GPIO Configuration
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6);

    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_7);

  /* USER CODE BEGIN I2C1_MspDeInit 1 */

  /* USER CODE END I2C1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

我是直接用stm32mx直接生成的初始化,标准库的如下:

#include <iic.h>

// 定义IIC接口引脚
#define IIC_SDA_PIN 10
#define IIC_SCL_PIN 11

// 初始化IIC接口
void iic_init() {
    // 设置IIC接口引脚为输出模式
    pinMode(IIC_SDA_PIN, OUTPUT);
    pinMode(IIC_SCL_PIN, OUTPUT);

    // 初始化IIC接口时钟
    iic_clock_init();
}

// 发送IIC开始信号
void iic_start() {
    // 发送低电平
    digitalWrite(IIC_SDA_PIN, LOW);
    delayMicroseconds(IIC_DELAY);

    // 发送高电平
    digitalWrite(IIC_SCL_PIN, HIGH);
    delayMicroseconds(IIC_DELAY);

    // 发送高电平
    digitalWrite(IIC_SDA_PIN, HIGH);
    delayMicroseconds(IIC_DELAY);
}

// 发送IIC停止信号
void iic_stop() {
    // 发送高电平
    digitalWrite(IIC_SDA_PIN, HIGH);
    delayMicroseconds(IIC_DELAY);

    // 发送低电平
    digitalWrite(IIC_SCL_PIN, LOW);
    delayMicroseconds(IIC_DELAY);

    // 发送低电平
    digitalWrite(IIC_SDA_PIN, LOW);
    delayMicroseconds(IIC_DELAY);
}

// 发送IIC数据
void iic_write(uint8_t data) {
    uint8_t i;

    // 发送数据位
    for (i = 0; i < 8; i++) {
        digitalWrite(IIC_SDA_PIN, (data & 0x80) ? HIGH : LOW);
        delayMicroseconds(IIC_DELAY);

        digitalWrite(IIC_SCL_PIN, HIGH);
        delayMicroseconds(IIC_DELAY);

        digitalWrite(IIC_SCL_PIN, LOW);
        delayMicroseconds(IIC_DELAY);

        data <<= 1;
    }
}

// 读取IIC数据
uint8_t iic_read() {
    uint8_t i, data = 0;

    // 发送高电平
    digitalWrite(IIC_SDA_PIN, HIGH);
    delayMicroseconds(IIC_DELAY);

    // 发送低电平
    digitalWrite(IIC_SCL_PIN, LOW);
    delayMicroseconds(IIC_DELAY);

    // 读取数据位
    for (i = 0; i < 8; i++) {
        digitalWrite(IIC_SCL_PIN, HIGH);
        delayMicroseconds(IIC_DELAY);

        data |= digitalRead(IIC_SDA_PIN) ? 0 : 1;
        delayMicroseconds(IIC_DELAY);

        digitalWrite(IIC_SCL_PIN, LOW);
        delayMicroseconds(IIC_DELAY);

        data <<= 1;
    }

    return data;
}

// 等待IIC设备响应
void iic_wait_response() {
    uint8_t response;

    // 发送开始信号
    iic_start();

    // 发送设备地址

iic写完以后就可以用32驱动oled传输数据了,传输的数据就是一些字模,先来驱动:

#include "font.h"	//字库文件
#include "oled.h"		//声明
#include "i2c.h"


//接线
// SCL --- PB6
// SDA --- PB7

/* 控制宏 */
#define LEFT 			0x27
#define RIGHT 			0x26
#define UP 				0X29
#define DOWM 			0x2A
#define ON				0xA7
#define OFF				0xA6


/* IIC接口选择 */
#define IICx hi2c1


//oled显示尺寸
uint16_t const displayWidth                = 128;
uint16_t const displayHeight               = 64;

/*  OLED显存
[0]0 1 2 3 ... 127	
[1]0 1 2 3 ... 127	
[2]0 1 2 3 ... 127	
[3]0 1 2 3 ... 127	
[4]0 1 2 3 ... 127	
[5]0 1 2 3 ... 127	
[6]0 1 2 3 ... 127	
[7]0 1 2 3 ... 127 */

static uint8_t OLED_RAM[8][128];//定义GDDRAM缓存区


//更换备注方式
/**
  * @brief  
  * @param  GPIOx: 
  * @param  GPIO_Init: 
  * @retval None
  */
	
void HAL_I2C_WriteByte(uint8_t addr,uint8_t data)
{
  uint8_t TxData[2] = {addr,data};
	
	HAL_I2C_Master_Transmit(&IICx,0x78,(uint8_t*)TxData,2,10);
	//HAL_I2C_Master_Transmit(&IICx,0x3c,(uint8_t*)TxData,2,10);
}

/**************************************************************
	 Prototype      : void WriteCmd(uint8_t IIC_Command)
	 Parameters     : IIC_Command
	 return					: none
	 Description    : 写命令
***************************************************************/
void WriteCmd(uint8_t IIC_Command)
{
	HAL_I2C_WriteByte(0x00, IIC_Command);
}

/**************************************************************
	 Prototype      : void WriteDat(uint8_t IIC_Data)
	 Parameters     : IIC_Data
	 return					: none
	 Description    : 写数据
***************************************************************/
void WriteDat(uint8_t IIC_Data)
{
	HAL_I2C_WriteByte(0x40, IIC_Data);
}

/**************************************************************
	 Prototype      : void OLED_Init(void)
	 Parameters     : none
	 return					: none
	 Description    : 初始化OLED模块
***************************************************************/
void OLED_Init(void) 
{
	HAL_Delay(500);
	
	WriteCmd(0xAE); //开显示
	WriteCmd(0x20);	//设置内存寻址模式	
	
	WriteCmd(0x10);	//00,水平寻址模式;01,垂直寻址模式;10,页面寻址模式(重置);11,无效
	WriteCmd(0xb0);	//为页面寻址模式设置页面开始地址,0-7
	WriteCmd(0x00); //---设置低列地址
	WriteCmd(0x10); //---设置高列地址

	WriteCmd(0xc8);	//设置COM输出扫描方向
	WriteCmd(0x40); //--设置起始行地址
	WriteCmd(0x81); //--set contrast control register
	WriteCmd(0xff); //亮度调节 0x00~0xff
	WriteCmd(0xa1); //--设置段重新映射0到127
	WriteCmd(0xa6); //--设置正常显示
	WriteCmd(0xa8); //--设置复用比(1 ~ 64)
	WriteCmd(0x3F); //
	WriteCmd(0xa4); //0xa4,输出遵循RAM内容;0xa5,Output忽略RAM内容
	WriteCmd(0xd3); //-设置显示抵消
	WriteCmd(0x00); //-not offset
	WriteCmd(0xd5); //--设置显示时钟分频/振荡器频率
	WriteCmd(0xf0); //--设置分率
	WriteCmd(0xd9); //--设置pre-charge时期
	WriteCmd(0x22); //
	WriteCmd(0xda); //--设置com大头针硬件配置
	WriteCmd(0x12);
	WriteCmd(0xdb); //--设置vcomh
	WriteCmd(0x20); //0x20,0.77xVcc
	WriteCmd(0x8d); //--设置DC-DC
	WriteCmd(0x14); //
	WriteCmd(0xaf); //--打开oled面板
	
	OLED_FullyClear();//清屏
}

/**************************************************************
	 Prototype      : void OLED_ON(void)
	 Parameters     : none
	 return					: none
	 Description    : 将OLED从休眠中唤醒
***************************************************************/
void OLED_ON(void)
{
	WriteCmd(0X8D);  //设置电荷泵
	WriteCmd(0X14);  //开启电荷泵
	WriteCmd(0XAF);  //OLED唤醒
}

/**************************************************************
	 Prototype      : void OLED_OFF(void)
	 Parameters     : none
	 return					: none
	 Description    : 让OLED休眠 -- 休眠模式下,OLED功耗不到10uA
***************************************************************/
void OLED_OFF(void)
{
	WriteCmd(0X8D);  //设置电荷泵
	WriteCmd(0X10);  //关闭电荷泵
	WriteCmd(0XAE);  //OLED休眠
}

/**************************************************************
	 Prototype      : void OLED_RefreshRAM(void)
	 Parameters     : none
	 return					: none
	 Description    : 全屏填充
***************************************************************/
void OLED_RefreshRAM(void)
{
	// 页寻址模式填充
	for(uint16_t m = 0; m < displayHeight/8; m++)
	{
		WriteCmd(0xb0+m);		//设置页地址b0~b7
		WriteCmd(0x00);		//设置显示位置—列低地址00-0f
		WriteCmd(0x10);		//设置显示位置—列高地址10-1f
		for(uint16_t n = 0; n < displayWidth; n++)
		{
				WriteDat(OLED_RAM[m][n]);
		}
	} 
}

/**************************************************************
	 Prototype      : void OLED_ClearRAM(void)
	 Parameters     : none
	 return					: none
	 Description    : 清除数据缓冲区
***************************************************************/
void OLED_ClearRAM(void)
{
	for(uint16_t m = 0; m < displayHeight/8; m++)
	{
		for(uint16_t n = 0; n < displayWidth; n++)
		{
				OLED_RAM[m][n] = 0x00;
		}
	}
}


/**************************************************************
	 Prototype      : void OLED_Fill(uint8_t fill_Data)
	 Parameters     : fill_Data 填充的1字节数据
	 return					: none
	 Description    : 全屏填充 0x00~0xff
***************************************************************/
void OLED_FullyFill(uint8_t fill_Data)
{
	for(uint16_t m = 0; m < displayHeight/8; m++)
	{
		for(uint16_t n = 0; n < displayWidth; n++)
		{
				OLED_RAM[m][n] = fill_Data;
		}
	}
	
	OLED_RefreshRAM();
}

/**************************************************************
	 Prototype      : void OLED_FullyClear(void)
	 Parameters     : none
	 return					: none
	 Description    : 全屏清除
***************************************************************/
void OLED_FullyClear(void)
{
		OLED_FullyFill(RESET_PIXEL);
}

/**************************************************************
	Prototype      :  void OLED_SetPixel(int16_t x, int16_t y, uint8_t set_pixel)
	Parameters     : 	x,y -- 起始点坐标(x:0~127, y:0~63); 
										set_pixel	 该点的数据  SET_PIXEL = 1, RESET_PIXEL = 0
	return				 :  none
	Description    : 	设置坐标像素点数据
***************************************************************/
void OLED_SetPixel(int16_t x, int16_t y, uint8_t set_pixel)
{ 
	if (x >= 0 && x < displayWidth && y >= 0 && y < displayHeight) {
		if(set_pixel){
				OLED_RAM[y/8][x] |= (0x01 << (y%8));
		}  
		else{
				OLED_RAM[y/8][x] &= ~(0x01 << (y%8));
		}
	}
}

/**************************************************************
	Prototype      :  void OLED_GetPixel(int16_t x, int16_t y)
	Parameters     : 	x,y -- 起始点坐标(x:0~127, y:0~63); 
	return				 :  PixelStatus 像素点状态 	SET_PIXEL = 1, RESET_PIXEL = 0
	Description    : 	获得坐标像素点数据	
***************************************************************/

PixelStatus OLED_GetPixel(int16_t x, int16_t y)
{
	 if(OLED_RAM[y/8][x] >> (y%8) & 0x01)
		 return SET_PIXEL;
	 
	return	RESET_PIXEL;
}

/**************************************************************
	Prototype      : void OLED_ShowStr(int16_t x, int16_t y, uint8_t ch[], uint8_t TextSize)
	Parameters     : 	x,y -- 起始点坐标(x:0~127, y:0~63); 
										ch[] -- 要显示的字符串; 
										TextSize -- 字符大小(1:6*8 ; 2:8*16)
	return				 :  none
	Description    : 	显示codetab.h中的ASCII字符,有6*8和8*16可选择
***************************************************************/
void OLED_ShowStr(int16_t x, int16_t y, uint8_t ch[], uint8_t TextSize)
{ 
	if (x >= 0 && x < displayWidth && y >= 0 && y < displayHeight) {
		int32_t c = 0;
		uint8_t j = 0;
	
		switch(TextSize)
		{
			case 1:
			{
				while(ch[j] != '\0')
				{
					c = ch[j] - 32;
					if(c < 0)	//无效字符
						break;
					
					if(x >= 125 || (127-x < 6))//一行最大显示字符数:21字节显示,多出两列,不显示 || 剩余列小于6不能显示完整字符,换行显示
					{
						x = 0;
						y += 8;//换行显示
						if(63 - y < 8)	// 不足以显示一行时不显示
							break;
					}
					for(uint8_t m = 0; m < 6; m++)
					{
						for(uint8_t n = 0; n < 8; n++)
						{
							OLED_SetPixel(x+m, y+n, (F6x8[c][m] >> n) & 0x01);
						}
					}
					x += 6;
					j++;
				}
			}break;
			case 2:
			{
				while(ch[j] != '\0')
				{
					c = ch[j] - 32;
					if(c < 0)	//无效字符
						break;
					
					if(x >= 127 || (127-x < 8))//16字节显示 || 剩余列小于8不能显示完整字符,换行显示
					{
						x = 0;
						y += 16;//换行显示
						if(63 - y < 16)	// 不足以显示一行时不显示
							break;
					}
					for(uint8_t m = 0; m < 2; m++)
					{
						for(uint8_t n = 0; n < 8; n++)
						{
							for(uint8_t i = 0; i < 8; i++)
							{
									OLED_SetPixel(x+n, y+i+m*8, (F8X16[c][n+m*8] >> i) & 0x01);
							}
						}	
					}
					x += 8;
					j++;
				}
			}break;
		}
	}
	OLED_RefreshRAM();
}

/**************************************************************
	 Prototype      : void OLED_ShowCN(int16_t x, int16_t y, uint8_t* ch)
	 Parameters     : x,y -- 起始点坐标(x:0~127, y:0~7); 
										CN[]:汉字在codetab.h中的索引
	 return				  : none
	 Description    : 显示codetab.h中的汉字,16*16点阵
***************************************************************/
void OLED_ShowCN(int16_t x, int16_t y, uint8_t* ch)
{
	if (x >= 0 && x < displayWidth && y >= 0 && y < displayHeight) {
		int32_t  len = 0,offset = sizeof(F16x16_CN[0].index);
		
		while(ch[len] != '\0')
		{
			if(x >= 127 || (127-x < 16))//8个汉字显示||剩余列小于16不能显示完整字符,换行显示
			{
				x = 0;
				y += 16;
				if(63 - y < 16)	// 不足以显示一行时不显示
					break;
			}
					
			//需要处理输入数据大于显示数据的问题
			for(uint8_t i = 0; i < sizeof(F16x16_CN)/sizeof(GB2312_CN); i++)
			{
				if(((F16x16_CN[i].index[0] == ch[len]) && (F16x16_CN[i].index[1] == ch[len+1]))){
						for(uint8_t m = 0; m < 2; m++)	//页
						{
								for(uint8_t n = 0; n < 16; n++) // 列
								{
										for(uint8_t j = 0; j < 8; j++)	// 行
										{
											OLED_SetPixel(x+n, y+j+m*8, (F16x16_CN[i].encoder[n+m*16] >> j) & 0x01);
										}
								}
						}			
						x += 16;
						len += offset;
						break;
				}
				else if(F16x16_CN[i].index[0] == ch[len] && ch[len] == 0x20){
					for(uint8_t m = 0; m < 2; m++)
					{
							for(uint8_t n = 0; n < 16; n++)
							{
								for(uint8_t j = 0; j < 8; j++)
								{
									OLED_SetPixel(x+n, y+j+m*8, (F16x16_CN[i].encoder[n+m*16] >> j) & 0x01);
								}								
							}	
					}			
					x += 16;
					len++;
					break;
				}
			}
		}
	}
	OLED_RefreshRAM();
}

/**************************************************************
	 Prototype      : void OLED_Show_MixedCH(int16_t x, int16_t y, uint8_t* ch)
	 Parameters     : x,y -- 起始点坐标(x:0~127, y:0~7); CN[]:汉字在codetab.h中的索引
	 return				  : none
	 Description    : 显示codetab.h中的汉字,16*16点阵,英文,8*16点阵
***************************************************************/
void OLED_ShowMixedCH(int16_t x, int16_t y, uint8_t* ch)
{
	if (x >= 0 && x < displayWidth && y >= 0 && y < displayHeight) {
		int32_t len = 0, c,offset = sizeof(F16x16_CN[0].index);

		while(ch[len] != '\0')
		{
			if(ch[len] >= 0xa1)//GB2312从0xA1A0开始
			{
				for(uint8_t i = 0; i < sizeof(F16x16_CN)/sizeof(GB2312_CN); i++)
				{
					if(((F16x16_CN[i].index[0] == ch[len]) && (F16x16_CN[i].index[1] == ch[len+1])))
					{
						if(x >= 127|| (127-x < 16))//8个汉字显示||剩余列小于16不能显示完整字符,换行显示
						{
							x = 0;
							y += 16;
							if(63 - y < 16)	// 不足以显示一行时不显示
								break;
						}
						for(uint8_t m = 0; m < 2; m++)	//页
						{
								for(uint8_t n = 0; n < 16; n++)	//列
								{
									for(uint8_t j = 0; j < 8; j++)	//行
									{
	
										OLED_SetPixel(x+n, y+j+m*8, (F16x16_CN[i].encoder[n+m*16] >> j) & 0x01);
									}		
								}								
						}			
						x += 16;
						len += offset;
						break;
					}
				}
			}
			else if(ch[len] <= 127)//ASCII编码范围0-127
			{
				c = ch[len] - 32;
				if(c < 0)	// 无效字符
					break;
				if(x >= 127 || (127-x < 8))//16字节显示 || 剩余列小于8不能显示完整字符,换行显示
				{
					x = 0;
					y += 16;
					if(63 - y < 16)	// 不足以显示一行时不显示
								break;
				}
				for(uint8_t m = 0; m < 2; m++)
				{
						for(uint8_t n = 0; n < 8; n++)
						{
							for(uint8_t i = 0; i < 8; i++)
							{
									OLED_SetPixel(x+n, y+i+m*8, (F8X16[c][n+m*8] >> i) & 0x01);
							}
						}
				}
				x += 8;
				len++;
			}
		}
	}
	OLED_RefreshRAM();
}

/***************************************************************
	 Prototype      :	void OLED_DrawBMP(int16_t x0,int16_t y0,int16_t L,int16_t H,const uint8_t BMP[])
	 Parameters     : (x0,y0)坐标长L宽H区域绘制图像BMP
										0<=x0<=127 0<=y0<=63 0<=L+x0<=127 0<=H+y0<= 63 图像取模 纵向取模,字节倒序
	 return				  : none
	 Description    : 区域图像绘制,显示BMP位图,格式使用二维数组存储
***************************************************************/
void OLED_DrawBMP(int16_t x0,int16_t y0,int16_t L,int16_t H,const uint8_t BMP[])
{
	if (x0 >= 0 && x0 < displayWidth && x0+L <= displayWidth &&\
		y0 >= 0 && y0 < displayHeight && y0+H <= displayHeight) {
		
		uint8_t *p = (uint8_t *)BMP;
		for(int16_t y = y0; y < y0+H; y+=8)
		{
			for(int16_t x = x0; x < x0+L; x++)
			{
				for(int16_t i = 0; i < 8; i++)
				{
//					OLED_SetPixel(x, y+i, ((*((uint8_t *)BMP+(x-x0)+L*((y-y0)/8))) >> i) & 0x01);
						OLED_SetPixel(x, y+i, ((*p) >> i) & 0x01);
				}
				p++;
			}
		}
	}
	OLED_RefreshRAM();
}

/***************************************************************
	 Prototype      :	void OLED_AreaFill(int16_t x0,int16_t y0,int16_t L,int16_t H)
	 Parameters     : 区域内容清除,(x0,y0)坐标长L宽H区域
										0<=x0<=127 0<=y0<=63 0<=L+x0<=127 0<=H+y0<= 63 图像取模 纵向取模,字节倒序
	 return				  : none
	 Description    : 规定区域内容填充
***************************************************************/
void OLED_AreaFill(int16_t x0,int16_t y0,int16_t L,int16_t H, uint8_t fill_data)
{
	if (x0 >= 0 && x0 < displayWidth && x0+L <= displayWidth &&\
		y0 >= 0 && y0 < displayHeight && y0+H <= displayHeight) {
		
		for(int16_t y = y0; y < y0+H; y++)
		{
			for(int16_t x = x0; x < x0+L; x++)
			{
				for(int16_t i = 0; i < 8; i++)
					{
							OLED_SetPixel(x, y+i, (fill_data >> i) & SET_PIXEL);
					}
			}
		}
		OLED_RefreshRAM();
	}
}

/***************************************************************
	 Prototype      :	void OLED_AreaCLR(int16_t x0,int16_t y0,int16_t L,int16_t H)
	 Parameters     : (x0,y0)坐标长L宽H区域
										0<=x0<=127 0<=y0<=63 0<=L+x0<=127 0<=H+y0<= 63 图像取模 纵向取模,字节倒序
	 return				  : none
	 Description    : 规定区域内容清除
***************************************************************/
void OLED_AreaClear(int16_t x0,int16_t y0,int16_t L,int16_t H)
{
	if (x0 >= 0 && x0 < displayWidth && x0+L <= displayWidth &&\
		y0 >= 0 && y0 < displayHeight && y0+H <= displayHeight) {
		
		for(int16_t y = y0; y < y0+H; y+=8)
		{
			for(int16_t x = x0; x < x0+L; x++)
			{
				for(int16_t i = 0; i < 8; i++)
					{
							OLED_SetPixel(x, y+i, RESET_PIXEL);
					}
			}
		}		
		OLED_RefreshRAM();
	}
}
/***************************************************************
	 Prototype      :	void OLED_FullyToggle(void)
	 Parameters     : none
	 return				  : none
	 Description    : 缓冲区数据取反后刷新到GDDRAM
***************************************************************/
void OLED_FullyToggle(void)
{
	for(uint16_t m = 0; m < displayHeight/8; m++)
	{
		for(uint16_t n = 0; n < displayWidth; n++)
		{
				OLED_RAM[m][n] = ~OLED_RAM[m][n];
		}
	}
	OLED_RefreshRAM();
}
/***************************************************************
	 Prototype      :	void OLED_AreaToggle(int16_t x0,int16_t y0,int16_t L,int16_t H)
	 Parameters     : (x0,y0)坐标长L宽H区域
										0<=x0<=127 0<=y0<=63 0<=L+x0<=127 0<=H+y0<= 63 图像取模 纵向取模,字节倒序
	 return				  : none
	 Description    : 规定区域内容取反
***************************************************************/
void OLED_AreaToggle(int16_t x0,int16_t y0,int16_t L,int16_t H)
{
	if (x0 >= 0 && x0 < displayWidth && x0+L <= displayWidth &&\
		y0 >= 0 && y0 < displayHeight && y0+H <= displayHeight) {
		
		for(int16_t y = y0; y < y0+H; y+=8)
		{
			for(int16_t x = x0; x < x0+L; x++)
			{
				for(int16_t i = 0; i < 8; i++)
					{
							OLED_SetPixel(x, y+i, !OLED_GetPixel(x, y+i));
					}
			}
		}		
		OLED_RefreshRAM();
	}
}

/****************************************************************
	全屏垂直偏移,0->63方向
	方向垂直向上,范围0-63
	方向垂直向下,范围63-0
****************************************************************/
void OLED_VerticalShift(void)
{
	for(uint8_t i = 0; i < displayHeight; i++)
		{
			WriteCmd(0xd3);//设置显示偏移,0->63方向
			WriteCmd(i);//偏移量
			HAL_Delay(40);//延时时间
		}
}

/****************************************************************
	屏幕内容水平全屏滚动播放
	左		LEFT	0x27
	右		RIGHT	0x26
****************************************************************/
void OLED_HorizontalShift(uint8_t direction)

{
	WriteCmd(direction);//设置滚动方向
	WriteCmd(0x00);//虚拟字节设置,默认为0x00
	WriteCmd(0x00);//设置开始页地址
	WriteCmd(0x05);//设置每个滚动步骤之间的时间间隔的帧频
	WriteCmd(0x07);//设置结束页地址
	WriteCmd(0x00);//虚拟字节设置,默认为0x00
	WriteCmd(0xff);//虚拟字节设置,默认为0xff
	WriteCmd(0x2f);//开启滚动-0x2f,禁用滚动-0x2e,禁用需要重写数据
}

/****************************************************************
	屏幕内容垂直水平全屏滚动播放
	上		UP		0x29
	下		DOWN	0x2A
****************************************************************/
void OLED_VerticalAndHorizontalShift(uint8_t direction)
{
	WriteCmd(direction);//设置滚动方向
	WriteCmd(0x00);//虚拟字节设置,默认为0x00
	WriteCmd(0x00);//设置开始页地址
	WriteCmd(0x05);//设置每个滚动步骤之间的时间间隔的帧频
	WriteCmd(0x07);//设置结束页地址
	WriteCmd(0x01);//垂直滚动偏移量
	
	WriteCmd(0x2f);//开启滚动-0x2f,禁用滚动-0x2e,禁用需要重写数据
}

/****************************************************************
	屏幕内容取反显示
	开	ON	0xA7
	关	OFF	0xA6	默认此模式,设置像素点亮
****************************************************************/
void OLED_DisplayMode(uint8_t mode)
{
	WriteCmd(mode);
}

/****************************************************************
	屏幕亮度调节
	intensity	0-255
	默认为0x7f
****************************************************************/
void OLED_IntensityControl(uint8_t intensity)
{
	WriteCmd(0x81);
	WriteCmd(intensity);
}

这个驱动代码只可以写8*16和16*16两种格式,需要更多的格式可以去网上找一下,然后按照驱动写的函数依次按照项目的逻辑写出来就可以了,看一下oled.h文件

#ifndef OLED_H__
#define OLED_H__

#include "stm32f1xx_hal.h"	//链接HAL库
/* BMP图片声明 
	图片格式为二位数组,下标分别对应图片的宽和高:
		BMP_xx[H/8][L];
*/
extern const uint8_t BMP_Picture[64/8][64];


/* 设置坐标点的状态 */
typedef enum 
{
	SET_PIXEL = 0x01,
  RESET_PIXEL = 0x00, 
} PixelStatus;


/* 功能函数声明 */
//写数据,硬件IIC使用
void HAL_I2C_WriteByte(uint8_t addr,uint8_t data);
//写命令
void WriteCmd(uint8_t IIC_Command);
//写数据
void WriteDat(uint8_t IIC_Data);
//初始化OLED
void OLED_Init(void);
//开启电荷泵
void OLED_ON(void);
//关闭电荷泵
void OLED_OFF(void);
//刷新缓冲区数据到GDDRAM
void OLED_RefreshRAM(void);
//清除数据缓冲区OLED_RAM buffer
void OLED_ClearRAM(void);
//全屏填充
void OLED_FullyFill(uint8_t fill_Data);
//清屏
void OLED_FullyClear(void);
//设置坐标像素点数据
void OLED_SetPixel(int16_t x, int16_t y, uint8_t set_pixel);
//获得坐标像素点数据
PixelStatus OLED_GetPixel(int16_t x, int16_t y);

/* 显示指定字符和图片时需要手动刷新缓冲区到GDDRAM 
* function list: OLED_ShowStr\OLED_ShowCN\OLED_Show_MixedCH\OLED_DrawBMP
*/
//显示英文字符串
void OLED_ShowStr(int16_t x, int16_t y, uint8_t ch[], uint8_t TextSize);
//显示中文字符串
void OLED_ShowCN(int16_t x, int16_t y, uint8_t* ch);
//显示中英文混合文字
void OLED_ShowMixedCH(int16_t x, int16_t y, uint8_t* ch);
//显示图片
void OLED_DrawBMP(int16_t x0,int16_t y0,int16_t L,int16_t H,const uint8_t BMP[]);

//区域填充
void OLED_AreaFill(int16_t x0,int16_t y0,int16_t L,int16_t H, uint8_t fill_data);
//区域清除
void OLED_AreaClear(int16_t x0,int16_t y0,int16_t L,int16_t H);
//全屏切换显示
void OLED_FullyToggle(void);
//区域切换显示
void OLED_AreaToggle(int16_t x0,int16_t y0,int16_t L,int16_t H);
//全屏垂直滚动播放
void OLED_VerticalShift(void);
//全屏水平滚动播放
void OLED_HorizontalShift(uint8_t direction);
//全屏同时垂直和水平滚动播放
void OLED_VerticalAndHorizontalShift(uint8_t direction);
//屏幕内容取反显示
void OLED_DisplayMode(uint8_t mode);
//屏幕亮度调节
void OLED_IntensityControl(uint8_t intensity);


#endif



然后就是具体的界面实现了,我没有用qt写,直接用C语言写。 

  • 27
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: STM32可以通过IIC通信协议来控制OLED幕。具体步骤如下: 1. 配置IIC线:设置STM32的GPIO引IIC模式,并配置IIC线的时钟速率、地址等参数。 2. 初始化OLED幕:发送初始化命令,设置OLED幕的显示模式、亮度、对比度等参数。 3. 发送数据:将要显示的数据通过IIC线发送到OLED幕上,可以显示文字、图像等。 4. 关闭OLED幕:发送关闭命令,关闭OLED幕。 以上是控制OLED幕的基本步骤,具体实现需要根据具体的硬件和软件环境进行调整。 ### 回答2: STM32是一款广泛使用的微控制器,它的I2C(也称为IIC)总线接口可以用于控制诸如OLED幕之类的外设。在这里,本人将详细介绍如何使用STM32I2C接口来驱动OLED幕。 首先,我们需要了解OLEDI2C协议的一些基础知识。OLED幕是一种显示技术,它使用有机发光材料来发光,相对于传统的液晶显示器,它的对比度更高、响应更快、更省电。而I2C是一种串行通信协议,它可以让微控制器与其他设备(如传感器、存储器、芯片等)进行通信,它使用两根线路(SCL和SDA)进行通信。 接下来,我们将详细介绍如何在STM32使用I2C来控制OLED幕。 步骤1:准备工作 在开始之前,我们需要准备好一些材料: 1. STM32微控制器板 2. OLED显示幕 3. 电缆线 4. 电源 步骤2:建立硬件连接 将OLED显示分别连接到VCC,GND,SCL,SDA的接口上,并连接到STM32I2C接口上。 步骤3:编写代码 以下是控制OLED幕的代码 #include "oled.h" #include "i2c.h" void OLED_WriteCmd(uint8_t cmd) { uint8_t data[2] = {0x00, cmd}; HAL_I2C_Master_Transmit(&hi2c1, OLED_I2C_ADDR, data, sizeof(data), 100); } void OLED_WriteData(uint8_t data) { uint8_t _data[2] = {0x40, data}; HAL_I2C_Master_Transmit(&hi2c1, OLED_I2C_ADDR, _data, sizeof(_data), 100); } void OLED_Init() { //设置 OLED_WriteCmd(0xAE); OLED_WriteCmd(0x20); OLED_WriteCmd(0x10); OLED_WriteCmd(0xb0); OLED_WriteCmd(0xc8); OLED_WriteCmd(0x00); OLED_WriteCmd(0x10); OLED_WriteCmd(0x40); OLED_WriteCmd(0x81); OLED_WriteCmd(0xff); OLED_WriteCmd(0xa1); OLED_WriteCmd(0xa6); OLED_WriteCmd(0xa8); OLED_WriteCmd(0x3f); OLED_WriteCmd(0xd3); OLED_WriteCmd(0x00); OLED_WriteCmd(0xd5); OLED_WriteCmd(0xf0); OLED_WriteCmd(0xd9); OLED_WriteCmd(0x22); OLED_WriteCmd(0xda); OLED_WriteCmd(0x02); OLED_WriteCmd(0xdb); OLED_WriteCmd(0x49); OLED_WriteCmd(0x8d); OLED_WriteCmd(0x14); OLED_WriteCmd(0xaf); } 如上代码,OLED_Init()用来初始化OLED幕,OLED_WriteCmd()用来向OLED幕写入命令,OLED_WriteData()用来向OLED幕写入数据。在写入之前,需要使用HAL_I2C_Master_Transmit()函数将数据通过I2C协议发送到OLED幕。 步骤4:测试 完成以上步骤后,就可以通过写入数据和命令来控制OLED幕的显示,可以在代码中加上一些图形和文字等来测试OLED幕的显示效果。 综上所述,使用STM32I2C接口控制OLED幕,不仅需要熟悉I2C协议的使用,还需要掌握OLED幕的通信协议及基础知识。通过以上步骤的实践,可以更好地理解和掌握STM32I2COLED幕的控制方法。 ### 回答3: STM32是一种32位的微控制器,而OLED幕是一种基于有机发光二极管技术的显示幕。它们可以通过IIC通信协议进行连接和控制。下面将会介绍如何使用STM32控制OLED幕。 首先,我们需要知道IIC通信协议。IIC通信协议是一种串行通信协议,它使用两根线路进行通信:SDA(串行数据线)和SCL(串行时钟线)。在OLED幕中,这两根线通常被称为SDA(数据)和SCL(时钟)。STM32上有硬件IIC模块,可以方便地实现IIC通信。 接下来,我们需要确定OLED幕的IIC通信地址。不同的OLED幕可能具有不同的IIC通信地址。一般情况下,我们可以通过查看OLED幕的数据手册或者询问厂家来确定它的IIC通信地址。一旦我们知道了这个地址,我们就可以在STM32使用IIC控制器向OLED幕发送命令或数据了。 具体实现的步骤如下: 1.初始化STM32IIC控制器。这通常包括设置IIC的时钟速率、使能IIC控制器等。 2.在STM32上编写要发送的指令或数据。 3.通过IIC控制器将指令或数据从STM32发送到OLED幕。 4.在OLED幕上显示。 需要注意的是,通过IIC通信协议进行通信可能存在信号干扰等问题,因此在实现过程中需要进行一定的电路设计和软件优化。 使用STM32来控制OLED幕可以实现某些应用场景下的高端功能和复杂图像显示。例如,可以通过STM32控制OLED幕显示实时监测数据、运动状态信息等。同时,这种实现方法可以提高产品的整体性能,使之具有更高的可定制性、易操作性和卓越的用户体验。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值