zoukankan      html  css  js  c++  java
  • MCU模拟IIC读写

    MCU模拟IIC读写,以E2PROM AT24C256为例

    /* 模拟IIC */
    #define EEPROM_WP_Pin                   GPIO_PIN_15
    #define EEPROM_WP_GPIO_Port             GPIOE
    #define WP_GPIO_CLK_ENABLE()            __HAL_RCC_GPIOE_CLK_ENABLE()
    
    #define EEPROM_I2C2_SCL_Pin             GPIO_PIN_10
    #define EEPROM_I2C2_SCL_GPIO_Port       GPIOB
    #define SCL_GPIO_CLK_ENABLE()           __HAL_RCC_GPIOB_CLK_ENABLE()
    
    #define EEPROM_I2C2_SDA_Pin             GPIO_PIN_11
    #define EEPROM_I2C2_SDA_GPIO_Port       GPIOB
    #define SDA_GPIO_CLK_ENABLE()           __HAL_RCC_GPIOB_CLK_ENABLE()
    
    
    #define SCL_EEPROM_H()                  HAL_GPIO_WritePin(EEPROM_I2C2_SCL_GPIO_Port, EEPROM_I2C2_SCL_Pin, GPIO_PIN_SET)
    #define SCL_EEPROM_L()                  HAL_GPIO_WritePin(EEPROM_I2C2_SCL_GPIO_Port, EEPROM_I2C2_SCL_Pin, GPIO_PIN_RESET)
    
    #define SDA_EEPROM_H()                  HAL_GPIO_WritePin(EEPROM_I2C2_SDA_GPIO_Port, EEPROM_I2C2_SDA_Pin, GPIO_PIN_SET)
    #define SDA_EEPROM_L()                  HAL_GPIO_WritePin(EEPROM_I2C2_SDA_GPIO_Port, EEPROM_I2C2_SDA_Pin, GPIO_PIN_RESET)
    
    #define SDA_EEPROM_READ()               HAL_GPIO_ReadPin(EEPROM_I2C2_SDA_GPIO_Port, EEPROM_I2C2_SDA_Pin)
    
    
    
    /* IIC设备常量 */
    #define     EXTEEPROM_HW_ADDRESS     0xA0        // EXTEEPROM地址
    
    #define     AT24C256                 1           //使用AT24C256使能
    #define     AT24C64                  0           //使用AT24C64使能
    
    #if AT24C256
        #define Page_Bite                64
        #define EXTEEPROM_STORAGE_SIZE   0x8000
    #endif
    
    #if AT24C64
        #define Page_Bite                32            //页大小
        #define EXTEEPROM_STORAGE_SIZE   0x2000        //EEPROM大小
    #endif
    
    #define     EEPROM_MAX_WRITE_LEN     1024        // 最大写入长度1024=1K
    
    
    
    unsigned char HAL_ReadDataFromEEPROM(unsigned short eeprom_add, unsigned short len, unsigned char *ram_add);
    unsigned char HAL_WriteDataToEEPROM(unsigned short eeprom_add, unsigned short len, unsigned char *ram_add);
    unsigned char ReadDataFromExtStoreWithCS(unsigned short Addr, unsigned short Len, unsigned char *DataBuff);
    unsigned char WriteDataToExtStoreWithCS(unsigned short Addr, unsigned short Len, unsigned char *DataBuff);
    void MX_GPIO_Init(void)
    {
      GPIO_InitTypeDef GPIO_InitStruct;
      
      /* GPIO Ports Clock Enable */
      WP_GPIO_CLK_ENABLE();
      SCL_GPIO_CLK_ENABLE();
      SCL_GPIO_CLK_ENABLE();
      
      /*eeprom*/
      GPIO_InitStruct.Pin = EEPROM_WP_Pin;
      GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;        /*推挽*/
      GPIO_InitStruct.Pull = GPIO_PULLDOWN;
      GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
      HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
      HAL_GPIO_WritePin(EEPROM_WP_GPIO_Port, EEPROM_WP_Pin, GPIO_PIN_RESET);
    
      GPIO_InitStruct.Pin = EEPROM_I2C2_SCL_Pin;
      GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;        /*开漏*/
      GPIO_InitStruct.Pull = GPIO_PULLUP;
      GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
      HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
      HAL_GPIO_WritePin(EEPROM_I2C2_SCL_GPIO_Port, EEPROM_I2C2_SCL_Pin, GPIO_PIN_SET);
    
      GPIO_InitStruct.Pin =  EEPROM_I2C2_SDA_Pin;
      GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;       /*开漏*/
      GPIO_InitStruct.Pull = GPIO_PULLUP;
      GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
      HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
      HAL_GPIO_WritePin(EEPROM_I2C2_SDA_GPIO_Port, EEPROM_I2C2_SDA_Pin, GPIO_PIN_SET);
    }
    
    /*******************************************************************************
    * 函数名称: HAL_WriteWPState
    * 函数功能: 设置写保护状态 -->针对eeprom
    * 输入参数: 使能,静止
    * 输出参数: 无
    * 返 回 值: 无
    *******************************************************************************/
    void HAL_WriteWPState(GPIO_PinState PinState)
    {
        HAL_GPIO_WritePin(EEPROM_WP_GPIO_Port,EEPROM_WP_Pin,PinState);
    }
    
    
    static void EEPROM_I2C_delay(void) //写引脚延时
    {
        volatile uint32_t i = 40; //这里可以优化速度 ,经测试最低到5还能写入
        for(i=0; i<40; i++)
        {
            ;
        }
    }
    
    void udelay(uint32_t usec) //usec延时 可以优化
    {
        volatile  uint32_t  i;
    
        for(i=(usec*4); i!=0; i--)
        {
            asm("NOP");
            asm("NOP");
            asm("NOP");
            asm("NOP");
            asm("NOP");
            asm("NOP");
            asm("NOP");
            asm("NOP");
            asm("NOP");
            asm("NOP");
            asm("NOP");
        }
    }
    
    static uint8 EEPROM_I2C_Start(void)
    {
        SDA_EEPROM_H();
        EEPROM_I2C_delay();
        SCL_EEPROM_H();
        EEPROM_I2C_delay();
        SDA_EEPROM_L();
        EEPROM_I2C_delay();
        SCL_EEPROM_L();
        EEPROM_I2C_delay();
    }
    
    static void EEPROM_I2C_Stop(void)
    {
        SCL_EEPROM_L();
        EEPROM_I2C_delay();
        SDA_EEPROM_L();
        EEPROM_I2C_delay();
        SCL_EEPROM_H();
        EEPROM_I2C_delay();
        SDA_EEPROM_H();
        EEPROM_I2C_delay();
    }
    
    static void EEPROM_I2C_Ack(void)
    {
        SDA_EEPROM_L();
        EEPROM_I2C_delay();
        SCL_EEPROM_H();
        EEPROM_I2C_delay();
        SCL_EEPROM_L();
        EEPROM_I2C_delay();
        SDA_EEPROM_H();
        EEPROM_I2C_delay();
    }
    
    static void EEPROM_I2C_NoAck(void)
    {
        SDA_EEPROM_H();
        EEPROM_I2C_delay();
        SCL_EEPROM_H();
        EEPROM_I2C_delay();
        SCL_EEPROM_L();
        EEPROM_I2C_delay();
    }
    
    static uint8 EEPROM_I2C_WaitAck(void)   //返回为:=1有ACK
    {
    
        SCL_EEPROM_H();
        EEPROM_I2C_delay();
        SCL_EEPROM_L();
        EEPROM_I2C_delay();
        return 1;
    }
    
    static void EEPROM_I2C_SendByte(uint8_t SendByte) //数据从高位到低位//
    {
    
        uint8 i = 8;
        while(i--)
        {
            if(SendByte&0x80)       //1000 0000
                SDA_EEPROM_H();
            else
                SDA_EEPROM_L();
            SendByte<<=1;
            EEPROM_I2C_delay();
            SCL_EEPROM_H();
            EEPROM_I2C_delay();
            SCL_EEPROM_L();
            EEPROM_I2C_delay();
        }
    
    }
    
    static uint8 EEPROM_I2C_ReceiveByte(void)  //数据从高位到低位//
    {
    
        uint8 i = 8;
        uint8 ReceiveByte = 0;
    
        while(i--)
        {
            ReceiveByte<<=1;       //0000 0000 
            SCL_EEPROM_H();
            EEPROM_I2C_delay();
            if(SDA_EEPROM_READ())
            {
                ReceiveByte|=0x01;//0000 0001 移位8次
            }
            SCL_EEPROM_L();
            EEPROM_I2C_delay();
        }
        return ReceiveByte;
    
    }
    
    /*******************************************************************************
    * 函数名称: ReadbytefromEEPROM
    * 函数功能: 读从设备指定地址指定长度字节
    * 输入参数: slave_addr:从设备地址
                addr:设备内部地址,读字节的起始地址
                len:读字节长度
    * 输出参数: *data:接收数据指针
    * 返 回 值: 1 -->读结束
    *******************************************************************************/
    static uint8 ReadbytefromEEPROM(uint8_t slave_addr, uint16_t addr, uint8_t *data, uint16_t len)
    {
        unsigned int i;
    
        EEPROM_I2C_Start();
        EEPROM_I2C_SendByte(slave_addr);
        if(EEPROM_I2C_WaitAck() != 1)
        {
            //return IIC_ERR_WADDR;
        }
        EEPROM_I2C_SendByte(addr>>8);
        if(EEPROM_I2C_WaitAck() != 1)
        {
            //return IIC_ERR_WADDR;
        }
        EEPROM_I2C_SendByte(addr);
        if(EEPROM_I2C_WaitAck() != 1)
        {
            //return IIC_ERR_WADDR;
        }
        EEPROM_I2C_Start();
        EEPROM_I2C_SendByte(slave_addr|0x01);
        if(EEPROM_I2C_WaitAck() != 1)
        {
            //return IIC_ERR_WADDR;
        }
        for(i = 0; i < len - 1; i++)
        {
            data[i] = EEPROM_I2C_ReceiveByte();
            EEPROM_I2C_Ack();
        }
        data[i] = EEPROM_I2C_ReceiveByte();
        EEPROM_I2C_NoAck();
        EEPROM_I2C_Stop();
        return 1;
    }
    
    /*******************************************************************************
    * 函数名称: ReadbytefromEEPROM
    * 函数功能: 读从设备指定地址指定长度字节
    * 输入参数: slave_addr:从设备地址
                addr:设备内部地址,写字节的起始地址
                len:要写的字节长度
                *data:要写的数据
    * 输出参数: 
    * 返 回 值: 1 -->写结束
    *******************************************************************************/
    static uint8 WritebytetoEEPROM(uint8_t slave_addr, uint16_t addr, uint8_t *data, uint16_t len)
    {
        unsigned int i;
    
        EEPROM_I2C_Start();
        EEPROM_I2C_SendByte(slave_addr);
        if(EEPROM_I2C_WaitAck() != 1)
        {
            //return IIC_ERR_WADDR;
        }
        EEPROM_I2C_SendByte(addr>>8);
        if(EEPROM_I2C_WaitAck() != 1)
        {
            //return IIC_ERR_WADDR;
        }
        EEPROM_I2C_SendByte(addr);
        if(EEPROM_I2C_WaitAck() != 1)
        {
            //return IIC_ERR_WADDR;
        }
        for(i = 0; i < len; i++)
        {
            EEPROM_I2C_SendByte(data[i]);
            if(EEPROM_I2C_WaitAck() != 1)
            {
                //return IIC_ERR_WADDR;
            }
        }
        EEPROM_I2C_Stop();
    
        return 1;
    }
    
    /***************************************************************************************
    * 名称: HAL_WriteDataToEEPROM
    * 功能: 向EEPROM写数据
    * 输入: EEPROM_add  数据地址
    *       len         数据项长度
    *       data     数据缓存
    * 输出:
    * 处理:
    * 返回: 1     写入成功
    *       0     写入失败
    ***************************************************************************************/
    uint8 HAL_WriteDataToEEPROM(uint16 eeprom_add, uint16 len, uint8 *data)
    {
        unsigned short WriteLen = len;
        unsigned short DateOffect = 0;
        unsigned short size = 0;
        unsigned short PageOffect = eeprom_add % Page_Bite; //
    
    
        if((eeprom_add + len > EXTEEPROM_STORAGE_SIZE)||(len>EEPROM_MAX_WRITE_LEN))
        {
            return FALSE;
        }
    
        HAL_WriteWPState(GPIO_PIN_RESET);//关闭写保护
        udelay(1);
    
        //EEPROM支持以32字节为单位的页写,而实际是EPPROM按照每16字节进行页的划分
        //写到页的边界后,要往后写必须重新调用写入
        while(WriteLen > 0)
        {
            if(PageOffect + WriteLen > Page_Bite)
            {
                size = Page_Bite - PageOffect;
            }
            else
            {
                size = WriteLen;
            }
    
            if(WritebytetoEEPROM(EXTEEPROM_HW_ADDRESS, eeprom_add + DateOffect, data+DateOffect, size) != 1)
            {
                return 0;
            }
    
            PageOffect = 0;
            DateOffect += size;
            WriteLen -= size;
            udelay(6000);
        }
    
        HAL_WriteWPState(GPIO_PIN_SET);//打开写保护
        return 1;
    }
    
    /***************************************************************************************
    * 名称: HAL_ReadDataFromEEPROM
    * 功能: 向EEPROM写数据
    * 输入: eeprom_add  数据偏移
    *       len         数据项长度
    *       data     数据缓存
    * 输出:
    * 处理:
    * 返回: > 0     写入成功
    *       = 0     写入失败
    ***************************************************************************************/
    uint8 HAL_ReadDataFromEEPROM(uint16 eeprom_add, uint16 len, uint8 *data)
    {
        unsigned short ReadLen = len;
        unsigned short DateOffect = 0;
        unsigned short size = 0;
        unsigned short PageOffect = eeprom_add % Page_Bite;
        
        if((eeprom_add + len > EXTEEPROM_STORAGE_SIZE)||(len > EEPROM_MAX_WRITE_LEN))
        {
            return 0;
        }
    
        //EEPROM支持以32字节为单位的页写,而实际是EPPROM按照每16字节进行页的划分
        //写到页的边界后,要往后写必须重新调用写入
        while(ReadLen > 0)
        {
            if(PageOffect + ReadLen > Page_Bite)
            {
                size = Page_Bite - PageOffect;
            }
            else
            {
                size = ReadLen;
            }
    
            if(ReadbytefromEEPROM(EXTEEPROM_HW_ADDRESS, eeprom_add + DateOffect, data + DateOffect, size) == 1)
            {
                //return size;
            }
    
            PageOffect = 0;
            DateOffect += size;
            ReadLen -= size;
            udelay(6000);
        }
        return 1;
    }
    
    
    unsigned char WriteDataToExtStoreWithCS(unsigned short Addr, unsigned short Len, unsigned char *DataBuff)//补校验和
    {
        uint32  i;
        uint8   TempBuff[1025]= {0};
        uint8   CS = 0;
    
        if(Len > 1024)
        {
          return  FALSE;
        }
        //数据暂存到缓冲区
        memcpy(TempBuff, DataBuff, Len);
    
        //计算校验和
        CS = 0x33;
        for (i=0; i < Len; i++)
        {
            CS += TempBuff[i];
        }
    
        //将校验和追加到缓冲区
        TempBuff[Len] = CS;
    
        HAL_WriteDataToEEPROM(Addr, Len+1, TempBuff);
    
        return  TRUE;
    }
    
    unsigned char ReadDataFromExtStoreWithCS(unsigned short Addr, unsigned short Len, unsigned char *DataBuff)
    {
        uint32   i;
        uint8   TempBuff[1025]= {0};
        uint8   CS = 0;
        
        if(Len > 1024)
        {
            return FALSE;
        }
    
        HAL_ReadDataFromEEPROM(Addr, Len+1, TempBuff);
    
        //计算校验和
        CS = 0x33;
        for (i=0; i < Len; i++)
        {
            CS += TempBuff[i];
        }
    
        //校验和相等,数据正确,直接返回
        if (TempBuff[Len] == CS)
        {
            //从缓冲区取数据返回
            memcpy(DataBuff, TempBuff, Len);
    
            return 1;
        }
        return 0;
    }
    真正的对手会灌输给你大量的勇气 --卡夫卡
  • 相关阅读:
    java类加载过程
    进程和线程
    Java对象的创建
    java异常—检查异常(checked exception)和未检查异常(unchecked exception)
    try...catch...finally语句块
    Mysql数据库索引
    java-生产者消费者模式
    解压字符串
    Java-break,continue,return用法
    归并排序-Java
  • 原文地址:https://www.cnblogs.com/firstparke/p/8351483.html
Copyright © 2011-2022 走看看