stm32实现IIC读写

IIC.c

c 复制代码
#include "Driver_I2C2.h"
#include "Delay.h"

#define I2C_DELAY Delay_us(10)


/**
 * @description: 初始化
 * @return {*}
 */
void Driver_I2C2_Init(void)
{
    /*
        PB10->SCL
        PB11->SDA
            开漏输出: 既可以用于输出也可以输入. 外界要有上拉电阻.
                    用于输入的时候,最好先输出一个1,把线的控制权交给外界.

            MODE=11 CNF=01

     */
    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;

    GPIOB->CRH |= (GPIO_CRH_MODE10 | GPIO_CRH_MODE11 | GPIO_CRH_CNF10_0 | GPIO_CRH_CNF11_0);
    GPIOB->CRH &= ~(GPIO_CRH_CNF10_1 | GPIO_CRH_CNF11_1);
}

/**
 * @description: 起始信号
 * @return {*}
 */
void Driver_I2C2_Start(void)
{
    /* 1. 拉高sda和scl */
    SDA_HIGH;
    SCL_HIGH;
    /* 2. 延时 */
    I2C_DELAY;
    /* 3. 拉低sda */
    SDA_LOW;
    /* 4. 延时 */
    I2C_DELAY;
}

/**
 * @description: 停止信号
 * @return {*}
 */
void Driver_I2C2_Stop(void)
{
    /* 1. scl 拉高 sda拉低 */
    SCL_HIGH;
    SDA_LOW;
    /* 2. 延时 */
    I2C_DELAY;
    /* 3. 拉高sda */
    SDA_HIGH;
    /* 4.  延时 */
    I2C_DELAY;
}

/**
 * @description: 接收方产生应答信号
 */
void Driver_I2C2_Ack(void)
{
    /* 1. 拉高sda和拉低scl */
    SDA_HIGH;
    SCL_LOW;
    /* 2. 延时 */
    I2C_DELAY;
    /* 3. sda拉低 */
    SDA_LOW;
    /* 4. 延时 */
    I2C_DELAY;
    /* 5. scl拉高 */
    SCL_HIGH;
    /* 6. 延时 */
    I2C_DELAY;
    /* 7. scl拉低 */
    SCL_LOW;
    /* 8. 延时 */
    I2C_DELAY;
    /* 9. sda 拉高 */
    SDA_HIGH;
    /* 10. 延时 */
    I2C_DELAY;
}

/**
 * @description: 接收方产生非应答信号
 */
void Driver_I2C2_NAck(void)
{
    /* 1. 拉高sda和拉低scl */
    SDA_HIGH;
    SCL_LOW;
    /* 2. 延时 */
    I2C_DELAY;

    /* 3. scl拉高 */
    SCL_HIGH;

    /* 4. 延时 */
    I2C_DELAY;

    /* 5. scl拉低*/
    SCL_LOW;

    /* 6. 延时 */
    I2C_DELAY;
}

/**
 * @description: 等待接收方法的应答
 * @return {*} 应答或非应答
 */
uint8_t Driver_I2C2_WaitAck(void)
{
    /* 1. 把sda拉高, sda的主动权交给对方(e2prom芯片) */
    SDA_HIGH;

    /* 2. scl拉低  */
    SCL_LOW;
    /* 3. 延时 */
    I2C_DELAY;
    /* 4. 拉高scl */
    SCL_HIGH;
    /* 5. 延时 */
    I2C_DELAY;
    /* 6. 读取sda的电平 */
    uint8_t ack = ACK;
    if (READ_SDA)
    {
        ack = NACK;
    }
    /* 7. 拉低scl */
    SCL_LOW;

    /* 8. 延时 */
    I2C_DELAY;
    return ack;
}

/**
 * @description: 发送一个字节的数据
 * @param {uint8_t} byte 要发送的字节
 */
void Driver_I2C_SendByte(uint8_t byte)
{
    for (uint8_t i = 0; i < 8; i++)
    {
        /* 1. sda和scl 拉低 */
        SDA_LOW;
        SCL_LOW;

        I2C_DELAY;

        /* 2. 向sda写数据 */
        if (byte & 0x80)
        {
            SDA_HIGH;
        }
        else
        {
            SDA_LOW;
        }
        I2C_DELAY;

        /* 3. 时钟拉高 */
        SCL_HIGH;

        I2C_DELAY;

        /* 4. 时钟拉低 */
        SCL_LOW;

        I2C_DELAY;

        /* 5. 左移1位, 为下一次发送做准备 */
        byte <<= 1;
    }
}

/**
 * @description: 读一个字节的数据
 * @param {uint8_t} byte 要发送的字节
 */
uint8_t Driver_I2C_ReadByte(void)
{
    uint8_t data = 0;
    for (uint8_t i = 0; i < 8; i++)
    {
        /* 1. 拉低scl */
        SCL_LOW;
        /* 2. 延时 */
        I2C_DELAY;
        /* 3. 拉高scl */
        SCL_HIGH;
        /* 4. 延时 */
        I2C_DELAY;
        /* 5. 读取sda */
        data <<= 1;
        if (READ_SDA)
        {
            data |= 0x01;
        }
        /* 6. 拉低scl */
        SCL_LOW;

        /* 7. 延时 */
        I2C_DELAY;
    }

    return data;
}

IIC.h

c 复制代码
#ifndef __DRIVER_I2C2_H
#define __DRIVER_I2C2_H

#include "Delay.h"
#include "stm32f10x.h"
#include "Driver_USART.h"

#define ACK 0
#define NACK 1

#define SCL_HIGH  (GPIOB->ODR |= GPIO_ODR_ODR10)
#define SCL_LOW  (GPIOB->ODR &= ~GPIO_ODR_ODR10)

#define SDA_HIGH  (GPIOB->ODR |= GPIO_ODR_ODR11)
#define SDA_LOW  (GPIOB->ODR &= ~GPIO_ODR_ODR11)

#define READ_SDA (GPIOB->IDR & GPIO_IDR_IDR11)


void Driver_I2C2_Init(void);

void Driver_I2C2_Start(void);

void Driver_I2C2_Stop(void);

void Driver_I2C2_Ack(void);

void Driver_I2C2_NAck(void);

uint8_t Driver_I2C2_WaitAck(void);

void Driver_I2C_SendByte(uint8_t byte);

uint8_t Driver_I2C_ReadByte(void);

#endif

读写操作

Inf_W24C02.c

c 复制代码
#include "Inf_W24C02.h"

void Inf_W24C02_Init(void)
{
    Driver_I2C2_Init();
}

void Inf_W24C02_WriteByte(uint8_t innerAddr, uint8_t byte)
{
    /* 1. 开始信号 */
    Driver_I2C2_Start();

    /* 2. 发送写地址 */
    Driver_I2C_SendByte(ADDR);
    /* 3. 等待响应 */
    uint8_t ack = Driver_I2C2_WaitAck();
    if (ack == ACK)
    {
        /* 4. 发送内部地址 */
        Driver_I2C_SendByte(innerAddr);
        /* 5. 等待响应 */
        Driver_I2C2_WaitAck();
        /* 6. 发送具体数据 */
        Driver_I2C_SendByte(byte);
        /* 7. 等待响应 */
        Driver_I2C2_WaitAck();
        /* 8. 停止信号 */
        Driver_I2C2_Stop();
    }
    Delay_ms(5);
}

uint8_t Inf_W24C02_ReadByte(uint8_t innerAddr)
{
    /* 1. 起始信号 */
    Driver_I2C2_Start();
    /* 2. 发送一个写地址   假写 */
    Driver_I2C_SendByte(ADDR);
    /* 3. 等待响应 */
    Driver_I2C2_WaitAck();
    /* 4. 发送内部地址 */
    Driver_I2C_SendByte(innerAddr);
    /* 5. 等待响应 */
    Driver_I2C2_WaitAck();
    /* 6. 起始信号 */
    Driver_I2C2_Start();
    /* 7. 发送读地址  真读 */
    Driver_I2C_SendByte(ADDR + 1);
    /* 8. 等待响应 */
    Driver_I2C2_WaitAck();
    /* 9. 读取一个字节 */
    uint8_t byte = Driver_I2C_ReadByte();

    /* 10. 给对方一个非应答 */
    Driver_I2C2_NAck();

    /* 11. 停止信号 */
    Driver_I2C2_Stop();
    return byte;
}

/**
 * @description: 页写入.一次写入多个字节
 * @param {uint8_t} innerAddr
 * @param {uint8_t} *bytes
 * @param {uint8_t} len
 * @return {*}
 */
void Inf_W24C02_WriteBytes(uint8_t innerAddr, uint8_t *bytes, uint8_t len)
{
    /* 1. 开始信号 */
    Driver_I2C2_Start();

    /* 2. 发送写地址 */
    Driver_I2C_SendByte(ADDR);
    /* 3. 等待响应 */
    uint8_t ack = Driver_I2C2_WaitAck();
    if (ack == ACK)
    {
        /* 4. 发送内部地址 */
        Driver_I2C_SendByte(innerAddr);
        /* 5. 等待响应 */
        Driver_I2C2_WaitAck();

        for (uint8_t i = 0; i < len; i++)
        {
            /* 6. 发送具体数据 */
            Driver_I2C_SendByte(bytes[i]);
            /* 7. 等待响应 */
            Driver_I2C2_WaitAck();
        }
        /* 8. 停止信号 */
        Driver_I2C2_Stop();
    }
    Delay_ms(5);
}

/**
 * @description: 一次性读取多个字节的数据
 * @param {uint8_t} innerAddr 起始位置
 * @param {uint8_t} *bytes 存储读到的数据
 * @param {uint8_t} len 读取的字节数
 * @return {*}
 */
void Inf_W24C02_ReadBytes(uint8_t innerAddr, uint8_t *bytes, uint8_t len)
{

    /* 1. 起始信号 */
    Driver_I2C2_Start();
    /* 2. 发送一个写地址   假写 */
    Driver_I2C_SendByte(ADDR);
    /* 3. 等待响应 */
    Driver_I2C2_WaitAck();
    /* 4. 发送内部地址 */
    Driver_I2C_SendByte(innerAddr);
    /* 5. 等待响应 */
    Driver_I2C2_WaitAck();
    /* 6. 起始信号 */
    Driver_I2C2_Start();
    /* 7. 发送读地址  真读 */
    Driver_I2C_SendByte(ADDR + 1);
    /* 8. 等待响应 */
    Driver_I2C2_WaitAck();

    for (uint8_t i = 0; i < len; i++)
    {
        /* 9. 读取一个字节 */
        bytes[i] = Driver_I2C_ReadByte();
        if (i < len - 1)
        {
            Driver_I2C2_Ack();
        }
        else
        {
            Driver_I2C2_NAck();
        }
    }
    /* 11. 停止信号 */
    Driver_I2C2_Stop();
}

void Inf_W24C02_WriteBytesAutoPage(uint8_t innerAddr, uint8_t *bytes, uint8_t len)
{
    // 不需要自动换页
    if ((innerAddr % 16) + len <= 16)
    {
        Inf_W24C02_ReadBytes(innerAddr, bytes, len);
        return;
    }
    // 需要换页处理
    //uint8_t apge = (len - innerAddr % 16) / 16 + 1  ;// 一共需要page页

}

Inf_W24C02.h

c 复制代码
#ifndef __INF_W24C02_H
#define __INF_W24C02_H

#include "Driver_I2C2.h"
#include "string.h"

#define ADDR 0xA0
void Inf_W24C02_Init(void);
void Inf_W24C02_WriteByte(uint8_t innerAddr, uint8_t byte);

uint8_t Inf_W24C02_ReadByte(uint8_t innerAddr);

void Inf_W24C02_WriteBytes(uint8_t innerAddr, uint8_t *bytes, uint8_t len);

void Inf_W24C02_ReadBytes(uint8_t innerAddr, uint8_t *bytes, uint8_t len);

#endif
相关推荐
QQ547176052几秒前
stm32实现回调功能
stm32·单片机·嵌入式硬件
wenchm1 小时前
细说STM32F407单片机轮询方式读写SPI FLASH W25Q16BV
stm32·单片机·嵌入式硬件
委员2 小时前
基于NodeMCU的物联网电灯控制系统设计
单片机·物联网·嵌入式·nodemcu··lu_asr01·gy-302
北国无红豆2 小时前
【CAN总线】STM32的CAN外设
c语言·stm32·嵌入式硬件
单片机学习之路2 小时前
【C语言】结构
c语言·开发语言·stm32·单片机·51单片机
m0_748254093 小时前
STM32--超声波模块(HC—SR04)(标准库+HAL库)
stm32·单片机·嵌入式硬件
南城花随雪。4 小时前
单片机:实现FFT快速傅里叶变换算法(附带源码)
单片机·嵌入式硬件·算法
逝灮4 小时前
【蓝桥杯——物联网设计与开发】基础模块8 - RTC
stm32·单片机·嵌入式硬件·mcu·物联网·蓝桥杯·rtc
LXL_245 小时前
模拟——郑益慧_笔记1_绪论
嵌入式硬件
weixin_4526006910 小时前
串行时钟保持芯片D1380/D1381,低功耗工作方式自带秒、分、时、日、日期、月、年的串行时钟保持芯片,每个月多少天以及闰年能自动调节
科技·单片机·嵌入式硬件·时钟·白色家电电源·微机串行时钟