参考文章:https://blog.csdn.net/qwer012345678/article/details/79866033。
STM32F030的硬件I2C程序,整理一下如下,注意使用的时候i2c器件地址的问题,文章最后有说明。
i2c_hard.c 文件:
#include "i2c_hard.h"
static int I2C_Timeout = 0;
void i2c1_port_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
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_PinSource6, GPIO_AF_1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_1);
}
void i2c1_init(void)
{
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 = 0x00;
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);
}
/**
* @brief 从I2C1总线上的某一器件的某一起始地址中读取一定字节的数据到数组中
* @param driver_Addr:I2C器件地址
* @param start_Addr:起始字节地址
* @param number_Bytes:要读取的字节数量(小于一页)
* @param read_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[read_Num] = 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;
}
/**
* @brief 从I2C1的总线上的某一器件的某一起始地址中读取一定字节的数据到数组中
* @param driver_Addr:I2C器件地址
* @param start_Addr:起始字节地址
* @param number_Bytes:要读取的字节数量(小于一页)
* @param write_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[write_Num]);
}
I2C_Timeout = I2C_TIMEOUT;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF) == RESET)
{
if((I2C_Timeout--) == 0)
{
return I2C_FAIL;
}
}
return I2C_OK;
}
i2c_hard.h 文件:
#ifndef __I2C_HARD_H__
#define __I2C_HARD_H__
#include "stm32f0xx.h"
#include "delay.h"
#include "USART1.h"
#include "bsp.h"
#define I2C_TIMEOUT 2000
typedef enum
{
I2C_OK = 0,
I2C_FAIL
}I2C_Status;
void i2c1_port_init(void);
void i2c1_init(void);
I2C_Status I2C1_Read_NBytes(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *read_Buffer);
I2C_Status I2C1_Write_NBytes(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *write_Buffer);
#endif
但是注意,这里的 I2C1_Read_NBytes 和 I2C1_Write_NBytes 函数中的 driver_Addr 不是 7位格式的,需要将I2C器件的硬件地址左移1位,这也是我被坑之后用逻辑分析仪测出来的,下图为地址左移后抓取的正确波形:
上述波形对应的程序:
I2C1_Write_NBytes(0x68 << 1,0x75,1,&data); //MPU6050硬件地址0x68