1677|4

75

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

【ST NUCLEO-U5A5ZJ-Q开发板测评】5 HAL库硬件IIC通讯(SSD1306 OLED屏幕点亮) [复制链接]

前言:I2C驱动OLED屏幕是年前开始研究的,一直困于驱动函数的编写,这里卡了大约一个星期,从一开始的若干报错到bug全改好但屏幕乱码,一直到昨天晚上才用上正确的驱动函数。由于困在不会编写,中间借用了网上许多大佬的函数,也是通过这次I2C的测评,深刻体会到驱动的重要性,未来还有许多需要学习。以下为此次的开发步骤:

1.引脚选择与配置

两个I2C1的引脚分别对应板子上的D15和D14,把SCL接屏幕的SCL引脚,SDA接屏幕的SDA引脚,VCC接板子上的3V3,GND接GND

接着配置ICACHE,SMPS,RCC,时钟树(默认配置),这里偷个懒,和串口那一篇配置一模一样

来到I2C,配置如图,只用选择I2c1,其他的默认就ok

 

接着生成代码

2.代码

main函数(注意添加头文件)

#include "main.h"
#include "i2c.h"
#include "icache.h"
#include "memorymap.h"
#include "gpio.h"
#include "oled.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void SystemPower_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * [url=home.php?mod=space&uid=159083]@brief[/url] The application entry point.
  * @retval int
  */

int main(void)
{
  /* USER CODE BEGIN 1 */


  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* Configure the System Power */
  SystemPower_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_ICACHE_Init();
  /* USER CODE BEGIN 2 */


  OLED_Init();
  OLED_ShowString(1, 1, "Hello eeWorld!!!");//显示字符串

  /* USER CODE END 2 */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */

  while (1)
  {
    /* USER CODE END WHILE */
	  /* USER CODE END WHILE */

	    /* USER CODE BEGIN 3 */
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

屏幕驱动函数

/**
 * 基于硬件IIC通信的OLED驱动程序
 * API完全打包好的直接选择你的硬件IIC口即可
 *
 */
#include "main.h"
#include "i2c.h"
#include "stdio.h"
#include "oled_font.h"
#include "oled.h"

uint8_t OLED_Buffer[8][128]={0};


/**
  * @brief  OLED写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void OLED_WriteCommand(uint8_t Command)
{
	 uint8_t *pData;
	 pData = &Command;
	 HAL_I2C_Mem_Write(&Hardware_IIC_No,0x78,0x00,I2C_MEMADD_SIZE_8BIT,pData,1,100);
}

/**
  * @brief  OLED写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void OLED_WriteData(uint8_t Data)
{
	 uint8_t *pData;
	 pData = &Data;
	HAL_I2C_Mem_Write(&Hardware_IIC_No,0x78,0x40,I2C_MEMADD_SIZE_8BIT,pData,1,100);

}

/**
  * @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)
{
	uint8_t i, j;
	for (j = 0; j < 8; j++)
	{
		OLED_SetCursor(j, 0);
		for(i = 0; i < 128; i++)
		{
			OLED_WriteData(0x00);
		}
	}
}

/**
  * @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]);
	}
}

/**
  * @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 Line起始位置,范围0~3
 *  @param Colum 起始列位置,0~7
 *  @param CHN 汉字序列
 */
void OLED_ShowChinese(uint8_t Line, uint8_t Column, uint8_t CHN)
{
		uint8_t i;
		OLED_SetCursor(Line*2, Column*16);		//设置光标位置在上半部分
		for (i = 0; i < 16; i++)
		{
			OLED_WriteData(GBK[CHN][i]);			//显示上半部分内容
		}
		OLED_SetCursor((Line*2)+1,Column*16);	//设置光标位置在下半部分
		for (i = 0; i < 16; i++)
		{
			OLED_WriteData(GBK[CHN][i + 16]);		//显示下半部分内容
		}
}

/**
 *  @brief OLED显示模拟量
 *  @param Pic第几张图片,范围0~3
 *  @param Colum 起始列位置,0~7
 *
 */
void OLED_ShowPicture(uint8_t Pic)
{
	uint8_t i,j;
	Pic=Pic*8;
	for(j=0;j<8;j++)
	{
		OLED_SetCursor(j,0);//开始显示
		for (i = 0; i < 128; i++)
				{
					OLED_WriteData(Picture[j+Pic][i]);			//发送数据
				}
	}
}
/*
 * 快速显示照片
 */
void OLED_FastShowPicture(uint8_t Pic)
{
	uint8_t i,j;
	Pic=Pic*8;
	for(j=0;j<8;j++)
	{
		for (i = 0; i < 128; i++)
				{
				OLED_Buffer[j][i]=(Picture[j+Pic][i]);			//发送数据
				}
	}
}
/*
 * @brief 向缓冲区写入字符数据
 * Line 1~4;
 * Column 1~16;
 */
void OLED_FastShowChar(uint8_t Line, uint8_t Column, char Char)
{
	uint8_t i;

		for (i = 0; i < 8; i++)
		{
			OLED_Buffer[(Line- 1) * 2][(Column-1)*8+i] = OLED_F8x16[Char - ' '][i];//显示上半部分内容
		}
		for (i = 0; i < 8; i++)
		{
			OLED_Buffer[((Line ) * 2) - 1][(Column-1)*8+i]= OLED_F8x16[Char - ' '][i+8];	//显示下半部分内容
		}
}
/**
  * @brief  快速的OLED显示字符串
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串,范围:ASCII可见字符
  * @retval 无
  */
void OLED_FastShowString(uint8_t Line, uint8_t Column, char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i++)
	{
		OLED_FastShowChar(Line, Column + i, String[i]);
	}
}
/**
  * @brief  快速的OLED显示数字
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的字数字,范围:数字,变量
  * @param  Length 数字长度
  * @retval 无
  */
void OLED_FastShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)
	{
		OLED_FastShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
	}
}
/*
 * @brief 向OLED屏幕发送缓存区数据到OLED的0x40寄存器位置用以显示;
 */
void Refresh()
{
	uint8_t j;
	 uint8_t *pData;

	for(j=0;j<8;j++)
	{
		pData = &OLED_Buffer[j][0];
		OLED_SetCursor(j,0);//开始显示
		HAL_I2C_Mem_Write(&Hardware_IIC_No,0x78,0x40,I2C_MEMADD_SIZE_8BIT,pData,128,0xff);
	}
}
/**
  * @brief  OLED初始化
  * @param  无
  * @retval 无
  */
void OLED_Init(void)
{

	HAL_Delay(200);
	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清屏
}

.h文件 使用的时候要选择自己使用的I2C号码,这里我用的是I2C1

#ifndef __OLED_H
#define __OLED_H

#include "main.h"

#define Hardware_IIC_No hi2c1 /*选择自己使用的IIC号码*/



void OLED_Init(void);
void OLED_Clear(void);
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char);//显示字符
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String);//字符串
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);//数字
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length);//负数
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);//16进制数
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);//二进制数
void OLED_ShowChinese(uint8_t Line, uint8_t Column, uint8_t CHN);
void OLED_ShowPicture(uint8_t Pic);//满屏幕显示照片
void OLED_FastShowPicture(uint8_t Pic);
void OLED_FastShowChar(uint8_t Line, uint8_t Column, char Char);
void OLED_FastShowString(uint8_t Line, uint8_t Column, char *String);
void OLED_FastShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void Refresh();
void DMA_Refresh();
uint32_t OLED_Pow(uint32_t X, uint32_t Y);

#endif

把文件添加进工程,在IDE点击左上角的文件,再点击导入,会出现下面的选项,选择文件夹(因为要把你存放的OLED驱动文件的.h和.c文件添加进来),点击下一步

然后把文件放到对应的工程目录,按照图示位置添加

这里也有汉字的驱动,感兴趣的小伙伴可以用汉字取模软件试试显示汉字

最终的效果:

工程附件: I2c OLED.zip (16.03 MB, 下载次数: 0)

I2c OLED.zip

16.03 MB, 下载次数: 5

此帖出自stm32/stm8论坛

最新回复

非常感谢楼主分享的技术信息,这些技术信息值得的收藏学习   详情 回复 发表于 2024-2-28 21:21
点赞 关注(1)
 

回复
举报

6471

帖子

10

TA的资源

版主

沙发
 

硬件IIC就怕卡在各种标志位查询  

此帖出自stm32/stm8论坛

点评

是的  详情 回复 发表于 2024-2-15 21:51
 
个人签名

在爱好的道路上不断前进,在生活的迷雾中播撒光引

 

回复

75

帖子

0

TA的资源

一粒金砂(中级)

板凳
 
秦天qintian0303 发表于 2024-2-14 23:18 硬件IIC就怕卡在各种标志位查询  

是的

此帖出自stm32/stm8论坛
 
 

回复

755

帖子

4

TA的资源

纯净的硅(高级)

4
 

非常感谢楼主分享的技术信息,这些技术信息值得的收藏学习

此帖出自stm32/stm8论坛

点评

不用客气,一起学习一起进步  详情 回复 发表于 2024-2-28 23:14
 
 
 

回复

75

帖子

0

TA的资源

一粒金砂(中级)

5
 
chejm 发表于 2024-2-28 21:21 非常感谢楼主分享的技术信息,这些技术信息值得的收藏学习

不用客气,一起学习一起进步

此帖出自stm32/stm8论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表