• 【蓝桥杯物联网赛项学习日志】Day3 关于IIC


    经过昨天的学习,已经了解和初步学会配置CubeMax进行初始化配置。今天就开始下一章节的学习,关于IIC

    关键词:I2C OLED SSD1306

    理论基础

    串行通信接口通讯方式分,可以分为两种,分别是同步和异步。按照数据的传输方向又可分为单工、半双工和全双工通信。
    同步:通讯双方靠一根时钟线约定通讯速率
    异步:通讯双方可以使用各自的通讯时钟,约定通讯速率进行通信
    单工:单方向通信,只能收数据或者只能发数据
    半双工:可以分时发收数据
    全双工:可以同时发收数据,单独时钟线


    IIC 简介


    IIC(Inter-Integrated Circuit)总线是一种由 PHILIPS 公司开发的两线式串行总线,用于连接
    微控制器及其外围设备。它是由数据线 SDA 时钟 SCL 构成的串行总线,可发送和接收数据。
    在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送,高速 IIC 总线一般可达 400kbps 以上。
    I2C 总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答
    信号。
    传输类型同步、半双工,带数据应答
    开始信号:SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。
    结束信号:SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。
    应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,
    表示已收到数据。CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU 接
    收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为
    受控单元出现故障。
    这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。

     GPIO引脚配置

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

     在STM32L071上有两个硬件I2C接口,记作I2C1 I2C3,全都支持I2C标准模式和I2C快速模式。

     在CubeMax中配置iic3

    1.单击I2C3
    2.选择I2C
    3.配置引脚模式,单击GPIO Settings(默认配置也可以)

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

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

    配置完成后生成初始化程序(时钟配置,生成代码请参考上一篇笔记)

    I2C库函数

    初始化函数:

    HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c);

    hi2c:  指的是I2C句柄; 初始化I2C的名称,定时值,自身地址1,地址模式(7位)或(10位)结构体参数。

    主设备发送:

    I2C数据传输此处采用的是阻塞式数据传输。阻塞式数据传输使用方便,且I2C接口传输速率不高,一般传输数据量也不大,阻塞式传输是常用的数据传输模式。

    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);

    OLED软件设计与实现:

    物联网竞赛平台使用的是128*32 OLED显示屏,I2C接口,控制器是SSD1306。
    竞赛会给OLED驱动程序的的资源包,在此基础上进行修改完成OLED软件设计部分。

    底层函数

    1.在i2c.h中添加以下函数声明

    1. /* USER CODE BEGIN Prototypes */
    2. void OLED_Write(uint8_t ucType,uint8_t ucData);
    3. /* USER CODE END Prototypes */

    2.在i2c.c中MX_I2C3_Init()后面部分添加延时

    1. /* USER CODE BEGIN I2C3_Init 2 */
    2. HAL_Delay(100); /* 等待OLED电源稳定 */
    3. /* USER CODE END I2C3_Init 2 */

    3.在i2c.c中添OLED_Write();用来写入OLED数据

    1. /* USER CODE BEGIN 1 */
    2. void OLED_Write(uint8_t ucType,uint8_t ucData)
    3. {
    4. uint8_t pData[2];
    5. pData[0] = ucType;
    6. pData[1] = ucData;
    7. HAL_I2C_Master_Transmit(&hi2c3,0x78,pData,2,10);
    8. }
    9. /* USER CODE END 1 */

    高层函数

    添加头文件 oled.h

    1. #ifndef __OLED_H
    2. #define __OLED_H
    3. #include "main.h"
    4. #include "i2c.h"
    5. #define Max_Column 128
    6. #define Max_Row 32
    7. typedef enum
    8. {
    9. TYPE_COMMAND = 0,
    10. TYPE_DATA = 0x40
    11. }OLED_TYPE;
    12. void OLED_Init(void);
    13. void OLED_Clear(void);
    14. void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t size);
    15. void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t size);
    16. #endif

    添加.C文件

    1. #include "stm32l0xx.h" // Device header
    2. #include "oled.h"
    3. #include "font.h"
    4. #include "i2c.h"
    5. /**
    6. * @brief OLED设置位置
    7. * @param x横坐标,y纵坐标
    8. * @retval 无
    9. */
    10. void OLED_SetPos(uint8_t x,uint8_t y)
    11. {
    12. OLED_Write(TYPE_COMMAND,x & 0x0f);
    13. OLED_Write(TYPE_COMMAND,0x10 +((x &0xf0) >> 4));
    14. OLED_Write(TYPE_COMMAND,0xb0 + y);
    15. }
    16. /* 清除屏幕 */
    17. void OLED_Clear(void)
    18. {
    19. uint8_t i, j;
    20. for(i = 0; i < 4; i++)
    21. {
    22. OLED_SetPos(0, i);
    23. for(j = 0; j < 128; j++)
    24. OLED_Write(TYPE_DATA, 0);
    25. }
    26. }
    27. /**
    28. * @brief OLED屏幕初始化。
    29. * @param None
    30. * @retval None
    31. */
    32. void OLED_Init(void)
    33. {
    34. OLED_Write(TYPE_COMMAND, 0xA1); /* 段重映射, b0:0,0->0(复位值);1,0->127 */
    35. OLED_Write(TYPE_COMMAND, 0xA8); /* 复用比 */
    36. OLED_Write(TYPE_COMMAND, 0x1F); /* 0F~3F,16MUX~64MUX(复位值) */
    37. OLED_Write(TYPE_COMMAND, 0xC8); /* COM扫描方向, b3:0,正常模式(复位值);b3:1,反转模式 */
    38. OLED_Write(TYPE_COMMAND, 0xDA); /* COM引脚配置 */
    39. OLED_Write(TYPE_COMMAND, 0x00); /* D4:0,顺序;1,交替(复位值) */
    40. OLED_Write(TYPE_COMMAND, 0x8D); /* 充电泵 */
    41. OLED_Write(TYPE_COMMAND, 0x14); /* D2:0,禁止(复位值);1,允许 */
    42. OLED_Clear(); /* 清除屏幕 */
    43. OLED_Write(TYPE_COMMAND, 0xAF); /* 开启显示 */
    44. }
    45. /**
    46. * @brief OLED屏幕显示一个字符。
    47. * @param x 横向选择位置;
    48. y 纵向选择位置;
    49. chr 需要显示的字符;
    50. size 需要显示的字符大小;
    51. @arg 16,选择8*16点阵大小字符。其他均选择6*8点阵字符
    52. * @retval None
    53. */
    54. void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t size)
    55. {
    56. uint8_t c, i;
    57. c = chr - ' ';
    58. if(x > Max_Column - 1)
    59. {
    60. x = 0;
    61. y = y + 2;
    62. }
    63. if(size == 16)
    64. {
    65. OLED_SetPos(x, y);
    66. for(i = 0; i < 8; i++)
    67. OLED_Write(TYPE_DATA, g_F8X16[c * 16 + i]);
    68. OLED_SetPos(x, y + 1);
    69. for(i = 0; i < 8; i++)
    70. OLED_Write(TYPE_DATA, g_F8X16[c * 16 + i + 8]);
    71. }
    72. else
    73. {
    74. OLED_SetPos(x, y);
    75. for(i = 0; i < 6; i++)
    76. {
    77. OLED_Write(TYPE_DATA, g_F6x8[c][i]);
    78. }
    79. }
    80. }
    81. /**
    82. * @brief OLED屏幕显示一个字符串。
    83. * @param x 横向选择位置;0
    84. y 纵向选择位置;
    85. chr 需要显示的字符串;
    86. size 需要显示的字符大小;
    87. * @retval None
    88. */
    89. void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *chr, uint8_t size)
    90. {
    91. uint8_t j = 0;
    92. while(chr[j] != '\0')
    93. {
    94. OLED_ShowChar(x, y, chr[j], size);
    95. x += 8;
    96. if(x > 120)
    97. {
    98. x = 0;
    99. y += 2;
    100. }
    101. j++;
    102. }
    103. }

    主函数

    1. int main(void)
    2. {
    3. /* USER CODE BEGIN 1 */
    4. /* USER CODE END 1 */
    5. /* MCU Configuration--------------------------------------------------------*/
    6. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    7. HAL_Init();
    8. /* USER CODE BEGIN Init */
    9. /* USER CODE END Init */
    10. /* Configure the system clock */
    11. SystemClock_Config();
    12. /* USER CODE BEGIN SysInit */
    13. /* USER CODE END SysInit */
    14. /* Initialize all configured peripherals */
    15. MX_GPIO_Init();
    16. MX_I2C3_Init();
    17. MX_USART2_UART_Init();
    18. /* USER CODE BEGIN 2 */
    19. OLED_Init();
    20. sprintf((char*)ucBufs, "HELLO!");
    21. OLED_ShowString(0,0,ucBufs,16);
    22. /* USER CODE END 2 */
    23. /* Infinite loop */
    24. /* USER CODE BEGIN WHILE */
    25. while (1)
    26. {
    27. HAL_Delay(500);
    28. HAL_GPIO_TogglePin(LD5);
    29. /* USER CODE END WHILE */
    30. /* USER CODE BEGIN 3 */
    31. }
    32. /* USER CODE END 3 */
    33. }

    实验现象

     写一个简单的时钟

    在主函数中添加三个时间变量

    uint8_t ucSec,ucMin,ucHour;                 	/* 秒计时 分计时 小时 */

    在系统定时器,void SysTick_Handler(void)中添加如下代码

    1. void SysTick_Handler(void)
    2. {
    3. /* USER CODE BEGIN SysTick_IRQn 0 */
    4. /* USER CODE END SysTick_IRQn 0 */
    5. HAL_IncTick();
    6. /* USER CODE BEGIN SysTick_IRQn 1 */
    7. usDly++;
    8. if(++usTms == 1000) /* 1s到 */
    9. {
    10. usTms = 0;
    11. ucSec++; /* 秒加1 */
    12. }
    13. if(ucSec == 60)
    14. {
    15. ucSec = 0;
    16. ucMin++;
    17. }
    18. if(ucMin == 60)
    19. {
    20. ucMin = 0;
    21. ucHour ++;
    22. if(ucHour==24)
    23. ucHour=0;
    24. }
    25. /* USER CODE END SysTick_IRQn 1 */
    26. }

    在主函数中添加以下代码

    1. int main(void)
    2. {
    3. /* USER CODE BEGIN 1 */
    4. /* USER CODE END 1 */
    5. /* MCU Configuration--------------------------------------------------------*/
    6. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    7. HAL_Init();
    8. /* USER CODE BEGIN Init */
    9. /* USER CODE END Init */
    10. /* Configure the system clock */
    11. SystemClock_Config();
    12. /* USER CODE BEGIN SysInit */
    13. /* USER CODE END SysInit */
    14. /* Initialize all configured peripherals */
    15. MX_GPIO_Init();
    16. MX_I2C3_Init();
    17. MX_USART2_UART_Init();
    18. /* USER CODE BEGIN 2 */
    19. OLED_Init();
    20. /* USER CODE END 2 */
    21. /* Infinite loop */
    22. /* USER CODE BEGIN WHILE */
    23. while (1)
    24. {
    25. HAL_Delay(500);
    26. HAL_GPIO_TogglePin(LD5);
    27. sprintf((char*)ucBuf, "TIME: %02u:%02u:%02u", ucHour, ucMin, ucSec);
    28. OLED_ShowString(0, 0, ucBuf, 16);
    29. /* USER CODE END WHILE */
    30. /* USER CODE BEGIN 3 */
    31. }
    32. /* USER CODE END 3 */
    33. }

    实验现象

    OLED显示时间,LD5闪烁

  • 相关阅读:
    ASP.NET Core 6.0 使用 资源过滤器和行为过滤器
    Error creating bean with name 'xImpl': Unsatisfied dependency expressed through field 'baseMapper'
    Error occurred while trying to proxy request项目突然起不来了
    pytest学习和使用10-Pytest中的测试用例如何跳过执行?
    Macs Fan Control Pro:掌握您的Mac风扇,提升散热效率
    跨域问题WebMvcConfigurer
    设计模式—结构型模式之装饰器模式
    redis的配置文件
    计算机视觉: 基于隐式BRDF自编码器的文生三维技术
    python获取pdf文件大小
  • 原文地址:https://blog.csdn.net/peng_papa/article/details/127756081