lkl0305 发表于 2014-1-26 15:16:58

【STM32F030开发日志/评测/笔记】+(2)STM32F0处理器I2C实例(...

上次给大家分享了STM32的I2C结构体中的时间寄存器配置工具的使用(【STM32F030开发日志/评测/笔记】+(1)STM32F0处理器I2C时间配置工具使用),为了测试STM32F0的I2C总线库变成,今天给大家分享一下I2C操作气压传感器BMP085的程序,至于完整的BMP085的说明文档及完整的程序,我放在附件中。
实现具体功能:STM32F030使用I2C1接口与BMP085通信,每个0.5s采集一次温度和气压值,然后通过USART1传送到电脑的SerialChart上,绘制曲线。
下图是用SerialChart接收到的气压和温度数据及曲线,绿色曲线是温度14.2度(温度值需要除10),红色曲线气压1.009MPa。


下图是用逻辑分析仪采集的I2C波形。


若要使用STM32F0操作硬件I2C外设,可使用下面的步骤。

1、配置GPIO引脚功能
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_1);

GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_1);

2、初始化I2C外设
I2C_InitTypeDef I2C_InitStructure;

RCC_I2CCLKConfig(RCC_I2C1CLK_SYSCLK);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable;
I2C_InitStructure.I2C_DigitalFilter = 0x01;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_Timing = 0x30E32E44;
I2C_Init(I2C1, &I2C_InitStructure);

I2C_Cmd(I2C1, ENABLE);

3、调用I2C的外设库函数进行读写I2C
我采用的是查询方式
主要使用的库函数有:
(A)void I2C_TransferHandling(I2C_TypeDef* I2Cx, uint16_t Address, uint8_t Number_Bytes, uint32_t ReloadEndMode, uint32_t StartStopMode)
(B)uint8_t I2C_ReceiveData( I2C_TypeDef *I2Cx )
(C)void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data)
详细说明可看标准外设库帮助文档。

(1)I2C设备读数据程序段
/**
* @brief从I2C1总线上的某一器件的某一起始地址中读取一定字节的数据到数组中
* @paramdriver_Addr:I2C器件地址
* @paramstart_Addr:起始字节地址
* @paramnumber_Bytes:要读取的字节数量(小于一页)
* @paramread_Buffer:存放读取数据的数组指针
* @retval 是否读取成功
*/
I2C_Status I2C1_Read_NBytes(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *read_Buffer)
{
uint8_t read_Num;

I2C_Timeout = I2C_TIMEOUT;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET)
{
    if((I2C_Timeout--) == 0)
    {
      return I2C_FAIL;
    }
}

I2C_TransferHandling(I2C1, driver_Addr, 1, I2C_SoftEnd_Mode, I2C_Generate_Start_Write);

I2C_Timeout = I2C_TIMEOUT;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET)
{
    if((I2C_Timeout--) == 0)
    {
      return I2C_FAIL;
    }
}

I2C_SendData(I2C1, start_Addr);

I2C_Timeout = I2C_TIMEOUT;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TC) == RESET)
{
    if((I2C_Timeout--) == 0)
    {
      return I2C_FAIL;
    }
}

I2C_TransferHandling(I2C1, driver_Addr, number_Bytes,I2C_AutoEnd_Mode, I2C_Generate_Start_Read);

for(read_Num = 0; read_Num < number_Bytes; read_Num++)
{
    I2C_Timeout = I2C_TIMEOUT;
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET)
    {
      if((I2C_Timeout--) == 0)
      {
      return I2C_FAIL;
      }
    }
   
    read_Buffer = I2C_ReceiveData(I2C1);
}

I2C_Timeout = I2C_TIMEOUT;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF) == RESET)
{
    if((I2C_Timeout--) == 0)
    {
      return I2C_FAIL;
    }
}

return I2C_OK;
}


(2)I2C设备写数据程序段
/**
* @brief从I2C1的总线上的某一器件的某一起始地址中读取一定字节的数据到数组中
* @paramdriver_Addr:I2C器件地址
* @paramstart_Addr:起始字节地址
* @paramnumber_Bytes:要读取的字节数量(小于一页)
* @paramwrite_Buffer:存放读取数据的数组指针
* @retval 是否读取成功
*/
I2C_Status I2C1_Write_NBytes(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *write_Buffer)
{
uint8_t write_Num;

I2C_Timeout = I2C_TIMEOUT;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET)
{
    if((I2C_Timeout--) == 0)
    {
      return I2C_FAIL;
    }
}

I2C_TransferHandling(I2C1, driver_Addr, 1, I2C_Reload_Mode, I2C_Generate_Start_Write);

I2C_Timeout = I2C_TIMEOUT;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET)
{
    if((I2C_Timeout--) == 0)
    {
      return I2C_FAIL;
    }
}

I2C_SendData(I2C1, start_Addr);

I2C_Timeout = I2C_TIMEOUT;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TCR) == RESET)
{
    if((I2C_Timeout--) == 0)
    {
      return I2C_FAIL;
    }
}

I2C_TransferHandling(I2C1, driver_Addr, number_Bytes, I2C_AutoEnd_Mode, I2C_No_StartStop);

for(write_Num = 0; write_Num < number_Bytes; write_Num++)
{
    I2C_Timeout = I2C_TIMEOUT;
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET)
    {
      if((I2C_Timeout--) == 0)
      {
      return I2C_FAIL;
      }
    }
   
    I2C_SendData(I2C1, write_Buffer);
}

I2C_Timeout = I2C_TIMEOUT;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF) == RESET)
{
    if((I2C_Timeout--) == 0)
    {
      return I2C_FAIL;
    }
}

return I2C_OK;
}

沐紫 发表于 2014-2-27 13:07:51

回复:【STM32F030开发日志/评测/笔记】+(2)STM32F0处理器I2C实例(操作BMP085气压传感器)

继续阅读原创汇总:
STM32F030探索套件开发日志,中文教程,使用问答80篇

asd1202 发表于 2014-2-28 16:17:54

回复:【STM32F030开发日志/评测/笔记】+(2)STM32F0处理器I2C实例(操作BMP085气压传感器)

帮了大忙了:L

beille 发表于 2014-3-5 11:27:27

RE:【STM32F030开发日志/评测/笔记】+(2)STM32F0处理器I2C实例(操作BMP085气压传感器)

请问有关I2C中断主从收发,能不能讲解指点一下呀?

swustlx86 发表于 2014-4-18 09:47:19

RE:【STM32F030开发日志/评测/笔记】+(2)STM32F0处理器I2C实例(操作BMP085气压传感器)

谢谢分享

cadillacxlr 发表于 2014-5-5 14:02:34

RE:【STM32F030开发日志/评测/笔记】+(2)STM32F0处理器I2C实例(操作BMP085气压传感器)

谢谢分享,学习一下

youyou202 发表于 2014-8-23 12:44:46

回复:【STM32F030开发日志/评测/笔记】+(2)STM32F0处理器I2C实例(操作BMP085气压传感器)

硬件I2C不需要管SCL,SDA的时序问题吗

boringtime 发表于 2015-1-7 21:46:31

顶顶顶顶顶顶顶顶顶顶顶顶顶顶

lkl0305 发表于 2015-1-9 09:41:54

youyou202 发表于 2014-8-23 12:44
硬件I2C不需要管SCL,SDA的时序问题吗

硬件I2C使用片内外设发送时序,当然你还是要对I2C时序非常清楚,片内外设在发送数据时,不同的时间会置不同的标志位,编程通过判断标志位的状态就来决定下一步的工作。

nomoreheracles 发表于 2015-1-9 10:17:37

学习了,可以看看!
页: [1] 2 3 4 5 6 7
查看完整版本: 【STM32F030开发日志/评测/笔记】+(2)STM32F0处理器I2C实例(...