STM32 模拟I2C 读取BH1750光照传感器数据

BH1750为光照强度传感器,可测量当前环境下光强度。VCC支持3.3V供电,通过I2C协议与STM32通信。

BH1750可直接过开发板相连。

以下代码,经过测量,稳定可用。

i2c.c文件中的内容如下:
/* 配置模拟I2C使用的GPIO */
/* PC6配置为SDA,PC7配置为SCL */
void I2C_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStr;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
    GPIO_InitStr.GPIO_Mode = GPIO_Mode_Out_OD;//开漏输出
    GPIO_InitStr.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
    GPIO_InitStr.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC,&GPIO_InitStr);
    /* 给一个停止信号,复位I2C总线上所有设备到待机模式  */
    GPIO_ResetBits(GPIOC,GPIO_Pin_6);
    GPIO_ResetBits(GPIOC,GPIO_Pin_7);
}

/* 主机产生一个起始信号 */
/* SCL为高电平时,SDA由高电平向低电平跳变,产生一个起始信号 */
void I2C_Start(void)
{

   /* 主机产生起始信号 */
    GPIO_SetBits(GPIOC,GPIO_Pin_6);
    GPIO_SetBits(GPIOC,GPIO_Pin_7);
    delay_us(5);
    GPIO_ResetBits(GPIOC,GPIO_Pin_6);
    /* 主机准备发送数据 */
    delay_us(5);
    GPIO_ResetBits(GPIOC,GPIO_Pin_7);
    delay_us(5);
}
/* 主机产生一个停止信号 */
/* SCL为高电平时,SDA由低电平向高电平跳变,产生一个停止信号  */
void I2C_Stop(void)
{
    
    GPIO_ResetBits(GPIOC,GPIO_Pin_6);
    GPIO_SetBits(GPIOC,GPIO_Pin_7);
    delay_us(5);
    GPIO_SetBits(GPIOC,GPIO_Pin_6);
}

/* 主机发送一个ACK给从机 */
void I2C_SendACK(void)
{

   /* 主机产生一个ACK信号 */
    GPIO_ResetBits(GPIOC,GPIO_Pin_6);
    delay_us(5);
    GPIO_SetBits(GPIOC,GPIO_Pin_7);
    delay_us(5);
    /*  为下一次发送做准备 */
    GPIO_ResetBits(GPIOC,GPIO_Pin_7);
    delay_us(5);
    GPIO_SetBits(GPIOC,GPIO_Pin_6);
}

/* 主机发送NCAK信号给从机 */
void I2C_SendNAK(void)
{

   /* 主机产生一个NACK信号 */
    GPIO_SetBits(GPIOC,GPIO_Pin_6);
    delay_us(5);
    GPIO_SetBits(GPIOC,GPIO_Pin_7);
    delay_us(5);
    /* 为下一次发送作准你 */
    GPIO_ResetBits(GPIOC,GPIO_Pin_7);
    delay_us(5);
}

/* 主机获取从机发送的ACK信号 */
/* 返回1表示获取到了ACK信号 */
int I2C_WaitACK(void)
{
    int ack;
    GPIO_SetBits(GPIOC,GPIO_Pin_6);//主机将SDA置高
    delay_us(5);
    GPIO_SetBits(GPIOC,GPIO_Pin_7);//之前SCL为低电平,现在将SCL置高后,主机去读取SDA的数据
    delay_us(5);
    ack = GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_6);//若SDA为低电平,表示从机发送了一个ACK给主机
    GPIO_ResetBits(GPIOC,GPIO_Pin_7);//获取信号后切记要将SCL置低,否则容易出错
    if (ack == 0)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

/* STM32(主机)向BH1750(从机)发送一个字节的数据,并等待BH1750返回一个ACK */
/* 如果函数返回值为1,表示数据发送成功,BH1750返回了一个ACK给主机;反之数据发送失败  */
/* 从最高位开始发送  */
int I2C_SendByte(unsigned char byte)
{
    int i;
    
    for (i = 0; i < 8; i++)
    {
        if (byte & 0x80)
        {
            GPIO_SetBits(GPIOC,GPIO_Pin_6);
        }
        else
        {
            GPIO_ResetBits(GPIOC,GPIO_Pin_6);
        }
        delay_us(5);
        GPIO_SetBits(GPIOC,GPIO_Pin_7);
        delay_us(5);
        GPIO_ResetBits(GPIOC,GPIO_Pin_7);
        if (i == 7)
        {
            GPIO_SetBits(GPIOC,GPIO_Pin_6);
        }
        delay_us(5);
        byte <<= 1;
    }
    
    return I2C_WaitACK();
}

/* STM32(主机)从BH1750读取一个字节的数据 */
/* 读取的第一个bit是最高位 */
unsigned char I2C_ReadByte(void)
{
    unsigned char result = 0;
    unsigned char data;
    int i;
    for (i = 0; i < 8; i++)
    {
        data = 0;
        GPIO_SetBits(GPIOC,GPIO_Pin_7);
        delay_us(5);
        data = GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_6);
        GPIO_ResetBits(GPIOC,GPIO_Pin_7);
        delay_us(5);
        data <<= (7 - i);
        result |= data;
    }
    return result;
}

bh1750.h文件内容如下:

#define ADDR 0x23   //0100011  ADDR = 'L'
#define BH_WRITEADDR   0x46    //01000110  BH1750写地址
#define BH_READADDR    0x47    //01000111  BH1750读地址
#define BH_POWEROFF    0x00    //0000_0000断电
#define BH_POWERON     0x01    //0000_0001 BH1750上电,等待测量指令
#define BH_RESET       0x07    //0000_0111 重置
#define BH_MODE_H      0x10    //连续H分辨率模式,精度为1x,测量时间为120ms,一般不超过180ms。

#define INTENSITY_WEAK    0  
#define INTENSITY_STRONG  1 

typedef struct _BH1750_STRUCT
{
    volatile int open;
    volatile int light_intensity; 
} BH1750_STRUCTURE;

extern BH1750_STRUCTURE BH1750_Str;
void BH1750_Init(void);
void vTask_BH1750( void * pvParameters );

bh1750.c文件中的内容如下:

BH1750_STRUCTURE BH1750_Str = {0};


/*BH1750的ADDR引脚接到STM32的PC12上 */
/* 根据参考手册,ADDR为低电平时,BH1750的7位地址为0100011b */
static void BH1750_ADDR_Set(void)
{
    GPIO_InitTypeDef GPIO_InitStr;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
    GPIO_InitStr.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStr.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStr.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC,&GPIO_InitStr);
    GPIO_ResetBits(GPIOC,GPIO_Pin_12);
}

static void BH1750_PowerOn(void)
{
    I2C_Start();
    I2C_SendByte(BH_WRITEADDR);
    I2C_SendByte(BH_POWERON);
    I2C_Stop();
}

static void BH1750_PowerOff(void)
{
    I2C_Start();
    I2C_SendByte(BH_WRITEADDR);
    I2C_SendByte(BH_POWEROFF);
    I2C_Stop();
}

static void BH1750_Reset(void)
{
    I2C_Start();
    I2C_SendByte(BH_WRITEADDR);
    I2C_SendByte(BH_RESET);
    I2C_Stop();
}

/* 设置BH1750的模式 为: 连续H分辨率模式 */
/* 返回0表示设置成功,否则失败  */
static int BH1750_Set_Mode(void)
{
    I2C_Start();
    if (I2C_SendByte(BH_WRITEADDR) == 0)
    {
        return 1;
    }
    
    if (I2C_SendByte(BH_MODE_H) == 0)
    {
        return 1;
    }
    
    I2C_Stop();
    return 0;
}

void BH1750_Init(void)
{
    I2C_GPIO_Init();
    BH1750_ADDR_Set();
    BH1750_PowerOn();
    BH1750_Reset();
    BH1750_Set_Mode();
}

/* 读取测量结果 */
static unsigned short BH1750_Read_Result(void)
{
    unsigned short result = 0;
    unsigned char data;

    I2C_Start();
    if (I2C_SendByte(BH_READADDR) == 0)
    {
        return 1;
    }
    data = I2C_ReadByte();
    result = data;
    result <<= 8;
    
    I2C_SendACK();
    data = I2C_ReadByte();
    result += data;
    
    I2C_SendNAK();
    I2C_Stop();
    result /= 1.2;
        
    return result;
}

/* 业务处理*/
void vTask_BH1750( void * pvParameters )
{
    unsigned int result;
    #if LOG_OPEN
    char s[20];
    #endif

    while (1)
    {
        if ( BH1750_Str.open != OPEN ) 
        {
            taskYIELD();
            continue;
        }
        result = 0;
        result = BH1750_Read_Result();
        
        if (result < 100) //
        {
            if ( BH1750_Str.light_intensity != INTENSITY_WEAK )
            {
                BH1750_Str.light_intensity = INTENSITY_WEAK;
            }
        }
        else //
        {
            if ( BH1750_Str.light_intensity != INTENSITY_STRONG )
            {
                BH1750_Str.light_intensity = INTENSITY_STRONG;
            }
        }
#if LOG_OPEN
        my_itoa(result,s);
        Usart_SendString(USART1,"BH1750 Result is ");        
        Usart_SendString(USART1,s);        
        vTaskDelay(500/portTICK_RATE_MS);//防止频繁打印,冲死串口
#endif
        vTaskDelay(100/portTICK_RATE_MS);//加一个延时,没必要太勤劳
//    taskYIELD();
    }
}

void BH1750_Close(void)
{
    BH1750_Str.open = CLOSE;
    BH1750_Str.light_intensity = INTENSITY_STRONG;
    BH1750_PowerOff();
}

 

 

你可能感兴趣的:(STM32 模拟I2C 读取BH1750光照传感器数据)