• 基于stm32f103系列的简单软件I2C和硬件I2C通讯


           这篇文章主要分为三个部分来阐述,分别是I2C的基本知识,软件I2C通讯,硬件I2C通讯。I2C的基本知识这一块,部分讲解以及图表来自b站江科大的up,很感谢这位up,大家可以关注一波。操作实现的时候,up使用的是标准库讲解,我是用是HAL库,但都可以实现。

    一、I2C的基本知识

    1.基本的三种通讯方式

    学过通讯的同学都知道,基本的通讯方式有单工,半双工,全双工。那么这三种工作方式有啥区别吗?我给大家举个例子:

          单工通讯就好比象棋里面的“卒”,卒有啥特性?没错,一条路走到黑,不走回头路,说白了,这种通讯方式就是“有去无回”。我只知道我可以通过这条线发过去,但是我没法通过这条线反馈信息。

          半双工通讯就好比你在狭窄的山路上开车,你可以开入山里面,也可以开出山里面,但是山路狭窄,在同一时刻同一路段只能允许一辆车通过。所以你你要想开入山里面,就必须等到出山的车先开出来;要想开出山里面,就必须让开入山里面的车先开进去。说白了,就是说,你可以出入山里,但是一定要确保你在开车的过程中,山路上没有相反方向的车堵住你。所以半双工在同一时刻,只能有一个方向的通讯。等到这个方向通讯完成,你才可以选择下一次通讯的方向。

          全双工通讯就好比我们现在的公路,随时随地,有来有回,去的车道完全不对回来的车道有影响,大家各走各的。

          这三种通道各自有各自的优劣与使用场景,感兴趣的同学可以自己百度百度。我们今天要说的就是I2C就是半双工通讯。

    2.I2C通讯规则

    起始条件:在SCL高电平的时候,SDA由高电平变为低电平

    终止条件:在SCL高电平的时候,SDA由高电平变为低电平

    发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节

    接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA,就是要让SDA=1

    发送应答:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答。

    接收应答:主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)。

    请大家看清楚接受和发送的对象是谁,不要混淆了。

    3.硬件电路

    第一张图告诉我们,所有的从机设备都和主机的时序一样,因此属于同步时序。主机的SDA连接着从机的SDA,这是一张典型的一主多从模型图。主机想要和谁通讯就,只需要输入对应的从机地址就行了。图中的两个R是为了保护电路的,具体咋保护的呢?

    按道理说,只要我们按照正常的时序,就可以实现主机的SDA输出,从机的SDA输入;从机的SDA输出,主机的SDA输入,这没问题。但是如果时序没有协调好,有可能会出现一方的SDA输出1,一方的SDA输出0,这样就相当于高低电平直接接在一起,不就短路了吗?

    因此I2C的设计规定,禁止所有的设备(无论是主机还是从此,内部的SDA,SCL电路都如第二张图所示)输出强上拉的高电平,采用外置弱上拉的电阻加开路输出的电路结构,这样就不用担心短路的问题了,如上图所示,在输入时,无论是SCL还是SDA的电路,输入高低电平都无影响。但是在输出是,因为SDA和SCL都是开漏模式,因此当输出低电平时,直接导通;输出高电平时,被截断处于浮空状态。但是浮空状态不稳定容易受到干扰,因此有外接一个电阻R,相当于让浮空的引脚与电阻相连,完成弱上拉,变相的输出高电平。

    下面我以主机SDA为例,给大家画一下等效图

    无论是主机还是从机,SDA和SCL都可以这样简化。如果你想了解为什么可以这样的简化,,你可以去b站上自己学一下场效应管的知识,再结合第一第二张图片的电路,你就懂了,这里我就不细说效应管的知识了。

    4.三种基本的I2C时序通讯

    指定地址写:指定地址写入一个字节

    如果想要写入多个字节,在终止条件前面的应答位应答,并且再次重复主机发送字节写内容及应答即可,直到不想发送,然后在写入终止条件。

    当前地址读

    如果想要读入多个字节,在终止条件前面的应答位应答,并且再次重复从机发送字节写内容及应答即可,直到不想发送,然后在写入终止条件。

    当前地址指针:就是说这个指针目前指向那个寄存器。当我们写的时候,会在该指针的位置写入,写完后自动加1,向下移动;当我们读的时候,会在该指针的位置读出,读完后自动加1,向下移动。

    指定地址读:相当于把指定地址写的终止条件去掉,然后和当前地址读结合起来。比如说我在指定地址写的时候,选好了从机的8位储存器地址,那么当前地址指针就要指向这里,我们就在这里写,接着应答,然后开始执行当前地址读的序列,那么就可以再当前的位置(也就是我们指定的写入地址的位置)读取出来数据。

    二、软件I2C通讯

    1.前提准备

       这里还是依据51单片机的I2C模拟通讯来进行改编,不熟悉的话,可以回看一下51模拟I2C通讯实现OLED显示图片

    2.代码部分(运行出来是一条蛇)

    这里我们想要用PB7端口模拟SDA,PB6端口模拟SCL,同时根据第一部分介绍,我们应该知道SDA,SCL都应该是开漏模式,所以我们的PB7端口和PB6端口都会配置成开漏模式。

    1. #include "main.h"
    2. #include "gpio.h"
    3. /* Private includes ----------------------------------------------------------*/
    4. /* USER CODE BEGIN Includes */
    5. #define OLED_I2C_SCL_CLK() __HAL_RCC_GPIOB_CLK_ENABLE()
    6. #define OLED_I2C_SCL_GPIO GPIOB
    7. #define OLED_I2C_SCL_PIN GPIO_PIN_6
    8. #define OLED_I2C_SDA_CLK() __HAL_RCC_GPIOB_CLK_ENABLE()
    9. #define OLED_I2C_SDA_GPIO GPIOB
    10. #define OLED_I2C_SDA_PIN GPIO_PIN_7
    11. #define OLED_SCL_RESET() HAL_GPIO_WritePin(OLED_I2C_SCL_GPIO,OLED_I2C_SCL_PIN,GPIO_PIN_RESET) //SCL
    12. #define OLED_SCL_SET() HAL_GPIO_WritePin(OLED_I2C_SCL_GPIO,OLED_I2C_SCL_PIN,GPIO_PIN_SET)
    13. #define OLED_SDA_RESET() HAL_GPIO_WritePin(OLED_I2C_SDA_GPIO,OLED_I2C_SDA_PIN,GPIO_PIN_RESET) //SDA
    14. #define OLED_SDA_SET() HAL_GPIO_WritePin(OLED_I2C_SDA_GPIO,OLED_I2C_SDA_PIN,GPIO_PIN_SET)
    15. /* USER CODE END Includes */
    16. /* Private typedef -----------------------------------------------------------*/
    17. /* USER CODE BEGIN PTD */
    18. void MyI2C_Start(void)//起始条件
    19. {
    20. OLED_SCL_SET();
    21. OLED_SDA_SET();
    22. OLED_SDA_RESET();
    23. OLED_SCL_RESET();
    24. }
    25. void MyI2C_Stop(void)//终止条件
    26. {
    27. OLED_SCL_SET() ;
    28. OLED_SDA_RESET();
    29. OLED_SDA_SET();
    30. }
    31. void MyI2C_SendByte(uint8_t Byte)//发送一个字节
    32. {
    33. uint8_t i;
    34. uint8_t m,da;
    35. da = Byte;
    36. OLED_SCL_RESET();
    37. for(i = 0; i < 8; i++)
    38. {
    39. m = da;
    40. m = m&0x80;
    41. if(m == 0x80)
    42. OLED_SDA_SET();
    43. else
    44. OLED_SDA_RESET();
    45. da = da << 1;
    46. OLED_SCL_SET();
    47. OLED_SCL_RESET();
    48. }
    49. }
    50. char MyI2C_SendAck()//发送应答
    51. {
    52. char flag;
    53. OLED_SDA_SET();//释放SDA
    54. OLED_SCL_SET();
    55. flag= HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7);
    56. OLED_SCL_RESET();
    57. return flag;
    58. }
    59. /* USER CODE END PTD */
    60. /* Private define ------------------------------------------------------------*/
    61. /* USER CODE BEGIN PD */
    62. void Oled_Write_Cmd(char dataCmd)//发送一个写命令字节
    63. {
    64. MyI2C_Start();
    65. MyI2C_SendByte(0x78);
    66. MyI2C_SendAck();
    67. MyI2C_SendByte(0x00);
    68. MyI2C_SendAck();
    69. MyI2C_SendByte(dataCmd);
    70. MyI2C_SendAck();
    71. MyI2C_Stop();
    72. }
    73. void Oled_Write_Data(char dataData)//发送一个写数据字节
    74. {
    75. MyI2C_Start();//起始条件
    76. MyI2C_SendByte(0x78);//发送从机地址
    77. MyI2C_SendAck();//应答
    78. MyI2C_SendByte(0x40);//开启写入命令0x00或写入数据0x40
    79. MyI2C_SendAck(); //应答
    80. MyI2C_SendByte(dataData);//写入具体的命令或者数据
    81. MyI2C_SendAck();
    82. MyI2C_Stop();//IIC结束
    83. }
    84. void OLED_Init(void)
    85. {
    86. Oled_Write_Cmd(0xAE);//--display off
    87. Oled_Write_Cmd(0x00);//---set low column address
    88. Oled_Write_Cmd(0x10);//---set high column address
    89. Oled_Write_Cmd(0x40);//--set start line address
    90. Oled_Write_Cmd(0xB0);//--set page address
    91. Oled_Write_Cmd(0x81); // contract control
    92. Oled_Write_Cmd(0xFF);//--128
    93. Oled_Write_Cmd(0xA1);//set segment remap
    94. Oled_Write_Cmd(0xA6);//--normal / reverse
    95. Oled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)
    96. Oled_Write_Cmd(0x3F);//--1/32 duty
    97. Oled_Write_Cmd(0xC8);//Com scan direction
    98. Oled_Write_Cmd(0xD3);//-set display offset
    99. Oled_Write_Cmd(0x00);//
    100. Oled_Write_Cmd(0xD5);//set osc division
    101. Oled_Write_Cmd(0x80);//
    102. Oled_Write_Cmd(0xD8);//set area color mode off
    103. Oled_Write_Cmd(0x05);//
    104. Oled_Write_Cmd(0xD9);//Set Pre-Charge Period
    105. Oled_Write_Cmd(0xF1);//
    106. Oled_Write_Cmd(0xDA);//set com pin configuartion
    107. Oled_Write_Cmd(0x12);//
    108. Oled_Write_Cmd(0xDB);//set Vcomh
    109. Oled_Write_Cmd(0x30);//
    110. Oled_Write_Cmd(0x8D);//set charge pump enable
    111. Oled_Write_Cmd(0x14);//
    112. Oled_Write_Cmd(0xAF);//--turn on oled panel
    113. }
    114. /* USER CODE END PD */
    115. /* Private macro -------------------------------------------------------------*/
    116. /* USER CODE BEGIN PM */
    117. void Oled_Screen_Clear(void){
    118. unsigned char i,n;
    119. for(i=0;i<8;i++){
    120. Oled_Write_Cmd(0xb0+i);
    121. Oled_Write_Cmd(0x00);
    122. Oled_Write_Cmd(0x10);
    123. for(n=0;n<128;n++)
    124. Oled_Write_Data(0x00);
    125. }
    126. }
    127. unsigned char bmpImager[] = {
    128. /*-- 调入了一幅图像:D:\无标题.bmp --*/
    129. /*-- 宽度x高度=128x64 --128x8x8*/
    130. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    131. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    132. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    133. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    134. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    135. 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
    136. 0xC0,0xC0,0xC0,0x40,0x40,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x80,0x80,0x80,0x80,
    137. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    138. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    139. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    140. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    141. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    142. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xE0,0xF0,0xB8,
    143. 0x8C,0x8E,0x86,0x03,0x03,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    144. 0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x61,0xE1,0xF1,
    145. 0xE1,0x63,0x03,0x06,0x0E,0x0C,0x18,0x70,0xE0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,
    146. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    147. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    148. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    149. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    150. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x81,0x81,
    151. 0x81,0x81,0x81,0xC1,0xC3,0x67,0x7E,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    152. 0x00,0x00,0x00,0x03,0x07,0x07,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    153. 0x00,0x00,0x80,0x00,0x00,0x00,0x00,0xC0,0xF1,0x7F,0x1F,0x00,0x00,0x00,0x00,0x00,
    154. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    155. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    156. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    157. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    158. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x07,0x0F,0x3D,
    159. 0x71,0xE1,0xC1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x10,0xF0,0xF0,
    160. 0xB0,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0xF0,0xF0,0xB3,0x33,0x36,0x36,0x16,0x1E,
    161. 0x1E,0x1B,0x0F,0x0C,0x06,0x07,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    162. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    163. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    164. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    165. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    166. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    167. 0x00,0x01,0x03,0x9F,0xFC,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xFF,
    168. 0xFF,0x66,0x66,0x46,0x46,0x46,0x46,0x46,0x62,0x63,0x67,0x7F,0xFC,0xF0,0x80,0x00,
    169. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    170. 0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
    171. 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0xC0,0xC0,
    172. 0xC0,0xC0,0xC0,0x60,0x60,0x60,0xE0,0xA0,0x30,0x30,0x30,0x10,0x18,0x98,0xF8,0xFC,
    173. 0x6C,0x0C,0x04,0x06,0x06,0x06,0x62,0xF3,0xF3,0xDB,0xDB,0xDB,0xDB,0xF3,0x73,0x03,
    174. 0x03,0x0F,0x1F,0x3F,0x33,0x63,0x62,0x66,0x66,0x36,0x3E,0x1E,0x06,0x06,0x06,0x06,
    175. 0x06,0x3B,0x7B,0x6F,0xCD,0xCC,0xC4,0xCC,0xCC,0x6C,0x78,0x38,0x80,0xE0,0x7C,0x3F,
    176. 0x0F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x08,0xEC,0xFF,0x7F,0x00,
    177. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    178. 0x00,0x00,0x00,0x00,0x01,0x01,0x03,0x03,0x03,0x07,0x07,0x05,0x0D,0x0D,0x09,0x19,
    179. 0x19,0x19,0x31,0x31,0x31,0x61,0x61,0x61,0x61,0x41,0xC1,0xC0,0xC0,0xC0,0xC0,0xC0,
    180. 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC1,0xC1,0x43,0x63,0x63,0x63,0x31,0x31,0x30,
    181. 0x10,0x18,0x18,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,
    182. 0x0C,0x0C,0x18,0x18,0x18,0x30,0x30,0x30,0x60,0x60,0x60,0x60,0x60,0xE0,0xF0,0xF0,
    183. 0xF0,0xF0,0xF0,0xF0,0xD8,0xD8,0xD8,0xDC,0xFC,0xF6,0xF6,0xE3,0xE3,0xE3,0x63,0x63,
    184. 0x63,0x62,0x66,0x36,0x36,0x36,0x1E,0x1E,0x0E,0x0E,0x06,0x07,0x03,0x00,0x00,0x00,
    185. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    186. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    187. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    188. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    189. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    190. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    191. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    192. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    193. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    194. };
    195. void Oled_Show_Image(unsigned char *image)
    196. {
    197. unsigned char i;
    198. unsigned int j;
    199. for(i=0;i<8;i++){
    200. Oled_Write_Cmd(0xB0 + i);//page0--page7
    201. //每个page0
    202. Oled_Write_Cmd(0x00);
    203. Oled_Write_Cmd(0x10);
    204. //0127列,依次写入0,每写入数据,列地址自动偏移
    205. for(j = 128 * i; j<(128 * (i+1));j++){
    206. Oled_Write_Data(image[j]);
    207. }
    208. }
    209. }
    210. /* USER CODE END PM */
    211. /* Private variables ---------------------------------------------------------*/
    212. /* USER CODE BEGIN PV */
    213. /* USER CODE END PV */
    214. /* Private function prototypes -----------------------------------------------*/
    215. void SystemClock_Config(void);
    216. /* USER CODE BEGIN PFP */
    217. /* USER CODE END PFP */
    218. /* Private user code ---------------------------------------------------------*/
    219. /* USER CODE BEGIN 0 */
    220. /* USER CODE END 0 */
    221. /**
    222. * @brief The application entry point.
    223. * @retval int
    224. */
    225. int main(void)
    226. {
    227. /* USER CODE BEGIN 1 */
    228. /* USER CODE END 1 */
    229. /* MCU Configuration--------------------------------------------------------*/
    230. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    231. HAL_Init();
    232. /* USER CODE BEGIN Init */
    233. /* USER CODE END Init */
    234. /* Configure the system clock */
    235. SystemClock_Config();
    236. /* USER CODE BEGIN SysInit */
    237. /* USER CODE END SysInit */
    238. /* Initialize all configured peripherals */
    239. MX_GPIO_Init();
    240. /* USER CODE BEGIN 2 */
    241. OLED_Init();
    242. //2. 选择一个位置
    243. //2.1 确认页寻址模式
    244. Oled_Write_Cmd(0x20);
    245. Oled_Write_Cmd(0x02);
    246. Oled_Screen_Clear();
    247. Oled_Show_Image(bmpImager);
    248. /* USER CODE END 2 */
    249. /* Infinite loop */
    250. /* USER CODE BEGIN WHILE */
    251. while (1)
    252. {
    253. /* USER CODE END WHILE */
    254. /* USER CODE BEGIN 3 */
    255. }
    256. /* USER CODE END 3 */
    257. }

    3.stm32cube配置

    SYS,RCC照旧

    GPIO的配置如下图,PB6,7配置一样

    三、硬件I2C通讯

    1.前提准备

           我们的32单片机是有I2C外设的,而51里面没有I2C外设,因此,我们的32单片机既可以用硬件I2C通讯,也可以模拟I2C通讯。这里我们要实现的是利用32单片机和HAL库重新做一下OLED显示图片,oled的操作说明和图片的操作细节可以再http://t.csdnimg.cn/Bk61c和http://t.csdnimg.cn/A8htshttp://t.csdnimg.cn/Bk61c和 里面看一下。

            我们使用硬件I2C后,可以直接调用直接调用库函数来控制寄存器,让寄存器控制硬件电路的状态从而来控制SDA和SCL的时序。诸如起始终止条件,接受发送字节,应答之类的,我们不用软件I2C那样,自己手动控制SDA和SCL的时序,只需要用库函数即可控制硬件,调制出我们需要的时序。那么既然硬件那么好,为啥还要软件I2C?我玩个梗,加个外设,可以,得加钱。

    2.代码部分(运行出来是女孩头像)

    先说一下我们要用的函数

    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,目标器件的地址,七位地址必须左对齐,外加最后一位读写位

    参数三:uint16_t MemAddress,目标器件的目标寄存器地址或者指令控制字

    参数四:uint16_t MemAddSize,目标器件内部寄存器地址数据长度及一个数据有多大,这里可以选择8位或者16位

    参数五:uint8_t *pData,待写的数据首地址

    参数六:uint16_t Size,待写的数据长度

    参数七:uint32_t Timeout,超时时间 返回值:HAL_StatusTypeDef,HAL状态(OK,busy,ERROR,TIMEOUT)

    沿着51单片机显示图片的程序,我们继续修改

    1. #include "main.h"
    2. #include "i2c.h"
    3. #include "gpio.h"
    4. /* Private includes ----------------------------------------------------------*/
    5. /* USER CODE BEGIN Includes */
    6. /* USER CODE END Includes */
    7. /* Private typedef -----------------------------------------------------------*/
    8. /* USER CODE BEGIN PTD */
    9. /* USER CODE END PTD */
    10. /* Private define ------------------------------------------------------------*/
    11. /* USER CODE BEGIN PD */
    12. /* USER CODE END PD */
    13. /* Private macro -------------------------------------------------------------*/
    14. /* USER CODE BEGIN PM */
    15. /* USER CODE END PM */
    16. /* Private variables ---------------------------------------------------------*/
    17. /* USER CODE BEGIN PV */
    18. void Oled_Write_Cmd(uint8_t dataCmd)
    19. {
    20. HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x00, I2C_MEMADD_SIZE_8BIT,
    21. &dataCmd, 1, 0xff);
    22. }
    23. void Oled_Write_Data(uint8_t dataData)
    24. {
    25. HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x40, I2C_MEMADD_SIZE_8BIT,
    26. &dataData, 1, 0xff);
    27. }
    28. void Oled_Init(void){
    29. Oled_Write_Cmd(0xAE);//--display off
    30. Oled_Write_Cmd(0x00);//---set low column address
    31. Oled_Write_Cmd(0x10);//---set high column address
    32. Oled_Write_Cmd(0x40);//--set start line address
    33. Oled_Write_Cmd(0xB0);//--set page address
    34. Oled_Write_Cmd(0x81); // contract control
    35. Oled_Write_Cmd(0xFF);//--128
    36. Oled_Write_Cmd(0xA1);//set segment remap
    37. Oled_Write_Cmd(0xA6);//--normal / reverse
    38. Oled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)
    39. Oled_Write_Cmd(0x3F);//--1/32 duty
    40. Oled_Write_Cmd(0xC8);//Com scan direction
    41. Oled_Write_Cmd(0xD3);//-set display offset
    42. Oled_Write_Cmd(0x00);//
    43. Oled_Write_Cmd(0xD5);//set osc division
    44. Oled_Write_Cmd(0x80);//
    45. Oled_Write_Cmd(0xD8);//set area color mode off
    46. Oled_Write_Cmd(0x05);//
    47. Oled_Write_Cmd(0xD9);//Set Pre-Charge Period
    48. Oled_Write_Cmd(0xF1);//
    49. Oled_Write_Cmd(0xDA);//set com pin configuartion
    50. Oled_Write_Cmd(0x12);//
    51. Oled_Write_Cmd(0xDB);//set Vcomh
    52. Oled_Write_Cmd(0x30);//
    53. Oled_Write_Cmd(0x8D);//set charge pump enable
    54. Oled_Write_Cmd(0x14);//
    55. Oled_Write_Cmd(0xAF);//--turn on oled panel
    56. }
    57. void Oled_Screen_Clear(void){
    58. char i,n;
    59. Oled_Write_Cmd (0x20); //set memory addressing mode
    60. Oled_Write_Cmd (0x02); //page addressing mode
    61. for(i=0;i<8;i++){
    62. Oled_Write_Cmd(0xb0+i); //éè??ò3μ??·£¨0~7£?
    63. Oled_Write_Cmd(0x00); //éè????ê??????aáDμíμ??·
    64. Oled_Write_Cmd(0x10); //éè????ê??????aáD??μ??·
    65. for(n=0;n<128;n++)
    66. Oled_Write_Data(0x00);
    67. }
    68. }
    69. unsigned char bmpImager[] = {
    70. /*-- 调入了一幅图像:D:\无标题.bmp --*/
    71. /*-- 宽度x高度=128x64 --128x8x8*/
    72. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    73. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    74. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    75. 0x00,0x00,0xF0,0x08,0x0C,0x04,0x06,0x06,0x0C,0x04,0x0C,0xFC,0x1C,0x74,0xFC,0xF8,
    76. 0xF0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    77. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    78. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    79. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    80. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    81. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    82. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    83. 0x00,0x00,0x01,0x07,0x04,0x88,0xF8,0x08,0x08,0x0C,0x06,0x01,0x00,0x00,0x01,0x1F,
    84. 0x7F,0xFF,0xDC,0xF8,0xE0,0xC0,0x40,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    85. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    86. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    87. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    88. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    89. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    90. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x10,0x18,0x08,0x0C,
    91. 0x04,0x04,0x06,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,
    92. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    93. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    94. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    95. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    96. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    97. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    98. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x60,0xC0,0x80,0x80,
    99. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xE0,0x00,0x00,0x00,0x00,
    100. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    101. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    102. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    103. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    104. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    105. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    106. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
    107. 0x03,0x06,0x1C,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x07,0xFC,0x00,0x00,
    108. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x88,0xE8,0x38,0x0E,0x09,0x08,
    109. 0x08,0x88,0xE8,0x18,0x08,0x08,0x08,0x00,0x00,0xFF,0x89,0x89,0x89,0xFF,0x00,0xFF,
    110. 0x89,0x89,0x89,0x89,0xFF,0x00,0x00,0x04,0x04,0x84,0x74,0x6F,0xA4,0x24,0x24,0x24,
    111. 0x24,0xA4,0x64,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    112. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    113. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    114. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    115. 0x00,0x80,0xF0,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x7F,0x00,0x00,
    116. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x08,0x09,0x09,0x06,0x06,
    117. 0x06,0x05,0x08,0x08,0x10,0x10,0x00,0x00,0x0C,0x03,0x10,0x10,0x10,0x1F,0x18,0x07,
    118. 0x00,0x00,0x10,0x10,0x1F,0x00,0x10,0x08,0x06,0x11,0x10,0x08,0x09,0x0A,0x06,0x06,
    119. 0x0B,0x08,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    120. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    121. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    122. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,
    123. 0x1E,0x03,0x00,0x00,0xC0,0x60,0x30,0x0C,0x04,0x06,0x02,0x01,0x01,0x00,0x00,0x00,
    124. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    125. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    126. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    127. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    128. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    129. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    130. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
    131. 0x1E,0x60,0x78,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    132. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    133. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    134. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    135. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    136. };
    137. void Oled_Show_Image(unsigned char *image)
    138. {
    139. unsigned char i;
    140. unsigned int j;
    141. for(i=0;i<8;i++){
    142. Oled_Write_Cmd(0xB0 + i);//page0--page7
    143. //每个page0
    144. Oled_Write_Cmd(0x00);
    145. Oled_Write_Cmd(0x10);
    146. //0127列,依次写入0,每写入数据,列地址自动偏移
    147. for(j = 128 * i; j<(128 * (i+1));j++){
    148. Oled_Write_Data(image[j]);
    149. }
    150. }
    151. }
    152. /* USER CODE END PV */
    153. /* Private function prototypes -----------------------------------------------*/
    154. void SystemClock_Config(void);
    155. /* USER CODE BEGIN PFP */
    156. /* USER CODE END PFP */
    157. /* Private user code ---------------------------------------------------------*/
    158. /* USER CODE BEGIN 0 */
    159. /* USER CODE END 0 */
    160. /**
    161. * @brief The application entry point.
    162. * @retval int
    163. */
    164. int main(void)
    165. {
    166. /* USER CODE BEGIN 1 */
    167. /* USER CODE END 1 */
    168. /* MCU Configuration--------------------------------------------------------*/
    169. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    170. HAL_Init();
    171. /* USER CODE BEGIN Init */
    172. /* USER CODE END Init */
    173. /* Configure the system clock */
    174. SystemClock_Config();
    175. /* USER CODE BEGIN SysInit */
    176. /* USER CODE END SysInit */
    177. /* Initialize all configured peripherals */
    178. MX_GPIO_Init();
    179. MX_I2C1_Init();
    180. /* USER CODE BEGIN 2 */
    181. //1. OLED初始化
    182. Oled_Init();
    183. //2. 选择一个位置
    184. //2.1 确认页寻址模式
    185. Oled_Write_Cmd(0x20);
    186. Oled_Write_Cmd(0x02);
    187. Oled_Screen_Clear();
    188. Oled_Show_Image(bmpImager);
    189. /* USER CODE END 2 */
    190. /* Infinite loop */
    191. /* USER CODE BEGIN WHILE */
    192. while (1)
    193. {
    194. /* USER CODE END WHILE */
    195. /* USER CODE BEGIN 3 */
    196. }
    197. /* USER CODE END 3 */
    198. }

    3.stm32cube的配置

    SYS,RCC照旧不变。I2C1里面如下图选择

    这里要说一点,就是stm32可以作为主机或者从机是用。实验里面,只要stm32产生起始条件,我们把stm32当做主机使用,因此从机模式里面我们压根就没有管,保持他的默认形式就行。

    最后我想说的是,无论是HAL还是标准库,都可以实现我们的需求。标准库写的麻烦,但是可以染你在写程序的时候更多关注于手册的细节,HAL库看似比较简单方便,但是他是高度集成的,里面很多细节不是那么容易看出来的,因为HAL库封装的程度太高了,各取所需吧。

  • 相关阅读:
    如何解释”字面量“?
    零基础入门Vue之To be or not to be——条件渲染
    5分钟让你在大火的多模态领域权威榜单VQA上超越人类
    MySQL 特殊字符
    【Android -- 开源库】fastjson 基本使用
    每日一题:【Leetcode】561.数组拆分
    Java的环境配置
    分布式机器学习(Parameter Server)
    漫谈广告机制设计 | 万剑归宗:聊聊广告机制设计与收入提升的秘密(3)
    二百零五、Flume——数据流监控工具Ganglia单机版安装以及使用Ganglia监控Flume任务的数据流(附流程截图)
  • 原文地址:https://blog.csdn.net/weixin_51374594/article/details/134247232