IIC

IIC

怎么用 STM32CubeMX 实现 I2C Slave?

回复

问题困惑吳秀Black-華love军曹 发起了问题 • 1 人关注 • 0 个回复 • 39 次浏览 • 2018-07-06 14:16 • 来自相关话题

鉴于好多人问,分享个24C64的HAL库文件和使用操作(利用硬件库iic)

软件教程小帅o同学 回复了问题 • 7 人关注 • 9 个回复 • 4668 次浏览 • 2018-07-01 20:14 • 来自相关话题

stm32cubemx配置的stm32的IIC死锁问题解决办法

经验分享aiqinhaii 回复了问题 • 5 人关注 • 5 个回复 • 1554 次浏览 • 2018-03-28 09:25 • 来自相关话题

STM32cubeMx配置I2C出现BUSY问题的解决办法

经验分享admin 回复了问题 • 2 人关注 • 1 个回复 • 707 次浏览 • 2018-01-04 21:25 • 来自相关话题

STM32F103ZET(基于秉火开发板)+Cubemx(F1 V1.60库)+IIC+AT24C02(修复官方例程读写死机bug)

经验分享开始现在-s 发表了文章 • 1 个评论 • 944 次浏览 • 2017-12-11 11:08 • 来自相关话题

首先说明下开发条件:1、开发板:秉火霸道,STM32F103ZET2、软件:Cubemx V4.23(F1 V1.60库)3、硬件:AT24C02 256KByte 问题描述:Cubemx生成IIC代码会出现死机问题,或者压根运行不了!问题原因:1、ST为了规避飞利浦IIC专利问题,将STM32的硬件IIC设计的比较复杂,而且稳定性不怎么好,所以一般教程都不推荐使用。2、Cubemx生成的代码有Bug!解决办法:1、设置2、IIC的回调函数里面需要将时钟初始化放在引脚初始化之前!void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c){  GPIO_InitTypeDef GPIO_InitStruct;  if(hi2c->Instance==I2C1)  {  /* USER CODE BEGIN I2C1_MspInit 0 */    __HAL_RCC_I2C1_CLK_ENABLE(); //默认生成的放在了引脚初始化后面!  /* USER CODE END I2C1_MspInit 0 */      /**I2C1 GPIO Configuration        PB6     ------> I2C1_SCL    PB7     ------> I2C1_SDA     */    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);    /* Peripheral clock enable */  /* USER CODE BEGIN I2C1_MspInit 1 */  /* USER CODE END I2C1_MspInit 1 */  }}3、函数的具体应用需要结合AT24C02的数据手册,符合AT24C02的要求!        我们在读写IIC时,即使不知道IIC的协议是什么,直接调用 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) 这个函数就可以对IIC的设备进行读写,这就是Cubemx的优势!        我先解释下这个函数里面的几个变量:    I2C_HandleTypeDef *hi2c IIC的句柄    uint16_t DevAddress IIC设备的外部地址    uint16_t MemAddress IIC设备的内部地址    uint16_t MemAddSize 读写内部地址的方式,一般使用I2C_MEMADD_SIZE_8BIT方式                        注意只有两种选择:I2C_MEMADD_SIZE_8BIT 或者 I2C_MEMADD_SIZE_16BIT    uint8_t *pData 写入的数组或者指针    uint16_t Size 写入的字节数!    注意:如果是AT24C02,这个字节数不能超过8!!!!!这也叫AT24C02的页写入!当然这是为了提高速度,如果你想不出错也不在乎速度,你可以将字节数设置为1,这样肯定不会出错!    uint32_t Timeout 时间超时4、程序实现    注意:需要在写函数后面加入短延时!uint8_t I2c_Buf_Write[256];uint8_t I2c_Buf_Read[256];uint8_t I2C_Test(void){uint16_t i;i2cStatus=HAL_I2C_IsDeviceReady(&hi2c1, 0xA0, 256, 1000);  //0表示readyprintf("i2cStatus = %d\r\n ", i2cStatus);i2cStatus1=HAL_I2C_GetState(&hi2c1);//32表示ready  HAL_I2C_STATE_READY  = 0x20U,   /*!< Peripheral Initialized and ready for use  */printf("i2cStatus1 = %d\r\n ", i2cStatus1);printf("写入的数据\n\r");for ( i=0; i<256; i++ ) //填充缓冲  {       I2c_Buf_Write[i] = i; HAL_I2C_Mem_Write(&hi2c1, (uint16_t)EEPROM_Block0_ADDRESS, i, I2C_MEMADD_SIZE_8BIT, (uint8_t*)(&(I2c_Buf_Write[i])), 1, 10000);//一个字节一个字节写,如果需要页写入(不超过8),使用40行的函数// HAL_I2C_Mem_Write(&hi2c1, (uint16_t)EEPROM_Block0_ADDRESS, 0x00, I2C_MEMADD_SIZE_8BIT,(uint8_t*)I2c_Buf_Write, 8, 10000);//不能超过8个字节,如果超过需要分开写,for循环里面改为i=i+8 printf("0xX ", I2c_Buf_Write[i]); HAL_Delay(5);//不能少   }  EEPROM_INFO("\n\r写成功\n\r");  HAL_Delay(500); EEPROM_INFO("\n\r读出的数据\n\r");  //将EEPROM读出数据顺序保持到I2c_Buf_Read中//if(HAL_I2C_GetState(&hi2c1) == 0x20 ) //加入检测if( HAL_I2C_IsDeviceReady(&hi2c1, 0xA0, 256, 1000) == HAL_OK)//另外一种检测方法{ HAL_I2C_Mem_Read(&hi2c1, (uint16_t)(EEPROM_Block0_ADDRESS+1 ),0x00, I2C_MEMADD_SIZE_8BIT,(uint8_t *)I2c_Buf_Read, 256, 10000); //读对字节数没有限制}//将I2c_Buf_Read中的数据通过串口打印for (i=0; i<256; i++){    printf("0xX ", I2c_Buf_Read[i]);         if(I2c_Buf_Read[i] != I2c_Buf_Write[i])          {             EEPROM_ERROR("0xX ", I2c_Buf_Read[i]);             EEPROM_ERROR("错误:I2C EEPROM写入与读出的数据不一致\n\r");             return 0;         }     }  EEPROM_INFO("I2C(AT24C02)读写测试成功\n\r");  return 1;  }5、联系方式:微信Startingray,本人准备将cubemx的小bug解决的过程记录下来,也是给爱好者一点启示,欢迎微信和我沟通,共同进步!个人觉得Cubemx是未来的发展方向,可以使我们避免很多小错误,但是由于现在软件版本之间的兼容性,加上不同版本库之间存在的bug,还是需要我们在使用时时刻保持警惕! 查看全部

首先说明下开发条件:

1、开发板:秉火霸道,STM32F103ZET

2、软件:Cubemx V4.23(F1 V1.60库)

3、硬件:AT24C02 256KByte 

问题描述:Cubemx生成IIC代码会出现死机问题,或者压根运行不了!

问题原因:

1、ST为了规避飞利浦IIC专利问题,将STM32的硬件IIC设计的比较复杂,而且稳定性不怎么好,所以一般教程都不推荐使用。

2、Cubemx生成的代码有Bug!

解决办法:

1、设置

捕获.JPG

2、IIC的回调函数里面需要将时钟初始化放在引脚初始化之前

void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)

{


  GPIO_InitTypeDef GPIO_InitStruct;

  if(hi2c->Instance==I2C1)

  {

  /* USER CODE BEGIN I2C1_MspInit 0 */

    __HAL_RCC_I2C1_CLK_ENABLE(); //默认生成的放在了引脚初始化后面!

  /* USER CODE END I2C1_MspInit 0 */

  

    /**I2C1 GPIO Configuration    

    PB6     ------> I2C1_SCL

    PB7     ------> I2C1_SDA 

    */

    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);


    /* Peripheral clock enable */


  /* USER CODE BEGIN I2C1_MspInit 1 */


  /* USER CODE END I2C1_MspInit 1 */

  }


}

3、函数的具体应用需要结合AT24C02的数据手册,符合AT24C02的要求!

    

    我们在读写IIC时,即使不知道IIC的协议是什么,直接调用 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) 这个函数就可以对IIC的设备进行读写,这就是Cubemx的优势!

    

    我先解释下这个函数里面的几个变量:


    I2C_HandleTypeDef *hi2c IIC的句柄

    uint16_t DevAddress IIC设备的外部地址

    uint16_t MemAddress IIC设备的内部地址

    uint16_t MemAddSize 读写内部地址的方式,一般使用I2C_MEMADD_SIZE_8BIT方式

                        注意只有两种选择:I2C_MEMADD_SIZE_8BIT 或者 I2C_MEMADD_SIZE_16BIT

    uint8_t *pData 写入的数组或者指针

    uint16_t Size 写入的字节数!

    注意:如果是AT24C02,这个字节数不能超过8!!!!!这也叫AT24C02的页写入!当然这是为了提高速度,如果你想不出错也不在乎速度,你可以将字节数设置为1,这样肯定不会出错!


捕获1.JPG    uint32_t Timeout 时间超时


4、程序实现

    注意:需要在写函数后面加入短延时!


uint8_t I2c_Buf_Write[256];

uint8_t I2c_Buf_Read[256];



uint8_t I2C_Test(void)

{

uint16_t i;

i2cStatus=HAL_I2C_IsDeviceReady(&hi2c1, 0xA0, 256, 1000);  //0表示ready

printf("i2cStatus = %d\r\n ", i2cStatus);

i2cStatus1=HAL_I2C_GetState(&hi2c1);//32表示ready  HAL_I2C_STATE_READY  = 0x20U,   /*!< Peripheral Initialized and ready for use  */

printf("i2cStatus1 = %d\r\n ", i2cStatus1);

printf("写入的数据\n\r");


for ( i=0; i<256; i++ ) //填充缓冲

  {   

    I2c_Buf_Write[i] = i;

HAL_I2C_Mem_Write(&hi2c1, (uint16_t)EEPROM_Block0_ADDRESS, i, I2C_MEMADD_SIZE_8BIT, (uint8_t*)(&(I2c_Buf_Write[i])), 1, 10000);//一个字节一个字节写,如果需要页写入(不超过8),使用40行的函数

// HAL_I2C_Mem_Write(&hi2c1, (uint16_t)EEPROM_Block0_ADDRESS, 0x00, I2C_MEMADD_SIZE_8BIT,(uint8_t*)I2c_Buf_Write, 8, 10000);//不能超过8个字节,如果超过需要分开写,for循环里面改为i=i+8 

printf("0xX ", I2c_Buf_Write[i]);

HAL_Delay(5);//不能少

   }

  EEPROM_INFO("\n\r写成功\n\r"); 

HAL_Delay(500);

EEPROM_INFO("\n\r读出的数据\n\r");

  //将EEPROM读出数据顺序保持到I2c_Buf_Read中

//if(HAL_I2C_GetState(&hi2c1) == 0x20 ) //加入检测

if( HAL_I2C_IsDeviceReady(&hi2c1, 0xA0, 256, 1000) == HAL_OK)//另外一种检测方法

{

HAL_I2C_Mem_Read(&hi2c1, (uint16_t)(EEPROM_Block0_ADDRESS+1 ),0x00, I2C_MEMADD_SIZE_8BIT,(uint8_t *)I2c_Buf_Read, 256, 10000); //读对字节数没有限制

}


//将I2c_Buf_Read中的数据通过串口打印

for (i=0; i<256; i++)

{

    printf("0xX ", I2c_Buf_Read[i]);

         if(I2c_Buf_Read[i] != I2c_Buf_Write[i])

          {

             EEPROM_ERROR("0xX ", I2c_Buf_Read[i]);

             EEPROM_ERROR("错误:I2C EEPROM写入与读出的数据不一致\n\r");

             return 0;

         } 

    }

  EEPROM_INFO("I2C(AT24C02)读写测试成功\n\r");

  return 1; 

 }


5、联系方式:微信Startingray,本人准备将cubemx的小bug解决的过程记录下来,也是给爱好者一点启示,欢迎微信和我沟通,共同进步!个人觉得Cubemx是未来的发展方向,可以使我们避免很多小错误,但是由于现在软件版本之间的兼容性,加上不同版本库之间存在的bug,还是需要我们在使用时时刻保持警惕!

知道为什么大部分人喜欢用IO口模拟IIC吗?知道怎么去模拟吗?这里有你要的答案

经验分享yunqingabc 回复了问题 • 7 人关注 • 4 个回复 • 3314 次浏览 • 2016-09-04 15:59 • 来自相关话题

(转)在转一篇针对u8glib单色屏库+SSD1306 的使用介绍

经验分享admin 发表了文章 • 0 个评论 • 1139 次浏览 • 2016-07-04 11:49 • 来自相关话题

Using the u8glib on the STM32
The u8glib is a really nice library to use when you don’t want to mess around with different diplay protocols or drawing routines. It is well-conceived and easy to use. Unfortunately there has been no port for STM32 microcontrollers so I tried to do this.

In the following example I will use the library to display some text on a SSD1306 display via I2C. The controller I use is the STM32F101CBT6 and the IDE will be Atollic True Studio for ARM Lite.

You should start by downloading the u8glib for arm. This is the C version of the library which I will use since you can only compile C code with the Lite version of my IDE.

The next step is to implement the entire project into your code. So I created a new folder and just draged in the „src“ folder from the archive.

Now some low level routines have to be implemented to allow the library to talk to the display device. The following routines have to be created:
Delay by n microsecondsDelay by 10 microsecondsDelay by 1 microsecondDoing a Reset on the displayWriting a byte to the displayWriting a sequence of bytes to the displaySwitching from data to command mode or vice versa
To do so we create a new source file called „u8g_arm.c“ and a header file „u8g_arm.h„.

In the header file you should include the original u8g.h header file so basically just do:
#ifndef _U8G_ARM_H
#define _U8G_ARM_H

//adjust this path:
#include "u8glib/u8g.h"

//main com function. read on...
uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);

#endifThe most important procedure in these files will be the one that is called by the u8g library with data to send to the display device. This communication procedure looks like this. I added comments for every important statement. Add it to the file „u8g_arm.c“.
uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{

switch(msg)
{
case U8G_COM_MSG_STOP:
//STOP THE DEVICE
break;

case U8G_COM_MSG_INIT:
//INIT HARDWARE INTERFACES, TIMERS, GPIOS...
break;

case U8G_COM_MSG_ADDRESS:
//SWITCH FROM DATA TO COMMAND MODE (arg_val == 0 for command mode)
break;

case U8G_COM_MSG_RESET:
//TOGGLE THE RESET PIN ON THE DISPLAY BY THE VALUE IN arg_val
break;

case U8G_COM_MSG_WRITE_BYTE:
//WRITE BYTE TO DEVICE
break;

case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
//WRITE A SEQUENCE OF BYTES TO THE DEVICE
break;

}
return 1;
}Now just add code to every case of the switch statement. For my communication with I2C it looks like this:
uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{

switch(msg)
{
case U8G_COM_MSG_STOP:
break; //do nothing...

case U8G_COM_MSG_INIT:
i2c_init(); //inits the i2c hardware, gpios and timers
u8g_MicroDelay();
break;

case U8G_COM_MSG_ADDRESS:
//the control byte switches the mode on the device and is set here
if (arg_val == 0)
{
control = 0;
}
else
{
control = 0x40;
}
u8g_10MicroDelay();
break;

case U8G_COM_MSG_RESET:
//pin 9 is my reset pin
GPIO_WriteBit(GPIOB, GPIO_Pin_9, arg_val);
u8g_10MicroDelay();
break;

case U8G_COM_MSG_WRITE_BYTE:
//simple: just write one byte
i2c_out(arg_val);
u8g_MicroDelay();
break;

case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
{
register uint8_t *ptr = arg_ptr;
//send the control byte (to switch from command to data mode)
I2C_start(SSD1306_I2C_ADDRESS, I2C_Direction_Transmitter);
I2C_SendData(I2C2, control);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

//now send the rest of data
while( arg_val > 0 )
{
I2C_SendData(I2C2, *ptr++);
arg_val--;
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}
//done
I2C_stop();
u8g_MicroDelay();
}
break;

}
return 1;
}My routines to  write and read data via I2C are basically copied from this nice article. If you want the full code please contact me or write a comment since I don’t want to publish it because of bad style.

Ok so now we have the low level hardware communication set up. Now it is time to really enjoy the amazing u8g library.

To tell u8glib to use our communication function we just have to call it like this.
My routines to write and read data via I2C are basically copied from this nice article. If you want the full code please contact me or write a comment since I don’t want to publish it because of bad style.

Ok so now we have the low level hardware communication set up. Now it is time to really enjoy the amazing u8g library.

To tell u8glib to use our communication function we just have to call it like this.I hope you noticed that the third parameter to this function is our hardware routine.

That is basically all you have to do. Now you can use all functions of the u8glib. Please remind that you use the C library of the project so you cannot directly copy code from the tutorials.
 
>>引用自:http://blog.bastelhalde.de/?p=759 查看全部
Using the u8glib on the STM32
The u8glib is a really nice library to use when you don’t want to mess around with different diplay protocols or drawing routines. It is well-conceived and easy to use. Unfortunately there has been no port for STM32 microcontrollers so I tried to do this.

In the following example I will use the library to display some text on a SSD1306 display via I2C. The controller I use is the STM32F101CBT6 and the IDE will be Atollic True Studio for ARM Lite.

You should start by downloading the u8glib for arm. This is the C version of the library which I will use since you can only compile C code with the Lite version of my IDE.

The next step is to implement the entire project into your code. So I created a new folder and just draged in the „src“ folder from the archive.

Now some low level routines have to be implemented to allow the library to talk to the display device. The following routines have to be created:
  • Delay by n microseconds
  • Delay by 10 microseconds
  • Delay by 1 microsecond
  • Doing a Reset on the display
  • Writing a byte to the display
  • Writing a sequence of bytes to the display
  • Switching from data to command mode or vice versa

To do so we create a new source file called „u8g_arm.c“ and a header file „u8g_arm.h„.

In the header file you should include the original u8g.h header file so basically just do:
#ifndef _U8G_ARM_H
#define _U8G_ARM_H

//adjust this path:
#include "u8glib/u8g.h"

//main com function. read on...
uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);

#endif
The most important procedure in these files will be the one that is called by the u8g library with data to send to the display device. This communication procedure looks like this. I added comments for every important statement. Add it to the file „u8g_arm.c“.
uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{

switch(msg)
{
case U8G_COM_MSG_STOP:
//STOP THE DEVICE
break;

case U8G_COM_MSG_INIT:
//INIT HARDWARE INTERFACES, TIMERS, GPIOS...
break;

case U8G_COM_MSG_ADDRESS:
//SWITCH FROM DATA TO COMMAND MODE (arg_val == 0 for command mode)
break;

case U8G_COM_MSG_RESET:
//TOGGLE THE RESET PIN ON THE DISPLAY BY THE VALUE IN arg_val
break;

case U8G_COM_MSG_WRITE_BYTE:
//WRITE BYTE TO DEVICE
break;

case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
//WRITE A SEQUENCE OF BYTES TO THE DEVICE
break;

}
return 1;
}
Now just add code to every case of the switch statement. For my communication with I2C it looks like this:
uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{

switch(msg)
{
case U8G_COM_MSG_STOP:
break; //do nothing...

case U8G_COM_MSG_INIT:
i2c_init(); //inits the i2c hardware, gpios and timers
u8g_MicroDelay();
break;

case U8G_COM_MSG_ADDRESS:
//the control byte switches the mode on the device and is set here
if (arg_val == 0)
{
control = 0;
}
else
{
control = 0x40;
}
u8g_10MicroDelay();
break;

case U8G_COM_MSG_RESET:
//pin 9 is my reset pin
GPIO_WriteBit(GPIOB, GPIO_Pin_9, arg_val);
u8g_10MicroDelay();
break;

case U8G_COM_MSG_WRITE_BYTE:
//simple: just write one byte
i2c_out(arg_val);
u8g_MicroDelay();
break;

case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
{
register uint8_t *ptr = arg_ptr;
//send the control byte (to switch from command to data mode)
I2C_start(SSD1306_I2C_ADDRESS, I2C_Direction_Transmitter);
I2C_SendData(I2C2, control);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

//now send the rest of data
while( arg_val > 0 )
{
I2C_SendData(I2C2, *ptr++);
arg_val--;
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}
//done
I2C_stop();
u8g_MicroDelay();
}
break;

}
return 1;
}
My routines to  write and read data via I2C are basically copied from this nice article. If you want the full code please contact me or write a comment since I don’t want to publish it because of bad style.

Ok so now we have the low level hardware communication set up. Now it is time to really enjoy the amazing u8g library.

To tell u8glib to use our communication function we just have to call it like this.
My routines to  write and read data via I2C are basically copied from this nice article. If you want the full code please contact me or write a comment since I don’t want to publish it because of bad style.

Ok so now we have the low level hardware communication set up. Now it is time to really enjoy the amazing u8g library.

To tell u8glib to use our communication function we just have to call it like this.
I hope you noticed that the third parameter to this function is our hardware routine.

That is basically all you have to do. Now you can use all functions of the u8glib. Please remind that you use the C library of the project so you cannot directly copy code from the tutorials.
 
>>引用自:http://blog.bastelhalde.de/?p=759

(转)STM32F4discovery + I2C OLED SSD1306 + u8glib + CubeMX--(u8glib单色库的使用)

经验分享admin 发表了文章 • 8 个评论 • 4954 次浏览 • 2016-07-04 11:39 • 来自相关话题

U8blib - is cool library to manage with various monochrome displays. It could take the responsibility of middle-level interface with display. For example, draw lines, place text, another primitives - everything this library can. But you need to provide low-level interface to it - such as byte send, reset device, delays etc. SSD1306 OLED display - this is the guy, like this:
U8blib——是一个库来管理各种单色显示器。它是一个用来处理用户显示接口的中间层。例如,绘制线条/文本/其他元素——这个库都能做。但你需要提供底层接口,如字节发送,重置设备,延误等等。SSD1306 OLED显示器,这个家伙,像这样:





I've bought it on aliexpress, and selected I2C connected display. Also, I have SPI version. But today we'll talk about I2C only.

Ok, let's start. First - download latest version of u8glib library here:
 
https://bintray.com/olikraus/u8glib/ARM/view
 
Unpack archive, we'll see folders  src and two folders for lpc controllers. But we are cool guys and we need code for cool controllers:) Thus - we delete folders for LPC controllers, and we'll make folder inc. Into inc folder place files u8g_arm.h (need to be created manually), and u8g.h (already existed in src folder).

u8g_arm.h contains:
#ifndef _U8G_ARM_H
#define _U8G_ARM_H


#include "u8g.h"
#include "stm32f4xx_hal.h"


#define DATA_BUFFER_SIZE 1000
#define I2C_TIMEOUT 10000
#define DEVICE_ADDRESS 0x78 //device address is written on back side of your display
#define I2C_HANDLER hi2c3

extern I2C_HandleTypeDef hi2c3; // use your i2c handler


uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);

#endif u8g_arm.c:
#include "u8g_arm.h"

static uint8_t control = 0;
void u8g_Delay(uint16_t val)
{

HAL_Delay(val);
}

void u8g_MicroDelay(void)
{
int i;
for (i = 0; i < 1000; i++);
}

void u8g_10MicroDelay(void)
{
int i;
for (i = 0; i < 10000; i++);
}


uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{
switch(msg)
{
case U8G_COM_MSG_STOP:
break;

case U8G_COM_MSG_INIT:
u8g_MicroDelay();
break;

case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
u8g_10MicroDelay();
if (arg_val == 0)
{
control = 0;
}
else
{
control = 0x40;
}
break;

case U8G_COM_MSG_WRITE_BYTE:
{
uint8_t buffer[2];
buffer[0] = control;
buffer[1] = arg_val;
HAL_I2C_Master_Transmit(&I2C_HANDLER, DEVICE_ADDRESS, (uint8_t*) buffer, 2, I2C_TIMEOUT);
}
break;

case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
{
uint8_t buffer[DATA_BUFFER_SIZE];
uint8_t *ptr = arg_ptr;
buffer[0] = control;
for (int i = 1; i <= arg_val; i++)
{
buffer[i] = *(ptr++);
}
HAL_I2C_Master_Transmit(&I2C_HANDLER, DEVICE_ADDRESS, (uint8_t *)buffer, arg_val, I2C_TIMEOUT);
}

break;
}
return 1;
} I'll remind you: place u8g_arm.c file into src folder, make inc folder and place there u8g.h file (without changes) and our prepared file u8g_arm.h.

Why we did this all?
U8glib must have access to low-level functions to work with display. It needs delay functions and function which could perform such operations: write byte to display, write sequence of bytes, init display etc.
Our OLED display works a little bit tricky: it has two modes of sending data. First - send command and second - send data. And how it recognises them? Before every byte, which you'll send, you need to send "instruction" to display, to told display, what type of data you'll send: data or command. If you intend to send command, you need to send [0x00 0xyour_command] array. If you want to send data, you need to send [0x40 0x_your_data] array. By the way, that blog, which I have mentioned before, made this operations incorrectly, which leads to wrong operation.

Ok, now we're ready to start CubeMX and prepare our project. I'll skip steps, where I just pick up my discoveryF4 board. 





Clock configuration stay unchanged, also I've did not changed any I2C configuration:





添加u8glib库的路径




Ok, let's generate project for system workbench, and try to compile it + flash your controller. If you have not achieved success with this, problem is not in display:) 
Now, we'll place our previously prepared folders "src" and "inc" into folder "your_project_folder\Drivers\u8glib\". I do not know why, but eclipse-based SystemWorkbench tool does not see our folder, and we need to link it manually to our project. Right-click on folder "Drivers" in project explorer, New->;Folder, then button "Advanced", there - "Link to alternate location"(huh, difficult, maybe someone knows how to do this simpler?).
Then - right-click on project, there - properties. There we need to add our folder to includes.

Also, I've changed c language dialect, to be able write like this:
for(int i = 0; i < 10; i++)
because older standards allows only like this:
int i;
for (i = 0; i < 10; i++)

and turn off code optimization.
Also, there is another issue. U8glib has A LOT of fonts for writing strings on your display. But they has large size. So, you need to select only fonts, which you need. You can watch them here: 
https://github.com/olikraus/u8glib/wiki/fontsize 
. And then, I'll select only two by deleting unnecessary fonts in file u8g_font_data.c. Or, you can just comment. Idea is to left only this per font: 
#include "u8g.h"
const u8g_fntpgm_uint8_t u8g_font_profont10[2560] U8G_FONT_SECTION("u8g_font_profont10") = {
/*you font, i've not placed this*/
}; Ok now we'll open our main.c
 and modify it like this:
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"

/* USER CODE BEGIN Includes */
#include "u8g_arm.h"
/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c3; /*this is our handler, you need to place it in your u8g_arm.h file!!!!!

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
static u8g_t u8g;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C3_Init(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */
/*
Function which responds for drawing
*/
void draw(void)
{
u8g_SetFont(&u8g,u8g_font_profont10);//set current font
u8g_DrawStr(&u8g, 2, 12, "Hello!");//write string - you set coordinates and string
u8g_DrawBox(&u8g, 30, 30, 35, 35);//draw some box
}
/* USER CODE END 0 */

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

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

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C3_Init();

/* USER CODE BEGIN 2 */
u8g_InitComFn(&u8g, &u8g_dev_ssd1306_128x64_i2c, u8g_com_hw_i2c_fn); //here we init our u8glib driver
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
//this loop correspond of drawing
u8g_FirstPage(&u8g);
do
{
draw();
} while ( u8g_NextPage(&u8g) );
u8g_Delay(10);
}
/* USER CODE END 3 */

}
/* UNCHANGED PART OF YOUR CODE */ Do not forget to place your i2c handler to u8g_arm.h file!
u8g_InitComFn(&u8g, &u8g_dev_ssd1306_128x64_i2c, u8g_com_hw_i2c_fn); - here we init our driver and tell it, what function if responsible for low-level communication with our display.

Everything you want to draw you place to draw() function.
Code here: 
https://github.com/sincoon/SSD1306_I2C 
  
Tadam! Start debug, and we see wonderful picture with square and little text:)
The only issue, which I've found - there is some garbage at last pixel in row, and now I do not know how to fix this. I hope, I'll found solution, and tell you. Or, you'll find and tell me:)

文中相关u8glib单色库在本站百度云中有下载:文件名u8glib单色屏库.zip
本文演示代码在本站百度云有下载:文件名SSD1306_I2C-master.zip
 
>>引用自:http://elastic-notes.blogspot. ... %3Dbl
 
  查看全部
U8blib - is cool library to manage with various monochrome displays. It could take the responsibility of middle-level interface with display. For example, draw lines, place text, another primitives - everything this library can. But you need to provide low-level interface to it - such as byte send, reset device, delays etc. SSD1306 OLED display - this is the guy, like this:
U8blib——是一个库来管理各种单色显示器。它是一个用来处理用户显示接口的中间层。例如,绘制线条/文本/其他元素——这个库都能做。但你需要提供底层接口,如字节发送,重置设备,延误等等。SSD1306 OLED显示器,这个家伙,像这样:

003edd.jpg

I've bought it on aliexpress, and selected I2C connected display. Also, I have SPI version. But today we'll talk about I2C only.

Ok, let's start. First - download latest version of u8glib library here:
 
https://bintray.com/olikraus/u8glib/ARM/view
 
Unpack archive, we'll see folders  src and two folders for lpc controllers. But we are cool guys and we need code for cool controllers:) Thus - we delete folders for LPC controllers, and we'll make folder inc. Into inc folder place files u8g_arm.h (need to be created manually), and u8g.h (already existed in src folder).

u8g_arm.h contains:
#ifndef _U8G_ARM_H  
#define _U8G_ARM_H


#include "u8g.h"
#include "stm32f4xx_hal.h"


#define DATA_BUFFER_SIZE 1000
#define I2C_TIMEOUT 10000
#define DEVICE_ADDRESS 0x78 //device address is written on back side of your display
#define I2C_HANDLER hi2c3

extern I2C_HandleTypeDef hi2c3; // use your i2c handler


uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);

#endif
u8g_arm.c:
#include "u8g_arm.h"  

static uint8_t control = 0;
void u8g_Delay(uint16_t val)
{

HAL_Delay(val);
}

void u8g_MicroDelay(void)
{
int i;
for (i = 0; i < 1000; i++);
}

void u8g_10MicroDelay(void)
{
int i;
for (i = 0; i < 10000; i++);
}


uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{
switch(msg)
{
case U8G_COM_MSG_STOP:
break;

case U8G_COM_MSG_INIT:
u8g_MicroDelay();
break;

case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
u8g_10MicroDelay();
if (arg_val == 0)
{
control = 0;
}
else
{
control = 0x40;
}
break;

case U8G_COM_MSG_WRITE_BYTE:
{
uint8_t buffer[2];
buffer[0] = control;
buffer[1] = arg_val;
HAL_I2C_Master_Transmit(&I2C_HANDLER, DEVICE_ADDRESS, (uint8_t*) buffer, 2, I2C_TIMEOUT);
}
break;

case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
{
uint8_t buffer[DATA_BUFFER_SIZE];
uint8_t *ptr = arg_ptr;
buffer[0] = control;
for (int i = 1; i <= arg_val; i++)
{
buffer[i] = *(ptr++);
}
HAL_I2C_Master_Transmit(&I2C_HANDLER, DEVICE_ADDRESS, (uint8_t *)buffer, arg_val, I2C_TIMEOUT);
}

break;
}
return 1;
}
I'll remind you: place u8g_arm.c file into src folder, make inc folder and place there u8g.h file (without changes) and our prepared file u8g_arm.h.

Why we did this all?
U8glib must have access to low-level functions to work with display. It needs delay functions and function which could perform such operations: write byte to display, write sequence of bytes, init display etc.
Our OLED display works a little bit tricky: it has two modes of sending data. First - send command and second - send data. And how it recognises them? Before every byte, which you'll send, you need to send "instruction" to display, to told display, what type of data you'll send: data or command. If you intend to send command, you need to send [0x00 0xyour_command] array. If you want to send data, you need to send [0x40 0x_your_data] array. By the way, that blog, which I have mentioned before, made this operations incorrectly, which leads to wrong operation.

Ok, now we're ready to start CubeMX and prepare our project. I'll skip steps, where I just pick up my discoveryF4 board. 

QQ截图20160704112028.png

Clock configuration stay unchanged, also I've did not changed any I2C configuration:

QQ截图20160704112333.png

添加u8glib库的路径
QQ截图20160704112318.png

Ok, let's generate project for system workbench, and try to compile it + flash your controller. If you have not achieved success with this, problem is not in display:) 
Now, we'll place our previously prepared folders "src" and "inc" into folder "your_project_folder\Drivers\u8glib\". I do not know why, but eclipse-based SystemWorkbench tool does not see our folder, and we need to link it manually to our project. Right-click on folder "Drivers" in project explorer, New->;Folder, then button "Advanced", there - "Link to alternate location"(huh, difficult, maybe someone knows how to do this simpler?).
Then - right-click on project, there - properties. There we need to add our folder to includes.

Also, I've changed c language dialect, to be able write like this:
for(int i = 0; i < 10; i++)
because older standards allows only like this:
int i;
for (i = 0; i < 10; i++)

and turn off code optimization.
Also, there is another issue. U8glib has A LOT of fonts for writing strings on your display. But they has large size. So, you need to select only fonts, which you need. You can watch them here: 
https://github.com/olikraus/u8glib/wiki/fontsize 
. And then, I'll select only two by deleting unnecessary fonts in file u8g_font_data.c. Or, you can just comment. Idea is to left only this per font: 
#include "u8g.h"  
const u8g_fntpgm_uint8_t u8g_font_profont10[2560] U8G_FONT_SECTION("u8g_font_profont10") = {
/*you font, i've not placed this*/
};
Ok now we'll open our main.c
 and modify it like this:
 /* Includes ------------------------------------------------------------------*/  
#include "stm32f4xx_hal.h"

/* USER CODE BEGIN Includes */
#include "u8g_arm.h"
/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c3; /*this is our handler, you need to place it in your u8g_arm.h file!!!!!

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
static u8g_t u8g;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C3_Init(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */
/*
Function which responds for drawing
*/
void draw(void)
{
u8g_SetFont(&u8g,u8g_font_profont10);//set current font
u8g_DrawStr(&u8g, 2, 12, "Hello!");//write string - you set coordinates and string
u8g_DrawBox(&u8g, 30, 30, 35, 35);//draw some box
}
/* USER CODE END 0 */

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

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

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C3_Init();

/* USER CODE BEGIN 2 */
u8g_InitComFn(&u8g, &u8g_dev_ssd1306_128x64_i2c, u8g_com_hw_i2c_fn); //here we init our u8glib driver
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
//this loop correspond of drawing
u8g_FirstPage(&u8g);
do
{
draw();
} while ( u8g_NextPage(&u8g) );
u8g_Delay(10);
}
/* USER CODE END 3 */

}
/* UNCHANGED PART OF YOUR CODE */
Do not forget to place your i2c handler to u8g_arm.h file!
u8g_InitComFn(&u8g, &u8g_dev_ssd1306_128x64_i2c, u8g_com_hw_i2c_fn); - here we init our driver and tell it, what function if responsible for low-level communication with our display.

Everything you want to draw you place to draw() function.
Code here: 
https://github.com/sincoon/SSD1306_I2C 
  
Tadam! Start debug, and we see wonderful picture with square and little text:)
The only issue, which I've found - there is some garbage at last pixel in row, and now I do not know how to fix this. I hope, I'll found solution, and tell you. Or, you'll find and tell me:)

文中相关u8glib单色库在本站百度云中有下载:文件名u8glib单色屏库.zip
本文演示代码在本站百度云有下载:文件名SSD1306_I2C-master.zip
 
>>引用自:http://elastic-notes.blogspot. ... %3Dbl
 
 

请问有用cube库做过利用DMA进行i2c通信的吗?能给个例子参考一下吗

回复

问题困惑raingoose 发起了问题 • 1 人关注 • 0 个回复 • 838 次浏览 • 2016-05-26 09:39 • 来自相关话题

怎么用 STM32CubeMX 实现 I2C Slave?

回复

问题困惑吳秀Black-華love军曹 发起了问题 • 1 人关注 • 0 个回复 • 39 次浏览 • 2018-07-06 14:16 • 来自相关话题

鉴于好多人问,分享个24C64的HAL库文件和使用操作(利用硬件库iic)

回复

软件教程小帅o同学 回复了问题 • 7 人关注 • 9 个回复 • 4668 次浏览 • 2018-07-01 20:14 • 来自相关话题

stm32cubemx配置的stm32的IIC死锁问题解决办法

回复

经验分享aiqinhaii 回复了问题 • 5 人关注 • 5 个回复 • 1554 次浏览 • 2018-03-28 09:25 • 来自相关话题

STM32cubeMx配置I2C出现BUSY问题的解决办法

回复

经验分享admin 回复了问题 • 2 人关注 • 1 个回复 • 707 次浏览 • 2018-01-04 21:25 • 来自相关话题

知道为什么大部分人喜欢用IO口模拟IIC吗?知道怎么去模拟吗?这里有你要的答案

回复

经验分享yunqingabc 回复了问题 • 7 人关注 • 4 个回复 • 3314 次浏览 • 2016-09-04 15:59 • 来自相关话题

请问有用cube库做过利用DMA进行i2c通信的吗?能给个例子参考一下吗

回复

问题困惑raingoose 发起了问题 • 1 人关注 • 0 个回复 • 838 次浏览 • 2016-05-26 09:39 • 来自相关话题

STM32F103ZET(基于秉火开发板)+Cubemx(F1 V1.60库)+IIC+AT24C02(修复官方例程读写死机bug)

经验分享开始现在-s 发表了文章 • 1 个评论 • 944 次浏览 • 2017-12-11 11:08 • 来自相关话题

首先说明下开发条件:1、开发板:秉火霸道,STM32F103ZET2、软件:Cubemx V4.23(F1 V1.60库)3、硬件:AT24C02 256KByte 问题描述:Cubemx生成IIC代码会出现死机问题,或者压根运行不了!问题原因:1、ST为了规避飞利浦IIC专利问题,将STM32的硬件IIC设计的比较复杂,而且稳定性不怎么好,所以一般教程都不推荐使用。2、Cubemx生成的代码有Bug!解决办法:1、设置2、IIC的回调函数里面需要将时钟初始化放在引脚初始化之前!void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c){  GPIO_InitTypeDef GPIO_InitStruct;  if(hi2c->Instance==I2C1)  {  /* USER CODE BEGIN I2C1_MspInit 0 */    __HAL_RCC_I2C1_CLK_ENABLE(); //默认生成的放在了引脚初始化后面!  /* USER CODE END I2C1_MspInit 0 */      /**I2C1 GPIO Configuration        PB6     ------> I2C1_SCL    PB7     ------> I2C1_SDA     */    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);    /* Peripheral clock enable */  /* USER CODE BEGIN I2C1_MspInit 1 */  /* USER CODE END I2C1_MspInit 1 */  }}3、函数的具体应用需要结合AT24C02的数据手册,符合AT24C02的要求!        我们在读写IIC时,即使不知道IIC的协议是什么,直接调用 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) 这个函数就可以对IIC的设备进行读写,这就是Cubemx的优势!        我先解释下这个函数里面的几个变量:    I2C_HandleTypeDef *hi2c IIC的句柄    uint16_t DevAddress IIC设备的外部地址    uint16_t MemAddress IIC设备的内部地址    uint16_t MemAddSize 读写内部地址的方式,一般使用I2C_MEMADD_SIZE_8BIT方式                        注意只有两种选择:I2C_MEMADD_SIZE_8BIT 或者 I2C_MEMADD_SIZE_16BIT    uint8_t *pData 写入的数组或者指针    uint16_t Size 写入的字节数!    注意:如果是AT24C02,这个字节数不能超过8!!!!!这也叫AT24C02的页写入!当然这是为了提高速度,如果你想不出错也不在乎速度,你可以将字节数设置为1,这样肯定不会出错!    uint32_t Timeout 时间超时4、程序实现    注意:需要在写函数后面加入短延时!uint8_t I2c_Buf_Write[256];uint8_t I2c_Buf_Read[256];uint8_t I2C_Test(void){uint16_t i;i2cStatus=HAL_I2C_IsDeviceReady(&hi2c1, 0xA0, 256, 1000);  //0表示readyprintf("i2cStatus = %d\r\n ", i2cStatus);i2cStatus1=HAL_I2C_GetState(&hi2c1);//32表示ready  HAL_I2C_STATE_READY  = 0x20U,   /*!< Peripheral Initialized and ready for use  */printf("i2cStatus1 = %d\r\n ", i2cStatus1);printf("写入的数据\n\r");for ( i=0; i<256; i++ ) //填充缓冲  {       I2c_Buf_Write[i] = i; HAL_I2C_Mem_Write(&hi2c1, (uint16_t)EEPROM_Block0_ADDRESS, i, I2C_MEMADD_SIZE_8BIT, (uint8_t*)(&(I2c_Buf_Write[i])), 1, 10000);//一个字节一个字节写,如果需要页写入(不超过8),使用40行的函数// HAL_I2C_Mem_Write(&hi2c1, (uint16_t)EEPROM_Block0_ADDRESS, 0x00, I2C_MEMADD_SIZE_8BIT,(uint8_t*)I2c_Buf_Write, 8, 10000);//不能超过8个字节,如果超过需要分开写,for循环里面改为i=i+8 printf("0xX ", I2c_Buf_Write[i]); HAL_Delay(5);//不能少   }  EEPROM_INFO("\n\r写成功\n\r");  HAL_Delay(500); EEPROM_INFO("\n\r读出的数据\n\r");  //将EEPROM读出数据顺序保持到I2c_Buf_Read中//if(HAL_I2C_GetState(&hi2c1) == 0x20 ) //加入检测if( HAL_I2C_IsDeviceReady(&hi2c1, 0xA0, 256, 1000) == HAL_OK)//另外一种检测方法{ HAL_I2C_Mem_Read(&hi2c1, (uint16_t)(EEPROM_Block0_ADDRESS+1 ),0x00, I2C_MEMADD_SIZE_8BIT,(uint8_t *)I2c_Buf_Read, 256, 10000); //读对字节数没有限制}//将I2c_Buf_Read中的数据通过串口打印for (i=0; i<256; i++){    printf("0xX ", I2c_Buf_Read[i]);         if(I2c_Buf_Read[i] != I2c_Buf_Write[i])          {             EEPROM_ERROR("0xX ", I2c_Buf_Read[i]);             EEPROM_ERROR("错误:I2C EEPROM写入与读出的数据不一致\n\r");             return 0;         }     }  EEPROM_INFO("I2C(AT24C02)读写测试成功\n\r");  return 1;  }5、联系方式:微信Startingray,本人准备将cubemx的小bug解决的过程记录下来,也是给爱好者一点启示,欢迎微信和我沟通,共同进步!个人觉得Cubemx是未来的发展方向,可以使我们避免很多小错误,但是由于现在软件版本之间的兼容性,加上不同版本库之间存在的bug,还是需要我们在使用时时刻保持警惕! 查看全部

首先说明下开发条件:

1、开发板:秉火霸道,STM32F103ZET

2、软件:Cubemx V4.23(F1 V1.60库)

3、硬件:AT24C02 256KByte 

问题描述:Cubemx生成IIC代码会出现死机问题,或者压根运行不了!

问题原因:

1、ST为了规避飞利浦IIC专利问题,将STM32的硬件IIC设计的比较复杂,而且稳定性不怎么好,所以一般教程都不推荐使用。

2、Cubemx生成的代码有Bug!

解决办法:

1、设置

捕获.JPG

2、IIC的回调函数里面需要将时钟初始化放在引脚初始化之前

void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)

{


  GPIO_InitTypeDef GPIO_InitStruct;

  if(hi2c->Instance==I2C1)

  {

  /* USER CODE BEGIN I2C1_MspInit 0 */

    __HAL_RCC_I2C1_CLK_ENABLE(); //默认生成的放在了引脚初始化后面!

  /* USER CODE END I2C1_MspInit 0 */

  

    /**I2C1 GPIO Configuration    

    PB6     ------> I2C1_SCL

    PB7     ------> I2C1_SDA 

    */

    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);


    /* Peripheral clock enable */


  /* USER CODE BEGIN I2C1_MspInit 1 */


  /* USER CODE END I2C1_MspInit 1 */

  }


}

3、函数的具体应用需要结合AT24C02的数据手册,符合AT24C02的要求!

    

    我们在读写IIC时,即使不知道IIC的协议是什么,直接调用 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) 这个函数就可以对IIC的设备进行读写,这就是Cubemx的优势!

    

    我先解释下这个函数里面的几个变量:


    I2C_HandleTypeDef *hi2c IIC的句柄

    uint16_t DevAddress IIC设备的外部地址

    uint16_t MemAddress IIC设备的内部地址

    uint16_t MemAddSize 读写内部地址的方式,一般使用I2C_MEMADD_SIZE_8BIT方式

                        注意只有两种选择:I2C_MEMADD_SIZE_8BIT 或者 I2C_MEMADD_SIZE_16BIT

    uint8_t *pData 写入的数组或者指针

    uint16_t Size 写入的字节数!

    注意:如果是AT24C02,这个字节数不能超过8!!!!!这也叫AT24C02的页写入!当然这是为了提高速度,如果你想不出错也不在乎速度,你可以将字节数设置为1,这样肯定不会出错!


捕获1.JPG    uint32_t Timeout 时间超时


4、程序实现

    注意:需要在写函数后面加入短延时!


uint8_t I2c_Buf_Write[256];

uint8_t I2c_Buf_Read[256];



uint8_t I2C_Test(void)

{

uint16_t i;

i2cStatus=HAL_I2C_IsDeviceReady(&hi2c1, 0xA0, 256, 1000);  //0表示ready

printf("i2cStatus = %d\r\n ", i2cStatus);

i2cStatus1=HAL_I2C_GetState(&hi2c1);//32表示ready  HAL_I2C_STATE_READY  = 0x20U,   /*!< Peripheral Initialized and ready for use  */

printf("i2cStatus1 = %d\r\n ", i2cStatus1);

printf("写入的数据\n\r");


for ( i=0; i<256; i++ ) //填充缓冲

  {   

    I2c_Buf_Write[i] = i;

HAL_I2C_Mem_Write(&hi2c1, (uint16_t)EEPROM_Block0_ADDRESS, i, I2C_MEMADD_SIZE_8BIT, (uint8_t*)(&(I2c_Buf_Write[i])), 1, 10000);//一个字节一个字节写,如果需要页写入(不超过8),使用40行的函数

// HAL_I2C_Mem_Write(&hi2c1, (uint16_t)EEPROM_Block0_ADDRESS, 0x00, I2C_MEMADD_SIZE_8BIT,(uint8_t*)I2c_Buf_Write, 8, 10000);//不能超过8个字节,如果超过需要分开写,for循环里面改为i=i+8 

printf("0xX ", I2c_Buf_Write[i]);

HAL_Delay(5);//不能少

   }

  EEPROM_INFO("\n\r写成功\n\r"); 

HAL_Delay(500);

EEPROM_INFO("\n\r读出的数据\n\r");

  //将EEPROM读出数据顺序保持到I2c_Buf_Read中

//if(HAL_I2C_GetState(&hi2c1) == 0x20 ) //加入检测

if( HAL_I2C_IsDeviceReady(&hi2c1, 0xA0, 256, 1000) == HAL_OK)//另外一种检测方法

{

HAL_I2C_Mem_Read(&hi2c1, (uint16_t)(EEPROM_Block0_ADDRESS+1 ),0x00, I2C_MEMADD_SIZE_8BIT,(uint8_t *)I2c_Buf_Read, 256, 10000); //读对字节数没有限制

}


//将I2c_Buf_Read中的数据通过串口打印

for (i=0; i<256; i++)

{

    printf("0xX ", I2c_Buf_Read[i]);

         if(I2c_Buf_Read[i] != I2c_Buf_Write[i])

          {

             EEPROM_ERROR("0xX ", I2c_Buf_Read[i]);

             EEPROM_ERROR("错误:I2C EEPROM写入与读出的数据不一致\n\r");

             return 0;

         } 

    }

  EEPROM_INFO("I2C(AT24C02)读写测试成功\n\r");

  return 1; 

 }


5、联系方式:微信Startingray,本人准备将cubemx的小bug解决的过程记录下来,也是给爱好者一点启示,欢迎微信和我沟通,共同进步!个人觉得Cubemx是未来的发展方向,可以使我们避免很多小错误,但是由于现在软件版本之间的兼容性,加上不同版本库之间存在的bug,还是需要我们在使用时时刻保持警惕!

(转)在转一篇针对u8glib单色屏库+SSD1306 的使用介绍

经验分享admin 发表了文章 • 0 个评论 • 1139 次浏览 • 2016-07-04 11:49 • 来自相关话题

Using the u8glib on the STM32
The u8glib is a really nice library to use when you don’t want to mess around with different diplay protocols or drawing routines. It is well-conceived and easy to use. Unfortunately there has been no port for STM32 microcontrollers so I tried to do this.

In the following example I will use the library to display some text on a SSD1306 display via I2C. The controller I use is the STM32F101CBT6 and the IDE will be Atollic True Studio for ARM Lite.

You should start by downloading the u8glib for arm. This is the C version of the library which I will use since you can only compile C code with the Lite version of my IDE.

The next step is to implement the entire project into your code. So I created a new folder and just draged in the „src“ folder from the archive.

Now some low level routines have to be implemented to allow the library to talk to the display device. The following routines have to be created:
Delay by n microsecondsDelay by 10 microsecondsDelay by 1 microsecondDoing a Reset on the displayWriting a byte to the displayWriting a sequence of bytes to the displaySwitching from data to command mode or vice versa
To do so we create a new source file called „u8g_arm.c“ and a header file „u8g_arm.h„.

In the header file you should include the original u8g.h header file so basically just do:
#ifndef _U8G_ARM_H
#define _U8G_ARM_H

//adjust this path:
#include "u8glib/u8g.h"

//main com function. read on...
uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);

#endifThe most important procedure in these files will be the one that is called by the u8g library with data to send to the display device. This communication procedure looks like this. I added comments for every important statement. Add it to the file „u8g_arm.c“.
uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{

switch(msg)
{
case U8G_COM_MSG_STOP:
//STOP THE DEVICE
break;

case U8G_COM_MSG_INIT:
//INIT HARDWARE INTERFACES, TIMERS, GPIOS...
break;

case U8G_COM_MSG_ADDRESS:
//SWITCH FROM DATA TO COMMAND MODE (arg_val == 0 for command mode)
break;

case U8G_COM_MSG_RESET:
//TOGGLE THE RESET PIN ON THE DISPLAY BY THE VALUE IN arg_val
break;

case U8G_COM_MSG_WRITE_BYTE:
//WRITE BYTE TO DEVICE
break;

case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
//WRITE A SEQUENCE OF BYTES TO THE DEVICE
break;

}
return 1;
}Now just add code to every case of the switch statement. For my communication with I2C it looks like this:
uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{

switch(msg)
{
case U8G_COM_MSG_STOP:
break; //do nothing...

case U8G_COM_MSG_INIT:
i2c_init(); //inits the i2c hardware, gpios and timers
u8g_MicroDelay();
break;

case U8G_COM_MSG_ADDRESS:
//the control byte switches the mode on the device and is set here
if (arg_val == 0)
{
control = 0;
}
else
{
control = 0x40;
}
u8g_10MicroDelay();
break;

case U8G_COM_MSG_RESET:
//pin 9 is my reset pin
GPIO_WriteBit(GPIOB, GPIO_Pin_9, arg_val);
u8g_10MicroDelay();
break;

case U8G_COM_MSG_WRITE_BYTE:
//simple: just write one byte
i2c_out(arg_val);
u8g_MicroDelay();
break;

case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
{
register uint8_t *ptr = arg_ptr;
//send the control byte (to switch from command to data mode)
I2C_start(SSD1306_I2C_ADDRESS, I2C_Direction_Transmitter);
I2C_SendData(I2C2, control);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

//now send the rest of data
while( arg_val > 0 )
{
I2C_SendData(I2C2, *ptr++);
arg_val--;
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}
//done
I2C_stop();
u8g_MicroDelay();
}
break;

}
return 1;
}My routines to  write and read data via I2C are basically copied from this nice article. If you want the full code please contact me or write a comment since I don’t want to publish it because of bad style.

Ok so now we have the low level hardware communication set up. Now it is time to really enjoy the amazing u8g library.

To tell u8glib to use our communication function we just have to call it like this.
My routines to write and read data via I2C are basically copied from this nice article. If you want the full code please contact me or write a comment since I don’t want to publish it because of bad style.

Ok so now we have the low level hardware communication set up. Now it is time to really enjoy the amazing u8g library.

To tell u8glib to use our communication function we just have to call it like this.I hope you noticed that the third parameter to this function is our hardware routine.

That is basically all you have to do. Now you can use all functions of the u8glib. Please remind that you use the C library of the project so you cannot directly copy code from the tutorials.
 
>>引用自:http://blog.bastelhalde.de/?p=759 查看全部
Using the u8glib on the STM32
The u8glib is a really nice library to use when you don’t want to mess around with different diplay protocols or drawing routines. It is well-conceived and easy to use. Unfortunately there has been no port for STM32 microcontrollers so I tried to do this.

In the following example I will use the library to display some text on a SSD1306 display via I2C. The controller I use is the STM32F101CBT6 and the IDE will be Atollic True Studio for ARM Lite.

You should start by downloading the u8glib for arm. This is the C version of the library which I will use since you can only compile C code with the Lite version of my IDE.

The next step is to implement the entire project into your code. So I created a new folder and just draged in the „src“ folder from the archive.

Now some low level routines have to be implemented to allow the library to talk to the display device. The following routines have to be created:
  • Delay by n microseconds
  • Delay by 10 microseconds
  • Delay by 1 microsecond
  • Doing a Reset on the display
  • Writing a byte to the display
  • Writing a sequence of bytes to the display
  • Switching from data to command mode or vice versa

To do so we create a new source file called „u8g_arm.c“ and a header file „u8g_arm.h„.

In the header file you should include the original u8g.h header file so basically just do:
#ifndef _U8G_ARM_H
#define _U8G_ARM_H

//adjust this path:
#include "u8glib/u8g.h"

//main com function. read on...
uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);

#endif
The most important procedure in these files will be the one that is called by the u8g library with data to send to the display device. This communication procedure looks like this. I added comments for every important statement. Add it to the file „u8g_arm.c“.
uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{

switch(msg)
{
case U8G_COM_MSG_STOP:
//STOP THE DEVICE
break;

case U8G_COM_MSG_INIT:
//INIT HARDWARE INTERFACES, TIMERS, GPIOS...
break;

case U8G_COM_MSG_ADDRESS:
//SWITCH FROM DATA TO COMMAND MODE (arg_val == 0 for command mode)
break;

case U8G_COM_MSG_RESET:
//TOGGLE THE RESET PIN ON THE DISPLAY BY THE VALUE IN arg_val
break;

case U8G_COM_MSG_WRITE_BYTE:
//WRITE BYTE TO DEVICE
break;

case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
//WRITE A SEQUENCE OF BYTES TO THE DEVICE
break;

}
return 1;
}
Now just add code to every case of the switch statement. For my communication with I2C it looks like this:
uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{

switch(msg)
{
case U8G_COM_MSG_STOP:
break; //do nothing...

case U8G_COM_MSG_INIT:
i2c_init(); //inits the i2c hardware, gpios and timers
u8g_MicroDelay();
break;

case U8G_COM_MSG_ADDRESS:
//the control byte switches the mode on the device and is set here
if (arg_val == 0)
{
control = 0;
}
else
{
control = 0x40;
}
u8g_10MicroDelay();
break;

case U8G_COM_MSG_RESET:
//pin 9 is my reset pin
GPIO_WriteBit(GPIOB, GPIO_Pin_9, arg_val);
u8g_10MicroDelay();
break;

case U8G_COM_MSG_WRITE_BYTE:
//simple: just write one byte
i2c_out(arg_val);
u8g_MicroDelay();
break;

case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
{
register uint8_t *ptr = arg_ptr;
//send the control byte (to switch from command to data mode)
I2C_start(SSD1306_I2C_ADDRESS, I2C_Direction_Transmitter);
I2C_SendData(I2C2, control);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

//now send the rest of data
while( arg_val > 0 )
{
I2C_SendData(I2C2, *ptr++);
arg_val--;
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}
//done
I2C_stop();
u8g_MicroDelay();
}
break;

}
return 1;
}
My routines to  write and read data via I2C are basically copied from this nice article. If you want the full code please contact me or write a comment since I don’t want to publish it because of bad style.

Ok so now we have the low level hardware communication set up. Now it is time to really enjoy the amazing u8g library.

To tell u8glib to use our communication function we just have to call it like this.
My routines to  write and read data via I2C are basically copied from this nice article. If you want the full code please contact me or write a comment since I don’t want to publish it because of bad style.

Ok so now we have the low level hardware communication set up. Now it is time to really enjoy the amazing u8g library.

To tell u8glib to use our communication function we just have to call it like this.
I hope you noticed that the third parameter to this function is our hardware routine.

That is basically all you have to do. Now you can use all functions of the u8glib. Please remind that you use the C library of the project so you cannot directly copy code from the tutorials.
 
>>引用自:http://blog.bastelhalde.de/?p=759

(转)STM32F4discovery + I2C OLED SSD1306 + u8glib + CubeMX--(u8glib单色库的使用)

经验分享admin 发表了文章 • 8 个评论 • 4954 次浏览 • 2016-07-04 11:39 • 来自相关话题

U8blib - is cool library to manage with various monochrome displays. It could take the responsibility of middle-level interface with display. For example, draw lines, place text, another primitives - everything this library can. But you need to provide low-level interface to it - such as byte send, reset device, delays etc. SSD1306 OLED display - this is the guy, like this:
U8blib——是一个库来管理各种单色显示器。它是一个用来处理用户显示接口的中间层。例如,绘制线条/文本/其他元素——这个库都能做。但你需要提供底层接口,如字节发送,重置设备,延误等等。SSD1306 OLED显示器,这个家伙,像这样:





I've bought it on aliexpress, and selected I2C connected display. Also, I have SPI version. But today we'll talk about I2C only.

Ok, let's start. First - download latest version of u8glib library here:
 
https://bintray.com/olikraus/u8glib/ARM/view
 
Unpack archive, we'll see folders  src and two folders for lpc controllers. But we are cool guys and we need code for cool controllers:) Thus - we delete folders for LPC controllers, and we'll make folder inc. Into inc folder place files u8g_arm.h (need to be created manually), and u8g.h (already existed in src folder).

u8g_arm.h contains:
#ifndef _U8G_ARM_H
#define _U8G_ARM_H


#include "u8g.h"
#include "stm32f4xx_hal.h"


#define DATA_BUFFER_SIZE 1000
#define I2C_TIMEOUT 10000
#define DEVICE_ADDRESS 0x78 //device address is written on back side of your display
#define I2C_HANDLER hi2c3

extern I2C_HandleTypeDef hi2c3; // use your i2c handler


uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);

#endif u8g_arm.c:
#include "u8g_arm.h"

static uint8_t control = 0;
void u8g_Delay(uint16_t val)
{

HAL_Delay(val);
}

void u8g_MicroDelay(void)
{
int i;
for (i = 0; i < 1000; i++);
}

void u8g_10MicroDelay(void)
{
int i;
for (i = 0; i < 10000; i++);
}


uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{
switch(msg)
{
case U8G_COM_MSG_STOP:
break;

case U8G_COM_MSG_INIT:
u8g_MicroDelay();
break;

case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
u8g_10MicroDelay();
if (arg_val == 0)
{
control = 0;
}
else
{
control = 0x40;
}
break;

case U8G_COM_MSG_WRITE_BYTE:
{
uint8_t buffer[2];
buffer[0] = control;
buffer[1] = arg_val;
HAL_I2C_Master_Transmit(&I2C_HANDLER, DEVICE_ADDRESS, (uint8_t*) buffer, 2, I2C_TIMEOUT);
}
break;

case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
{
uint8_t buffer[DATA_BUFFER_SIZE];
uint8_t *ptr = arg_ptr;
buffer[0] = control;
for (int i = 1; i <= arg_val; i++)
{
buffer[i] = *(ptr++);
}
HAL_I2C_Master_Transmit(&I2C_HANDLER, DEVICE_ADDRESS, (uint8_t *)buffer, arg_val, I2C_TIMEOUT);
}

break;
}
return 1;
} I'll remind you: place u8g_arm.c file into src folder, make inc folder and place there u8g.h file (without changes) and our prepared file u8g_arm.h.

Why we did this all?
U8glib must have access to low-level functions to work with display. It needs delay functions and function which could perform such operations: write byte to display, write sequence of bytes, init display etc.
Our OLED display works a little bit tricky: it has two modes of sending data. First - send command and second - send data. And how it recognises them? Before every byte, which you'll send, you need to send "instruction" to display, to told display, what type of data you'll send: data or command. If you intend to send command, you need to send [0x00 0xyour_command] array. If you want to send data, you need to send [0x40 0x_your_data] array. By the way, that blog, which I have mentioned before, made this operations incorrectly, which leads to wrong operation.

Ok, now we're ready to start CubeMX and prepare our project. I'll skip steps, where I just pick up my discoveryF4 board. 





Clock configuration stay unchanged, also I've did not changed any I2C configuration:





添加u8glib库的路径




Ok, let's generate project for system workbench, and try to compile it + flash your controller. If you have not achieved success with this, problem is not in display:) 
Now, we'll place our previously prepared folders "src" and "inc" into folder "your_project_folder\Drivers\u8glib\". I do not know why, but eclipse-based SystemWorkbench tool does not see our folder, and we need to link it manually to our project. Right-click on folder "Drivers" in project explorer, New->;Folder, then button "Advanced", there - "Link to alternate location"(huh, difficult, maybe someone knows how to do this simpler?).
Then - right-click on project, there - properties. There we need to add our folder to includes.

Also, I've changed c language dialect, to be able write like this:
for(int i = 0; i < 10; i++)
because older standards allows only like this:
int i;
for (i = 0; i < 10; i++)

and turn off code optimization.
Also, there is another issue. U8glib has A LOT of fonts for writing strings on your display. But they has large size. So, you need to select only fonts, which you need. You can watch them here: 
https://github.com/olikraus/u8glib/wiki/fontsize 
. And then, I'll select only two by deleting unnecessary fonts in file u8g_font_data.c. Or, you can just comment. Idea is to left only this per font: 
#include "u8g.h"
const u8g_fntpgm_uint8_t u8g_font_profont10[2560] U8G_FONT_SECTION("u8g_font_profont10") = {
/*you font, i've not placed this*/
}; Ok now we'll open our main.c
 and modify it like this:
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"

/* USER CODE BEGIN Includes */
#include "u8g_arm.h"
/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c3; /*this is our handler, you need to place it in your u8g_arm.h file!!!!!

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
static u8g_t u8g;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C3_Init(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */
/*
Function which responds for drawing
*/
void draw(void)
{
u8g_SetFont(&u8g,u8g_font_profont10);//set current font
u8g_DrawStr(&u8g, 2, 12, "Hello!");//write string - you set coordinates and string
u8g_DrawBox(&u8g, 30, 30, 35, 35);//draw some box
}
/* USER CODE END 0 */

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

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

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C3_Init();

/* USER CODE BEGIN 2 */
u8g_InitComFn(&u8g, &u8g_dev_ssd1306_128x64_i2c, u8g_com_hw_i2c_fn); //here we init our u8glib driver
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
//this loop correspond of drawing
u8g_FirstPage(&u8g);
do
{
draw();
} while ( u8g_NextPage(&u8g) );
u8g_Delay(10);
}
/* USER CODE END 3 */

}
/* UNCHANGED PART OF YOUR CODE */ Do not forget to place your i2c handler to u8g_arm.h file!
u8g_InitComFn(&u8g, &u8g_dev_ssd1306_128x64_i2c, u8g_com_hw_i2c_fn); - here we init our driver and tell it, what function if responsible for low-level communication with our display.

Everything you want to draw you place to draw() function.
Code here: 
https://github.com/sincoon/SSD1306_I2C 
  
Tadam! Start debug, and we see wonderful picture with square and little text:)
The only issue, which I've found - there is some garbage at last pixel in row, and now I do not know how to fix this. I hope, I'll found solution, and tell you. Or, you'll find and tell me:)

文中相关u8glib单色库在本站百度云中有下载:文件名u8glib单色屏库.zip
本文演示代码在本站百度云有下载:文件名SSD1306_I2C-master.zip
 
>>引用自:http://elastic-notes.blogspot. ... %3Dbl
 
  查看全部
U8blib - is cool library to manage with various monochrome displays. It could take the responsibility of middle-level interface with display. For example, draw lines, place text, another primitives - everything this library can. But you need to provide low-level interface to it - such as byte send, reset device, delays etc. SSD1306 OLED display - this is the guy, like this:
U8blib——是一个库来管理各种单色显示器。它是一个用来处理用户显示接口的中间层。例如,绘制线条/文本/其他元素——这个库都能做。但你需要提供底层接口,如字节发送,重置设备,延误等等。SSD1306 OLED显示器,这个家伙,像这样:

003edd.jpg

I've bought it on aliexpress, and selected I2C connected display. Also, I have SPI version. But today we'll talk about I2C only.

Ok, let's start. First - download latest version of u8glib library here:
 
https://bintray.com/olikraus/u8glib/ARM/view
 
Unpack archive, we'll see folders  src and two folders for lpc controllers. But we are cool guys and we need code for cool controllers:) Thus - we delete folders for LPC controllers, and we'll make folder inc. Into inc folder place files u8g_arm.h (need to be created manually), and u8g.h (already existed in src folder).

u8g_arm.h contains:
#ifndef _U8G_ARM_H  
#define _U8G_ARM_H


#include "u8g.h"
#include "stm32f4xx_hal.h"


#define DATA_BUFFER_SIZE 1000
#define I2C_TIMEOUT 10000
#define DEVICE_ADDRESS 0x78 //device address is written on back side of your display
#define I2C_HANDLER hi2c3

extern I2C_HandleTypeDef hi2c3; // use your i2c handler


uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);

#endif
u8g_arm.c:
#include "u8g_arm.h"  

static uint8_t control = 0;
void u8g_Delay(uint16_t val)
{

HAL_Delay(val);
}

void u8g_MicroDelay(void)
{
int i;
for (i = 0; i < 1000; i++);
}

void u8g_10MicroDelay(void)
{
int i;
for (i = 0; i < 10000; i++);
}


uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{
switch(msg)
{
case U8G_COM_MSG_STOP:
break;

case U8G_COM_MSG_INIT:
u8g_MicroDelay();
break;

case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
u8g_10MicroDelay();
if (arg_val == 0)
{
control = 0;
}
else
{
control = 0x40;
}
break;

case U8G_COM_MSG_WRITE_BYTE:
{
uint8_t buffer[2];
buffer[0] = control;
buffer[1] = arg_val;
HAL_I2C_Master_Transmit(&I2C_HANDLER, DEVICE_ADDRESS, (uint8_t*) buffer, 2, I2C_TIMEOUT);
}
break;

case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
{
uint8_t buffer[DATA_BUFFER_SIZE];
uint8_t *ptr = arg_ptr;
buffer[0] = control;
for (int i = 1; i <= arg_val; i++)
{
buffer[i] = *(ptr++);
}
HAL_I2C_Master_Transmit(&I2C_HANDLER, DEVICE_ADDRESS, (uint8_t *)buffer, arg_val, I2C_TIMEOUT);
}

break;
}
return 1;
}
I'll remind you: place u8g_arm.c file into src folder, make inc folder and place there u8g.h file (without changes) and our prepared file u8g_arm.h.

Why we did this all?
U8glib must have access to low-level functions to work with display. It needs delay functions and function which could perform such operations: write byte to display, write sequence of bytes, init display etc.
Our OLED display works a little bit tricky: it has two modes of sending data. First - send command and second - send data. And how it recognises them? Before every byte, which you'll send, you need to send "instruction" to display, to told display, what type of data you'll send: data or command. If you intend to send command, you need to send [0x00 0xyour_command] array. If you want to send data, you need to send [0x40 0x_your_data] array. By the way, that blog, which I have mentioned before, made this operations incorrectly, which leads to wrong operation.

Ok, now we're ready to start CubeMX and prepare our project. I'll skip steps, where I just pick up my discoveryF4 board. 

QQ截图20160704112028.png

Clock configuration stay unchanged, also I've did not changed any I2C configuration:

QQ截图20160704112333.png

添加u8glib库的路径
QQ截图20160704112318.png

Ok, let's generate project for system workbench, and try to compile it + flash your controller. If you have not achieved success with this, problem is not in display:) 
Now, we'll place our previously prepared folders "src" and "inc" into folder "your_project_folder\Drivers\u8glib\". I do not know why, but eclipse-based SystemWorkbench tool does not see our folder, and we need to link it manually to our project. Right-click on folder "Drivers" in project explorer, New->;Folder, then button "Advanced", there - "Link to alternate location"(huh, difficult, maybe someone knows how to do this simpler?).
Then - right-click on project, there - properties. There we need to add our folder to includes.

Also, I've changed c language dialect, to be able write like this:
for(int i = 0; i < 10; i++)
because older standards allows only like this:
int i;
for (i = 0; i < 10; i++)

and turn off code optimization.
Also, there is another issue. U8glib has A LOT of fonts for writing strings on your display. But they has large size. So, you need to select only fonts, which you need. You can watch them here: 
https://github.com/olikraus/u8glib/wiki/fontsize 
. And then, I'll select only two by deleting unnecessary fonts in file u8g_font_data.c. Or, you can just comment. Idea is to left only this per font: 
#include "u8g.h"  
const u8g_fntpgm_uint8_t u8g_font_profont10[2560] U8G_FONT_SECTION("u8g_font_profont10") = {
/*you font, i've not placed this*/
};
Ok now we'll open our main.c
 and modify it like this:
 /* Includes ------------------------------------------------------------------*/  
#include "stm32f4xx_hal.h"

/* USER CODE BEGIN Includes */
#include "u8g_arm.h"
/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c3; /*this is our handler, you need to place it in your u8g_arm.h file!!!!!

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
static u8g_t u8g;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C3_Init(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */
/*
Function which responds for drawing
*/
void draw(void)
{
u8g_SetFont(&u8g,u8g_font_profont10);//set current font
u8g_DrawStr(&u8g, 2, 12, "Hello!");//write string - you set coordinates and string
u8g_DrawBox(&u8g, 30, 30, 35, 35);//draw some box
}
/* USER CODE END 0 */

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

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

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C3_Init();

/* USER CODE BEGIN 2 */
u8g_InitComFn(&u8g, &u8g_dev_ssd1306_128x64_i2c, u8g_com_hw_i2c_fn); //here we init our u8glib driver
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
//this loop correspond of drawing
u8g_FirstPage(&u8g);
do
{
draw();
} while ( u8g_NextPage(&u8g) );
u8g_Delay(10);
}
/* USER CODE END 3 */

}
/* UNCHANGED PART OF YOUR CODE */
Do not forget to place your i2c handler to u8g_arm.h file!
u8g_InitComFn(&u8g, &u8g_dev_ssd1306_128x64_i2c, u8g_com_hw_i2c_fn); - here we init our driver and tell it, what function if responsible for low-level communication with our display.

Everything you want to draw you place to draw() function.
Code here: 
https://github.com/sincoon/SSD1306_I2C 
  
Tadam! Start debug, and we see wonderful picture with square and little text:)
The only issue, which I've found - there is some garbage at last pixel in row, and now I do not know how to fix this. I hope, I'll found solution, and tell you. Or, you'll find and tell me:)

文中相关u8glib单色库在本站百度云中有下载:文件名u8glib单色屏库.zip
本文演示代码在本站百度云有下载:文件名SSD1306_I2C-master.zip
 
>>引用自:http://elastic-notes.blogspot. ... %3Dbl