stm32f4 rt-thread studio IO模拟IIC

因项目需要控制其他芯片进行ADC采集,协议用的是IIC,需要用到IO模拟IIC,特此记录,已经过测试,但由于个人水平不够导致芯片使用不规范没有采集到合理的数值(ADS7830)。本篇为个人编程记录,其中也掺杂自己的理解,可能有错误之处,敬请斧正!!

由于IIC是通过SDA进行单线通信,所以使用过程中需要重新配置SDA引脚的输入输出模式,实现数据的收发。SDA和SCL线处于空闲状态时候(高电平),SDA线先拉低,SCL线后拉低表示起始信号;SDA线先拉高,SCL线后拉高表示停止信号,其间,SCL拉低的时候SDA线准备数据(0/1),在SCL线拉高时表示SDA的数据有效,接收应答前需要将SDA的引脚设置为输入模式,接收之后恢复成输出模式。

宏定义:

#define GPIO_SCL_PIN      GET_PIN(F,1)
#define GPIO_SDA_PIN      GET_PIN(F,0)

#define I2C_SCL(x)      rt_pin_write(GPIO_SCL_PIN, x)
#define I2C_SDA(x)      rt_pin_write(GPIO_SDA_PIN, x)

#define RD_I2C_SDA      rt_pin_read(GPIO_SDA_PIN)

#define SW_SCL_DLY        (300)  

io配置:

void I2C_SDA_IN(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
}

void I2C_SDA_OUT(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
}

void I2C_Init(void)
{
    __HAL_RCC_GPIOF_CLK_ENABLE();
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

    HAL_GPIO_WritePin(GPIOF,GPIO_PIN_0, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOF,GPIO_PIN_1, GPIO_PIN_SET);
}

IIC用到的延时采用的是硬延时__NOP()

void I2C_DELAY(uint32_t count)
{
    for(; count > 0; count --)
    {
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
    }
}

重要的是模拟出信号跳变,使用IO口模拟出起始、停止信号

void I2C_START(void)
{
    I2C_SDA(1);
    I2C_DELAY(SW_SCL_DLY >> 1);
    I2C_SCL(1);
    I2C_DELAY(SW_SCL_DLY);
    I2C_SDA(0);
    I2C_DELAY(SW_SCL_DLY);
    I2C_SCL(0);
}

void I2C_STOP(void)
{
    I2C_SCL(0);
    I2C_SDA(0);
    I2C_DELAY(SW_SCL_DLY);
    I2C_SCL(1);
    I2C_DELAY(SW_SCL_DLY);
    I2C_SDA(1);
    I2C_DELAY(SW_SCL_DLY);  //增加的延时
}

应答相关函数:

uint8_t I2C_WAIT_ACK(void)
{
    uint8_t Wait_cnt = 255;
    I2C_SCL(0);
    I2C_SDA_IN();
    I2C_SDA(0);
    I2C_SCL(1);   //产生第九个时钟脉冲,用于接收应答
    while(RD_I2C_SDA != 0){
        Wait_cnt--;
        if(Wait_cnt == 0){
            break;
        }
    }
    I2C_SCL(0);
    I2C_SDA_OUT();
    if(Wait_cnt == 0)
    {
        I2C_STOP();
    }
    return Wait_cnt;
}

void I2C_ACK(void)
{
    I2C_SCL(0);
    I2C_SDA(0);//发送低电平,响应从机
    I2C_DELAY(SW_SCL_DLY);
    I2C_SCL(1);
    I2C_DELAY(SW_SCL_DLY);
    I2C_SCL(0);
}

void I2C_NOT_ACK(void)
{
    I2C_SCL(0);
    I2C_SDA(1);//发送低电平,响应从机
    I2C_DELAY(SW_SCL_DLY);
    I2C_SCL(1);
    I2C_DELAY(SW_SCL_DLY);
    I2C_SCL(0);
}

IIC的读写函数:

uint8_t I2C_WRITE_BYTE(uint8_t dat)
{
    uint8_t i;
    I2C_DELAY(SW_SCL_DLY);
    for(i = 0;i < 8;i++){
        I2C_DELAY(W_SCL_DLY);
        if(dat & 0x80){
            I2C_SDA(1);
        }else{
            I2C_SDA(0);
        }
        dat <<= 1;
        I2C_DELAY(SW_SCL_DLY);
        I2C_SCL(1);
        I2C_DELAY(SW_SCL_DLY);
        I2C_SCL(0);
    }
    i = I2C_WAIT_ACK();

    return i;
}

uint8_t I2C_READ_BYTE(uint8_t ack)
{
    uint8_t dat = 0;
    I2C_SCL(0);
    I2C_SDA_IN();
    I2C_SDA(0);
    I2C_DELAY(SW_SCL_DLY >> 1);
    for(uint8_t i = 0;i < 8;i ++){
        I2C_SCL(1);
        I2C_DELAY(SW_SCL_DLY);
        if(RD_I2C_SDA != 0){
            dat |= 0x01;
            dat <<= 1;
        }
        I2C_SCL(0);
        I2C_DELAY(SW_SCL_DLY);
    }
    I2C_SDA_OUT();
    if(ack != 0){
        I2C_ACK();
    }else{
       I2C_NOT_ACK();
    }
    return dat;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值