目录
一、IIC协议
IIC全称Inter-Integrated Circuit (集成电路总线),由PHILIPS公司在80年代开发的两线式串行总线,用于连接微控制器及其外围设备。IIC属于半双工同步通信方式。
二、IIC构成
IIC串行总线有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。两条线都接上拉电阻,以确保总线空闲时刻为高电平,其中时钟信号是由主控器件产生。IIC总线支持多设备连接,允许多主机存在,对于并联在一条总线上的每个IIC设备都有唯一的地址(即靠地址来区分每一个IIC设备)。
三、IIC特点
简单性和有效性:由于接口直接在组件之上,因此IIC总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。总线的长度可高达25英尺,并且能够以10Kbps的最大传输速率支持40个组件
多主控(multimastering):其中任何能够进行发送和接收的设备都可以成为主总线。一个主控能够控制信号的传输和时钟频率。当然,在任何时间点上只能有一个主控。
四、IIC传输数据过程的三种信号
分别为:起始信号、终止信号和应答信号。
起始信号
时序图
终止信号
时序图
应答信号
主机每发送一个字节(8个bit),就在第9个时钟脉冲期间释放数据线(SDA),由从机反馈一个应答信号。应答信号(SDA)为低电平时,规定为有效应答位(ACK,简称应答位),表示从机成功地接收了该字节。应答信号(SDA)为高电平时,规定为非应答位(NACK),一般表示从机接收该字节没有成功。
时序图
五、IIC发送/接收一个字节数据
六、OLED屏
OLED显示屏是一个128列*64行的点阵,垂直方向由8个PAGE控制,每个PAGE控制8个点阵,8个点阵8个位。
一个PAGE由8位二进制组成 低位在上,高位在下。
例如:写入数据0xaa(aa转成8位二进制后,位为1的点阵亮灯)
1.选择PAGE(在垂直方向的哪个位置显示):
命令为0xBx(例如0xB2 则选择的是在page2处显示)
共8个PAGE,每个PAGE8位,所以垂直方向8*8=64位。
2.选择列(在水平方向的哪个位置显示):
命令为0x1x1(x1高4位),0x0x2(x2低4位),x1、x2合起来构成8位二进制控制列位置。
例如:0x10、0x01构成0000 0001 则选择的是第一列
3.三种地址模式
模式选择(2行代码顺序不能颠倒)
Oled_Write_Cmd(0x20); //进入寻址方式选择
Oled_Write_Cmd(0x02); //02是页寻址、00是水平寻址、01是垂直寻址模式
1.页地址模式(PAGE 与所在的所以的COL列构成一页)
2.水平地址模式
3.垂直地址模式
七、用到的函数
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c,
uint16_t DevAddress,
uint16_t MemAddress,
uint16_t MemAddSize,
uint8_t *pData,
uint16_t Size,
uint32_t Timeout)
参数一:I2C_HandleTypeDef *hi2c,I2C设备句柄
参数二:uint16_t DevAddress,IIC设备地址
参数三:uint16_t MemAddress,目标器件的目标寄存器地址
参数四:uint16_t MemAddSize,目标器件内部寄存器地址数据长度
参数五:uint8_t *pData,待写的数据首地址
参数六:uint16_t Size,待写的数据长度
参数七:uint32_t Timeout,超时时间
返回值:HAL_StatusTypeDef,HAL状态(OK,busy,ERROR,TIMEOUT)
例如
写入命令
void Oled_Write_Cmd(uint8_t dataCmd)
{
HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x00, I2C_MEMADD_SIZE_8BIT, &dataCmd, 1, 0xff);
}
写入数据
void Oled_Write_Data(uint8_t dataData)
{
HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x40, I2C_MEMADD_SIZE_8BIT,&dataData, 1, 0xff);
}
八、配置
1.RCC
2.SYS
3.I2C1
4.接线
查看芯片SCL与SDA引脚在哪,然后与oled屏上对应的SCL与SDA连接。
九、main代码详细注释(oled显示字)
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "gpio.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 */
void Oled_Write_Cmd(uint8_t dataCmd)//写入命令===================================
{
HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x00, I2C_MEMADD_SIZE_8BIT,&dataCmd, 1, 0xff);
//&hi2c1句柄, 0x78IIC设备地址, 0x00写入命令
//I2C_MEMADD_SIZE_8BIT 后库提供的宏定义内部内存地址大小8位
//&dataCmd待写数据首地址, 1待写的数据长度, 0xff超时时间
}
void Oled_Write_Data(uint8_t dataData)//写入数据
{
HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x40, I2C_MEMADD_SIZE_8BIT,&dataData, 1, 0xff);
//0x40写入数据
}
void Oled_Init()//OLED初始化
{
Oled_Write_Cmd(0xAE);//--display off
Oled_Write_Cmd(0x00);//---set low column address
Oled_Write_Cmd(0x10);//---set high column address
Oled_Write_Cmd(0x40);//--set start line address
Oled_Write_Cmd(0xB0);//--set page address
Oled_Write_Cmd(0x81); // contract control
Oled_Write_Cmd(0xFF);//--128
Oled_Write_Cmd(0xA1);//set segment remap
Oled_Write_Cmd(0xA6);//--normal / reverse
Oled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)
Oled_Write_Cmd(0x3F);//--1/32 duty
Oled_Write_Cmd(0xC8);//Com scan direction
Oled_Write_Cmd(0xD3);//-set display offset
Oled_Write_Cmd(0x00);//
Oled_Write_Cmd(0xD5);//set osc division
Oled_Write_Cmd(0x80);//
Oled_Write_Cmd(0xD8);//set area color mode off
Oled_Write_Cmd(0x05);//
Oled_Write_Cmd(0xD9);//Set Pre-Charge Period
Oled_Write_Cmd(0xF1);//
Oled_Write_Cmd(0xDA);//set com pin configuartion
Oled_Write_Cmd(0x12);//
Oled_Write_Cmd(0xDB);//set Vcomh
Oled_Write_Cmd(0x30);//
Oled_Write_Cmd(0x8D);//set charge pump enable
Oled_Write_Cmd(0x14);//
Oled_Write_Cmd(0xAF);//--turn on oled panel
}
void Oled_Screen_Clear(void)//清屏
{
int i,j;//选择char会导致雪花 因为-128—127导致j<128越界
for(i=0;i<8;i++){
Oled_Write_Cmd(0xB0 + i); //选择PAGE的位置
Oled_Write_Cmd(0x00); //选择列的位值低四位
Oled_Write_Cmd(0x10);//高四位
for(j = 0;j < 128; j++){//
Oled_Write_Data(0); //写入字符0
}
}
}
//上字的点阵
char s1[16] = {0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00};
char s2[16] = {0x40,0x40,0x40,0x40,0x40,0x40,0x7F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00};
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief 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();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
int i;//==========================================================================
Oled_Screen_Clear();//清屏
Oled_Init();//oled初始化
Oled_Write_Cmd(0x20);//选择寻址方式
Oled_Write_Cmd(0x02);//02是页寻址、00是水平寻址、01是垂直寻址模式
Oled_Write_Cmd(0xB0);//选择一个PAGE0选择第0页
Oled_Write_Cmd(0x00);//低四位
Oled_Write_Cmd(0x10);//高四位
//显示字
for(i=0;i<16;i++){
Oled_Write_Data(s1[i]);
}
Oled_Write_Cmd(0xB1);//选择一个PAGE1选择第1页
Oled_Write_Cmd(0x00);//低四位
Oled_Write_Cmd(0x10);//高四位
for(i=0;i<16;i++){
Oled_Write_Data(s2[i]);
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */