经过昨天的学习,已经了解和初步学会配置CubeMax进行初始化配置。今天就开始下一章节的学习,关于IIC。
关键词:I2C OLED SSD1306
串行通信接口通讯方式分,可以分为两种,分别是同步和异步。按照数据的传输方向又可分为单工、半双工和全双工通信。
同步:通讯双方靠一根时钟线约定通讯速率
异步:通讯双方可以使用各自的通讯时钟,约定通讯速率进行通信
单工:单方向通信,只能收数据或者只能发数据
半双工:可以分时发收数据
全双工:可以同时发收数据,单独时钟线
IIC(Inter-Integrated Circuit)总线是一种由 PHILIPS 公司开发的两线式串行总线,用于连接
微控制器及其外围设备。它是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。
在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送,高速 IIC 总线一般可达 400kbps 以上。
I2C 总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答
信号。
传输类型:同步、半双工,带数据应答
开始信号:SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。
结束信号:SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。
应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,
表示已收到数据。CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU 接
收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为
受控单元出现故障。
这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。

查询文档可知OLED显示屏使用的是PA8,PB4,PB5 三个引脚

在STM32L071上有两个硬件I2C接口,记作I2C1 I2C3,全都支持I2C标准模式和I2C快速模式。
1.单击I2C3
2.选择I2C
3.配置引脚模式,单击GPIO Settings(默认配置也可以)

PA8: I2C3_SCL,复用开漏模式,上拉,超高速
PB4: I2C3_SDA,复用开漏模式,上拉,超高速

4. 注意配置初始化PB5引脚,这是OLED的电源控制引脚。

配置完成后生成初始化程序(时钟配置,生成代码请参考上一篇笔记)
HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c);
hi2c: 指的是I2C句柄; 初始化I2C的名称,定时值,自身地址1,地址模式(7位)或(10位)结构体参数。
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
DevAddress:器件地址
pData:发送的数据指针
Size:发送的数据数量
Timeout:超时(ms)
HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData,uint16_t Size, uint32_t Timeout);
物联网竞赛平台使用的是128*32 OLED显示屏,I2C接口,控制器是SSD1306。
竞赛会给OLED驱动程序的的资源包,在此基础上进行修改完成OLED软件设计部分。
- /* USER CODE BEGIN Prototypes */
- void OLED_Write(uint8_t ucType,uint8_t ucData);
- /* USER CODE END Prototypes */
- /* USER CODE BEGIN I2C3_Init 2 */
- HAL_Delay(100); /* 等待OLED电源稳定 */
- /* USER CODE END I2C3_Init 2 */
- /* USER CODE BEGIN 1 */
- void OLED_Write(uint8_t ucType,uint8_t ucData)
- {
- uint8_t pData[2];
-
- pData[0] = ucType;
- pData[1] = ucData;
- HAL_I2C_Master_Transmit(&hi2c3,0x78,pData,2,10);
- }
-
- /* USER CODE END 1 */
- #ifndef __OLED_H
- #define __OLED_H
-
- #include "main.h"
- #include "i2c.h"
-
-
- #define Max_Column 128
- #define Max_Row 32
-
- typedef enum
- {
- TYPE_COMMAND = 0,
- TYPE_DATA = 0x40
- }OLED_TYPE;
-
-
- void OLED_Init(void);
- void OLED_Clear(void);
- void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t size);
- void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t size);
- #endif
- #include "stm32l0xx.h" // Device header
- #include "oled.h"
- #include "font.h"
- #include "i2c.h"
- /**
- * @brief OLED设置位置
- * @param x横坐标,y纵坐标
- * @retval 无
- */
- void OLED_SetPos(uint8_t x,uint8_t y)
- {
- OLED_Write(TYPE_COMMAND,x & 0x0f);
- OLED_Write(TYPE_COMMAND,0x10 +((x &0xf0) >> 4));
- OLED_Write(TYPE_COMMAND,0xb0 + y);
- }
- /* 清除屏幕 */
- void OLED_Clear(void)
- {
- uint8_t i, j;
-
- for(i = 0; i < 4; i++)
- {
- OLED_SetPos(0, i);
- for(j = 0; j < 128; j++)
- OLED_Write(TYPE_DATA, 0);
- }
- }
- /**
- * @brief OLED屏幕初始化。
- * @param None
- * @retval None
- */
- void OLED_Init(void)
- {
- OLED_Write(TYPE_COMMAND, 0xA1); /* 段重映射, b0:0,0->0(复位值);1,0->127 */
-
- OLED_Write(TYPE_COMMAND, 0xA8); /* 复用比 */
- OLED_Write(TYPE_COMMAND, 0x1F); /* 0F~3F,16MUX~64MUX(复位值) */
-
- OLED_Write(TYPE_COMMAND, 0xC8); /* COM扫描方向, b3:0,正常模式(复位值);b3:1,反转模式 */
-
- OLED_Write(TYPE_COMMAND, 0xDA); /* COM引脚配置 */
- OLED_Write(TYPE_COMMAND, 0x00); /* D4:0,顺序;1,交替(复位值) */
-
- OLED_Write(TYPE_COMMAND, 0x8D); /* 充电泵 */
- OLED_Write(TYPE_COMMAND, 0x14); /* D2:0,禁止(复位值);1,允许 */
-
- OLED_Clear(); /* 清除屏幕 */
- OLED_Write(TYPE_COMMAND, 0xAF); /* 开启显示 */
- }
-
- /**
- * @brief OLED屏幕显示一个字符。
- * @param x 横向选择位置;
- y 纵向选择位置;
- chr 需要显示的字符;
- size 需要显示的字符大小;
- @arg 16,选择8*16点阵大小字符。其他均选择6*8点阵字符
- * @retval None
- */
- void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t size)
- {
- uint8_t c, i;
-
- c = chr - ' ';
- if(x > Max_Column - 1)
- {
- x = 0;
- y = y + 2;
- }
- if(size == 16)
- {
- OLED_SetPos(x, y);
- for(i = 0; i < 8; i++)
- OLED_Write(TYPE_DATA, g_F8X16[c * 16 + i]);
- OLED_SetPos(x, y + 1);
- for(i = 0; i < 8; i++)
- OLED_Write(TYPE_DATA, g_F8X16[c * 16 + i + 8]);
- }
- else
- {
- OLED_SetPos(x, y);
- for(i = 0; i < 6; i++)
- {
- OLED_Write(TYPE_DATA, g_F6x8[c][i]);
- }
- }
- }
-
- /**
- * @brief OLED屏幕显示一个字符串。
- * @param x 横向选择位置;0
- y 纵向选择位置;
- chr 需要显示的字符串;
- size 需要显示的字符大小;
- * @retval None
- */
- void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *chr, uint8_t size)
- {
- uint8_t j = 0;
-
- while(chr[j] != '\0')
- {
- OLED_ShowChar(x, y, chr[j], size);
- x += 8;
- if(x > 120)
- {
- x = 0;
- y += 2;
- }
- j++;
- }
- }
- 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_I2C3_Init();
- MX_USART2_UART_Init();
- /* USER CODE BEGIN 2 */
- OLED_Init();
- sprintf((char*)ucBufs, "HELLO!");
- OLED_ShowString(0,0,ucBufs,16);
- /* USER CODE END 2 */
-
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
-
- HAL_Delay(500);
- HAL_GPIO_TogglePin(LD5);
- /* USER CODE END WHILE */
-
- /* USER CODE BEGIN 3 */
- }
- /* USER CODE END 3 */
- }

uint8_t ucSec,ucMin,ucHour; /* 秒计时 分计时 小时 */
- void SysTick_Handler(void)
- {
- /* USER CODE BEGIN SysTick_IRQn 0 */
-
- /* USER CODE END SysTick_IRQn 0 */
- HAL_IncTick();
- /* USER CODE BEGIN SysTick_IRQn 1 */
- usDly++;
- if(++usTms == 1000) /* 1s到 */
- {
- usTms = 0;
- ucSec++; /* 秒加1 */
- }
- if(ucSec == 60)
- {
- ucSec = 0;
- ucMin++;
- }
- if(ucMin == 60)
- {
- ucMin = 0;
- ucHour ++;
- if(ucHour==24)
- ucHour=0;
- }
-
- /* USER CODE END SysTick_IRQn 1 */
- }
- 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_I2C3_Init();
- MX_USART2_UART_Init();
- /* USER CODE BEGIN 2 */
- OLED_Init();
-
- /* USER CODE END 2 */
-
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
-
- HAL_Delay(500);
- HAL_GPIO_TogglePin(LD5);
- sprintf((char*)ucBuf, "TIME: %02u:%02u:%02u", ucHour, ucMin, ucSec);
- OLED_ShowString(0, 0, ucBuf, 16);
- /* USER CODE END WHILE */
-
- /* USER CODE BEGIN 3 */
- }
- /* USER CODE END 3 */
- }
OLED显示时间,LD5闪烁
