ARM技术william hill官网
直播中

李娜

7年用户 1648经验值
私信 关注
[经验]

如何利用硬件IIC去读取SHT40温湿度传感器呢?

准备工作

拿到板子以后,LED闪烁正常,说明板子正常。

由于以前用的MDK开发环境,本次想要改用IAR的环境,此处需要添加支持包,首先要把这个后缀名改为exe

bVbI3X.png

另外, 必须以管理员身份运行 ,能正确识别到本机IAR的安装路径才算成功,否则安装是不成功的。

bVbI3Y.png

另外这个板子配置串口也有些小波折

硬件连接

image.png

如图所示,iic的通信只需要SDA和SCL两根线。

IIC通信过程由开始、结束、发送、响应、接收五个部分构成。

1、(在发送、接收数据的时候)当SCL为高电平时,SDA线不允许变化;当SCL线为低电平时,SDA线可以任意0、1变化。

2、(在任意时候)只有当SCL为高电平时,IIC威廉希尔官方网站 才对SDA线上的电平(0或者1)进行记录,当SCL线为低电平时,无论SDA是高还是低,IIC威廉希尔官方网站 都不对SDA进行采样。

空闲状态:SDA和SCL都为高

开始和停止:

开始信号:当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平。

停止信号:当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号

应答:

发送器每发送一个字节,就在时钟脉冲9期间释放数据先,由接收器反馈一个应答信号。

应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。

对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间位稳定的低电平。

如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。

image.png

软件实现

通过参考demo,我们可以很快的试用iic,我们使用PB8 和PB9来做scl和sdl

iic配置的代码如下

时钟配置
/* enable GPIOB clock */
    rcu_periph_clock_enable(RCU_GPIOB);
    /* enable I2C1 clock */
    rcu_periph_clock_enable(RCU_I2C1);

GPIO配置

/* I2C0 and I2C1 GPIO ports */
    /* connect PB8 to I2C0_SCL */
    gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_8);
    /* connect PB9 to I2C0_SDA */
    gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_9);

iic 配置

/* configure GPIO pins of I2C0 */
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_8);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
    
        /* configure I2C clock */
    i2c_clock_config(I2C0, 100000, I2C_DTCY_2);
    /* configure I2C address */
    i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, I2C0_SLAVE_ADDRESS7);
    /* enable I2C0 */
    i2c_enable(I2C0);
    /* enable acknowledge */
    i2c_ack_config(I2C0, I2C_ACK_ENABLE);

上述配置好了以后,我们就能正常使用i2c了,我们需要对原始api进行一些简单的封装。

void I2C_LeaderWrite(uint16_t followerAddress, , uint8_t targetAddress, uint8_t *txBuff,
                     uint8_t numBytes) {
    /* wait until I2C bus is idle */
    while (i2c_flag_get(I2C0, I2C_FLAG_I2CBSY))
        ;
    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C0);
    /* wait until SBSEND bit is set */
    while (!i2c_flag_get(I2C0, I2C_FLAG_SBSEND))
        ;
    /* send slave address to I2C bus */
    i2c_master_addressing(I2C0, followerAddress, I2C_TRANSMITTER);
    /* wait until ADDSEND bit is set */
    while (!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND))
        ;
    /* clear ADDSEND bit */
    i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND);
    /* wait until the transmit data buffer is empty */
    while (!i2c_flag_get(I2C0, I2C_FLAG_TBE))
        ;

    for (i = 0; i < numBytes; i++) {
        /* data transmission */
        i2c_data_transmit(I2C0, txBuff[i]);
        /* wait until the TBE bit is set */
        while (!i2c_flag_get(I2C0, I2C_FLAG_TBE))
            ;
    }
    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(I2C0);
    /* wait until stop condition generate */
    while (I2C_CTL0(I2C0) & 0x0200)
        ;
}
void I2C_LeaderRead(uint16_t followerAddress, uint8_t targetAddress, uint8_t *rxBuff,
                    uint8_t numBytes) {
    /* wait until I2C bus is idle */
    while (i2c_flag_get(I2C0, I2C_FLAG_I2CBSY))
        ;

    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C0);

    /* wait until SBSEND bit is set */
    while (!i2c_flag_get(I2C0, I2C_FLAG_SBSEND))
        ;

    /* send slave address to I2C bus */
    i2c_master_addressing(I2C0, followerAddress, I2C_TRANSMITTER);

    /* wait until ADDSEND bit is set */
    while (!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND))
        ;

    /* clear the ADDSEND bit */
    i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND);

    /* wait until the transmit data buffer is empty */
    while (SET != i2c_flag_get(I2C0, I2C_FLAG_TBE))
        ;

    /* enable I2C0*/
    i2c_enable(I2C0);

    /* send the EEPROM's internal address to write to */
    i2c_data_transmit(I2C0, targetAddress);

    /* wait until BTC bit is set */
    while (!i2c_flag_get(I2C0, I2C_FLAG_BTC))
        ;

    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C0);

    /* wait until SBSEND bit is set */
    while (!i2c_flag_get(I2C0, I2C_FLAG_SBSEND))
        ;

    /* send slave address to I2C bus */
    i2c_master_addressing(I2C0, followerAddress, I2C_RECEIVER);

    /* wait until ADDSEND bit is set */
    while (!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND))
        ;

    /* clear the ADDSEND bit */
    i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND);

    /* while there is data to be read */
    for (int i = 0; i < numBytes; i++) {
        /* code */

        /* read a data from I2C_DATA */
        rxBuff[i++] = i2c_data_receive(I2C0);
        /* send a stop condition */
        i2c_stop_on_bus(I2C0);
    }

    /* wait until the stop condition is finished */
    while (I2C_CTL0(I2C0) & 0x0200)
        ;

    /* enable acknowledge */
    i2c_ack_config(I2C0, I2C_ACK_ENABLE);

    i2c_ackpos_config(I2C0, I2C_ACKPOS_CURRENT);
}

如上,我们的MCU就能作为主机来发送和接受了
查阅sht40的手册可以得到读取的命令以及转换关系

image.png

主函数代码如下

int main(void)
{
    my_iic_init():
      
    init_sensor_sht40();
  
    while(1) {

        delay_1ms(1000);
        get_sensor_sht40(&temp,&hum);
        printf ("get T:%d, H: %d",temp,hum);

    }
}

结果定时采集当前的环境的数据。

image.png

原作者:兆易创新GD32 MCU 烟花易冷

更多回帖

发帖
×
20
完善资料,
赚取积分