STM32模拟IIC读写24CXX

发布者:CyborgDreamer最新更新时间:2018-04-15 来源: eefocus关键字:STM32  模拟IIC  读写24CXX 手机看文章 扫描二维码
随时随地手机看文章

文件(iic.h):


#define SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=0X80000000;}

#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=0X30000000;}


#define IIC_SCL    PBout(6) 

#define IIC_SDA    PBout(7)  

#define READ_SDA   PBin(7) 


void bsp_iic_init(void);                             

void bsp_iic_start(void);               

void bsp_iic_stop(void);                

void bsp_iic_sendByte(u8 txd);      

u8 bsp_iic_readByte(unsigned char ack);

u8 bsp_iic_waitAck(void);           

void bsp_iic_ack(void);             

void bsp_iic_nAck(void);    


文件(iic.c):


/*

****************************************************************

**  brief : IIC 初始化,IO模拟IIC

**  note : SDA-PB7,SCL-PB6

****************************************************************

*/

void bsp_iic_init(void)

{

    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); 

}


/*

***************************************************************

**  brief : IIC开始信号

**  note  : SCL为高电平时,SDA由高电平向低电平跳变

***************************************************************

*/

void bsp_iic_Start(void) 

{

    delay_5us();   

    SDA_OUT();     

    IIC_SDA=1;        

    IIC_SCL=1;

    delay_5us();

    IIC_SDA=0;

    delay_5us();

    IIC_SCL=0;

}

/*

***************************************************************

**  brief : IIC停止信号

**  note  : SCL为高电平时,SDA由低电平向高电平跳变

***************************************************************

*/


void bsp_iic_stop(void)

{

    delay_5us();   

    SDA_OUT();

    IIC_SCL=0;

    IIC_SDA=0;

    delay_5us();

    IIC_SCL=1; 

    delay_5us();

    IIC_SDA=1;

    delay_5us();                                

}


/*

********************************************************** 

**  brief : 等待应答信号到来

**  ret    : 1.接收应答失败

**            0.接收应答成功

*********************************************************

*/

u8 bsp_iic_waitAck(void)

{

    u8 ucErrTime=0;


    delay_5us();    

    SDA_IN();        

    IIC_SDA=1;

    delay_5us();       

    IIC_SCL=1;

    delay_5us();     

    while(READ_SDA)

    {

        ucErrTime++;

        if(ucErrTime>100)

        {

            bsp_iic_stop();

            return 1;

        }

    }

    delay_5us();

    IIC_SCL=0;

    return 0;  

/* brief : 产生应答信号*/

void bsp_iic_ack(void)

{

    IIC_SCL=0;

    SDA_OUT();

    IIC_SDA=0;

    delay_5us();

    IIC_SCL=1;

    delay_5us();

    IIC_SCL=0;

}

/* brief : 产生非应答信号*/            

void bsp_iic_nAck(void)

{

    IIC_SCL=0;

    SDA_OUT();

    IIC_SDA=1;

    delay_5us();

    IIC_SCL=1;

    delay_5us();

    IIC_SCL=0;

}                                        

/*

*************************************************

**  breif : IIC发送一个字节

*************************************************

*/

void bsp_iic_sendByte( u8 txd )

{

    u8 t;

    delay_5us();    

    SDA_OUT();      

    IIC_SCL=0;

    for(t=0;t<8;t++)

    {              

        if((txd&0x80)>>7)

            IIC_SDA=1;

        else

            IIC_SDA=0;

        txd<<=1;      

        delay_5us(); 

        IIC_SCL=1;

        delay_5us(); 

        IIC_SCL=0;  

        delay_5us();

    }    

}       

/*

**************************************************************************************

**  brief : 读1个字节

**  ack   :1.发送ACK,0.发送NACK

**  note  : 主机作为接收方,发送一个非应答信号表示数据传输结束

**                                                   发送一个应答信号表示数据接收成功

**            从机作为接收方,发送一个非应答信号表示数据接受失败

**                                                   发送一个应答信号表示数据接收成功

**************************************************************************************

*/

u8 bsp_iic_readByte(unsigned char ack)

{

    unsigned char i,receive=0;


    delay_5us();    

    SDA_IN();

    for(i=0;i<8;i++ )

    {

        IIC_SCL=0; 

        delay_5us();

        IIC_SCL=1;

        receive<<=1;

        delay_5us();

        if(READ_SDA)receive++;   

        delay_5us(); 

    }

    if (!ack)

        bsp_iic_nAck();

    else

        bsp_iic_ack(); 


    return receive;

}


文件(24cxx.h)


u8 bsp_eeprom_readOneByte(u16 ReadAddr);                            

void bsp_eeprom_writeOneByte(u16 WriteAddr,u8 DataToWrite);     

void bsp_eeprom_writeLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);

u32 bsp_eeprom_readLenByte(u16 ReadAddr,u8 Len);                    

void bsp_eeprom_write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);    

void bsp_eeprom_read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);   

u8 bsp_eeprom_writePage_zero(u16 WriteAddr, u8 data, u16 NumToWrite);


void bsp_eeprom_init(void);

void bsp_eeprom_reset(void);


文件(24cxx.c)


#define AT24C01     127

#define AT24C02     255

#define AT24C04     511

#define AT24C08     1023

#define AT24C16     2047

#define AT24C32     4095

#define AT24C64     8191

#define AT24C128    16383

#define AT24C256    32767


#define EE_TYPE AT24C256

#define EE_PAGE_SIZE 64   


/*

**************************************************************************

**  note : 1. EEPROM高四位地址固定为1010

**           2. 主设备在从从设备接收到最后一个字节后发送

**               一个NACK 。接收到NACK 后,从设备释放对SCL和SDA

**               线的控制;主设备就可以发送一个停止/ 重起始

**               条件

**           3. 在EEPROM的一次写循环中可以写多个字节,但一次

**               写入的字节数不能超过EEPROM的页大小

*************************************************************************

*/

void bsp_eeprom_init(void)

{

    bsp_eeprom_reset();

    delay_ms(1);

}

/* brief : EEPROM复位*/

void bsp_eeprom_reset(void)

{

    u32 i;

    //OSSchedLock();

    bsp_iic_Start();

    SDA_OUT();

    delay_us(1);

    IIC_SDA = 1;

    for(i=0; i<9; ++i) {

        delay_us(1);

        IIC_SCL = 1;

        delay_us(1);

        IIC_SCL = 0;

    }

    SDA_IN();

    bsp_iic_Start();

    IIC_Stop();

    //OSSchedUnlock();

}

/*

**********************************************************

**  brief : 读数据

**  ReadAddr : 待读数据地址

**  ret : 读出的数据

**********************************************************

*/

u8 bsp_eeprom_readOneByte(u16 ReadAddr)

{

    u8 temp=0;


    //OSSchedLock();


    bsp_iic_Start();  

    if(EE_TYPE>AT24C16)

    {

        bsp_iic_sendByte(0XA0);       /*发送写命令*/

        bsp_iic_waitAck();

        bsp_iic_sendByte(ReadAddr>>8);/*发送高地址*/

    } else {

        bsp_iic_sendByte(0XA0+((ReadAddr/256)<<1));/*发送器件地址0XA0,写数据*/    

    }

    bsp_iic_waitAck(); 

    bsp_iic_sendByte(ReadAddr%256);   /*发送低地址*/

    bsp_iic_waitAck();      

    bsp_iic_Start();           

    bsp_iic_sendByte(0XA1);           /*进入接收模式  */         

    bsp_iic_waitAck();   

    temp=bsp_iic_readByte(0);


    bsp_iic_stop();                   


    //OSSchedUnlock();


    return temp;

}

/*

*******************************************************************

**  brief : 指定地址写入数据

**  WriteAddr : 待写入地址

**  DataToWrite : 待写入数据

*******************************************************************

*/

void bsp_eeprom_writeOneByte(u16 WriteAddr,u8 DataToWrite)

{

    //OSSchedLock();


    bsp_iic_Start();  

    if(EE_TYPE>AT24C16)

    {

        bsp_iic_sendByte(0XA0);    

        bsp_iic_waitAck();


        bsp_iic_sendByte(WriteAddr>>8);

    }else

    {

        bsp_iic_sendByte(0XA0+((WriteAddr/256)<<1));

    }    

    bsp_iic_waitAck();


    bsp_iic_sendByte(WriteAddr%256);   

    bsp_iic_waitAck();


    bsp_iic_sendByte(DataToWrite);    

    bsp_iic_waitAck();


    bsp_iic_stop();                    


    //OSSchedUnlock();

    /*AT24C256的WriteCycle 最大5ms,所以这个世界绝对不能小于5ms*/

    delay_ms(10);

}


/*

***********************************************************************************************

**  brief : 指定地址写入指定长度的数据

**  WriteAddr : 待写入地址

**  datas : 待写入数据缓冲指针

**  NumToWrite : 待写入数据长度,调用方需要确保不超过页大小

**  ret : 0成功,否者失败

**  note : 在用Page 的方式进行离线数据写入时,会出现写入失败的情况.

***********************************************************************************************

*/ 

static u8 bsp_eeprom_writePage(u16 WriteAddr, u8 *datas, u16 NumToWrite)

{

    u8 result;

    u8 ret = 0;

    u32 i;


    //OSSchedLock();


    do {

        bsp_iic_Start();  

        if(EE_TYPE>AT24C16)

        {

            bsp_iic_sendByte(0XA0);    

            result = bsp_iic_waitAck();

            if(0 != result) {

                ret = 1;

                break;

            }

            bsp_iic_sendByte(WriteAddr>>8);

         } else {

            bsp_iic_sendByte(0XA0+((WriteAddr/256)<<1));  

        }

        result = bsp_iic_waitAck();

        if(0 != result) {

            ret = 1;

            break;

        }

        bsp_iic_sendByte(WriteAddr%256);   


        result = bsp_iic_waitAck();

        if(0 != result) {

            ret = 1;

            break;

        }


        i=0;

        while(NumToWrite--) {        /* 循环发送数据*/

            bsp_iic_sendByte(datas[i]);    

            ++i;

            result = bsp_iic_waitAck();

            if(0 != result) {

                ret = 1;

                break;

            }

        }

        bsp_iic_stop();

    }while(0);


    //OSSchedUnlock();


    delay_ms(10);    


    return ret;

}


/*

***********************************************************************************

**  brief : 指定地址写入指定长度的数据

**  WriteAddr : 待写入地址

**  data : 待写入数据

**  NumToWrite : 待写入数据长度,调用方需要确保不超过页大小

**  ret : 0成功,否者失败

***********************************************************************************

*/ 


u8 bsp_eeprom_writePage_zero(u16 WriteAddr, u8 data, u16 NumToWrite)

{

    u8 result;

    u8 ret = 0;


    //OSSchedLock();


    do {

        bsp_iic_Start();  

        if(EE_TYPE>AT24C16)

        {

            bsp_iic_sendByte(0XA0);    

            result = bsp_iic_waitAck();

            if(0 != result) {

                ret = 1;

                break;

            }


            bsp_iic_sendByte(WriteAddr>>8);

        } else {

            bsp_iic_sendByte(0XA0+((WriteAddr/256)<<1));   

        }

        result = bsp_iic_waitAck();

        if(0 != result) {

            ret = 1;

            break;

        }

        bsp_iic_sendByte(WriteAddr%256);   


        result = bsp_iic_waitAck();

        if(0 != result) {

            ret = 1;

            break;

        }


        while(NumToWrite--) {

            bsp_iic_sendByte(data);     

            result = bsp_iic_waitAck();

            if(0 != result) {

                ret = 1;

                break;

            }

        }


        bsp_iic_stop();

    }while(0);


    //OSSchedUnlock();

    delay_ms(10);   


    return ret;

}

/*

************************************************************************

**  breif : 指定地址写入指定长度数据

**  WriteAddr : 待写入地址

**  DataToWrite : 待写入数据

**  Len : 待写入数据长度1-4

************************************************************************

*/

void bsp_eeprom_writeLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)

{

    u8 b[4];

    b[0] = (u8)DataToWrite;

    b[1] = (u8)(DataToWrite>>8);

    b[2] = (u8)(DataToWrite>>16);

    b[3] = (u8)(DataToWrite>>24);

    bsp_eeprom_write(WriteAddr, b, Len);

}


/*

************************************************************************

**  breif : 指定地址开始读出长度为Len的数据

**            该函数用于读出16bit或者32bit的数据.

**  ReadAddr   : 开始读出的地址 

**  Len : 要读出数据的长度2,4

**  Ret : 读出的16bit或32bit数据

************************************************************************

*/

u32 bsp_eeprom_readLenByte(u16 ReadAddr,u8 Len)

{

    u8 buf[4];

    u32 temp=0;

    u32 v;

    if(Len == 0 || Len == 1 || Len == 3|| (Len > 4)) {

        return 0;

    }

    bsp_eeprom_read(ReadAddr, buf, Len);


    if(Len == 2) {

        v = buf[1];

        temp |= (v << 8);

        v = buf[0];

        temp |= v;

    }


    if(Len == 4) {

        v = buf[3];

        temp |= (v << 24);

        v = buf[2];

        temp |= (v << 16);

        v = buf[1];

        temp |= (v << 8);

        v = buf[0];

        temp |= v;

    }

    return temp;                                                    

}


/*

*****************************************************************************

**  breif : 指定地址读出指定长度的数据

**  ReadAddr : 待读取地址

**  buf : 待读出数据的缓冲指针

**  numToRead : 待读出的数据长度

*****************************************************************************

*/

void bsp_eeprom_read(u16 ReadAddr,u8 *buf,u16 numToRead)

{

    u8 temp=0;

    if(numToRead == 0) {

        return ;

    }

    //OSSchedLock();

    bsp_iic_Start();  

    if(EE_TYPE>AT24C16)

    {

        bsp_iic_sendByte(0XA0);    

        bsp_iic_waitAck();

        bsp_iic_sendByte(ReadAddr>>8);

    } else {

        bsp_iic_sendByte(0XA0+((ReadAddr/256)<<1));      

    }

    bsp_iic_waitAck(); 


    bsp_iic_sendByte(ReadAddr%256);  

    bsp_iic_waitAck();      

    bsp_iic_Start();           

    bsp_iic_sendByte(0XA1);            

    bsp_iic_waitAck();

    while(numToRead-1) {

        temp = bsp_iic_readByte(1);

        *buf = temp;

        ++buf;

        --numToRead;

    }

    temp = bsp_iic_readByte(0);

    *buf = temp;


    bsp_iic_stop();


    //OSSchedUnlock();

}

/*

*****************************************************************************

**  brief           : 将缓冲区的数据写到EEPROM 中

**  WriteAddr    : 待写入地址

**  pBuffer        : 数据缓冲区指针

**  NumToWrite : 待写入字节数

**  note            : http://wenku.baidu.com/view/4ffb2eb21a37f111f1855ba7.html

*****************************************************************************

*/

void bsp_eeprom_write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)

{

    u16 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;

    Addr = WriteAddr % EE_PAGE_SIZE;          /* 写入地址是不是64的整数倍*/

    count = EE_PAGE_SIZE - Addr;              /* 距离下一页页首的距离*/

    NumOfPage = NumToWrite / EE_PAGE_SIZE;    /* 一共多少页*/

    NumOfSingle = NumToWrite % EE_PAGE_SIZE;  /* 不够一页的数据余量*/


    if(Addr == 0)                   /* 首页地址*/

    {

        if(NumOfPage == 0)          /* 不足一页数据*/

        {        

            bsp_eeprom_writePage(WriteAddr, pBuffer, NumOfSingle);

        }else                       /* 数据超过一页*/

        {

            while(NumOfPage -- ) 

            {

                bsp_eeprom_writePage(WriteAddr, pBuffer, EE_PAGE_SIZE);

                pBuffer += EE_PAGE_SIZE;

                WriteAddr += EE_PAGE_SIZE;

            }

            if(NumOfSingle > 0) 

            {

                bsp_eeprom_writePage(WriteAddr, pBuffer, NumOfSingle);

            }

        }

    } else                           /* 非首页地址*/

    {

        if(NumOfPage == 0)           /* 不足一页数据*/

        {        

            bsp_eeprom_writePage(WriteAddr, pBuffer, NumOfSingle);

        } else                       /* 数据超过一页*/

        {

            NumToWrite -= count;   

            NumOfPage = NumToWrite / EE_PAGE_SIZE;    /* 剩余的页数*/

            NumOfSingle = NumToWrite % EE_PAGE_SIZE;  /* 不足一页的数据*/

            if(count > 0) 

            {

                bsp_eeprom_writePage(WriteAddr, pBuffer, count);

                pBuffer += count;

                WriteAddr += count;

            }

            while(NumOfPage -- ) 

            {

               bsp_eeprom_writePage(WriteAddr, pBuffer, EE_PAGE_SIZE);

                pBuffer += EE_PAGE_SIZE;

                WriteAddr += EE_PAGE_SIZE;

            }

            if(NumOfSingle > 0)

            {

                bsp_eeprom_writePage(WriteAddr, pBuffer, NumOfSingle);

            }

        }

    }

}


关键字:STM32  模拟IIC  读写24CXX 引用地址:STM32模拟IIC读写24CXX

上一篇:STM32 USART DMA发送 中断接收
下一篇:STM32 模拟I2C (STM32F051)

推荐阅读最新更新时间:2024-03-16 16:00

再造STM32---第十六部分:SysTick—系统定时器
本章参考资料《ARM Cortex™-M4F 技术参考手册》 -4.5 章节 SysTick Timer(STK), 和4.48 章节 SHPRx,其中 STK 这个章节有 SysTick 的简介和寄存器的详细描述。因为SysTick 是属于 CM4 内核的外设,有关寄存器的定义和部分库函数都在 core_cm4.h 这个头文件中实现。所以学习 SysTick 的时候可以参考这两个资料,一个是文档,一个是源码。 16.1 SysTick 简介: SysTick—系统定时器是属于 CM4 内核中的一个外设,内嵌在 NVIC 中。系统定时器是一个 24bit 的向下递减的计数器,计数器每计数一次的时间为 1/SYSC
[单片机]
再造STM32---第十六部分:SysTick—系统定时器
能够完美替代STM32的两款产品介绍和评测
今日带来能够完美替代STM32的产品是沁恒微电子的CH32F103以及RISC-V内核的CH32V103两款产品。 CH32F1系列是基于32位Cortex-M3内核设计的通用微控制器。片上集成了时钟安全机制、多级电源管理、 通用DMA控制器等。此系列具有 2 路 USB2.0接口、多通道 TouchKey、 12 位 DAC 转换模块,多通道 12 位 ADC、 多组定时器、 CAN 通讯控制器、 I2C/USART/SPI 等丰富的外设资源。 CH32V103则是其在去年上半年推出的RISC-V架构的32位通用MCU微控制器。CH32V103系列是以RISC-V3A处理器为核心的32位通用微控制器,该处理器是基于RISC-V开
[单片机]
能够完美替代<font color='red'>STM32</font>的两款产品介绍和评测
STM32库文件结构及CMSIS介绍
使用STM32库时,各库文件作用及关系: CMSIS标准介绍:
[单片机]
写几点内容给学习STM32的朋友
1查找资料去官网 许多初学者总是在问:能给我一份xxx手册吗? 你有关于xxx的资料吗? 同时,我也常在某些“技术群”里看到类似这种“给资料”的对话。 这样说吧,你们向别人获取的“资料”,别人基本上也是从官网下载而来的。而且,别人给你的资料不一定是最新版本。 因此,建议初学者查找资料,寻找资料尽量找官方原版资料,毕竟官方的才具有权威性。 STM32官方整理的资料很多,而且针对每一种型号的MCU都有各种资料。夸一点的说:你想要的都有。 针对你MCU芯片型号,进入对应的网址即可(具体这里就不说过程了): https://www.st.com/en/microcontrollers.html 这里肯定又有许多
[单片机]
写几点内容给学习<font color='red'>STM32</font>的朋友
STM32时钟配置及相关问题
Ⅰ、写在前面 最近有很多朋友问: 1.我的USART串口打印出来的数据是乱码? 2.我的TIM定时器延时或定时不准确? 常见可能原因: 1.晶振问题:外部晶振不起振、或频率与配置不匹配。 2.软件问题:分频、倍频、时钟源选择等。 总结来说,主要还在于软件的问题。因为即使没有外部晶振,也可以使用内部晶振。 其实,软件的问题是容易得到解决的,只要你了解了STM32时钟配置里面具体内容就知道了。 关于本文的详细内容请看下面章节 Ⅱ、本文要点 要了解时钟的配置,就需要知道它在哪里配置,也就是还需要了解软件执行的流程。 1.软件流程 说软件流程是让大家知道系统时钟配置的位置。不管是使用寄存器开发,还是使用库(标准库、
[单片机]
<font color='red'>STM32</font>时钟配置及相关问题
关于STM32的ISP指令
关于STM32的ISP指令---读写数据缓存 在测试擦除命令的时候发现,写入和读出的数据是有缓存的,目前测试的结果为:写入数据有四个字的缓存,读取数据有15个字的缓存。 例如:最后写入的4个字数据,在擦除flash之后,重新读出,仍然读到的是擦除前的数值,尽管实际该地址flash的内容已经改变。 例如:在擦除flash之前读出4个地址数据,则flash内容擦除以后,再次读取该4个地址的数据,返回内容仍然为flash擦除之前的数据。 如果连续读出地址相连的16个字数据,则最早读出的那个数据将会从缓存清除。如果读出的数据为非连续的,则可能读不到第16个字,最早读出的那个数据已经从缓存清除。猜测在请求读取一个地址数据的时
[单片机]
9.TouchGFX界面应用之综合应用--打地鼠
上一节我们学习了自定义组件(容器),这一节我我们使用自定义组件(容器)做一个简易打地鼠的小游戏,再创建一个屏幕,在第三个屏幕上面先放置切换屏幕的按键。 然后百度找两张图片,一个作为土拨鼠,一个作为坑,坑和土拨鼠图片的像素点大小保证一致减少计算。 放置几个按钮表示土拨鼠的坑,用上面表示坑的图片表示背景,这样你按钮的大小就和图片的大小保持一致,每一个按钮设置好编号, 每一个按钮对应一个函数。我们在CustomContainer2.hpp中声明定义这些函数 我们写一个类似于滴答定时器的函数,来作为打地鼠的时钟。在组件(容器)中使用handleTickEvent是没有效果的,组件不会自己产生时钟需要外部提供,那
[单片机]
9.TouchGFX界面应用之综合应用--打地鼠
STM32单片机半主机模式的应用
在keil中编程时常会遇到__use_no_semihosting_swi的警告,这时你就是进入了半主机模式。 在嵌入式的编程中你是避免不了使用printf、fopen、fclose等函数的但是因为嵌入式的程序中并没有对这些函数的底层实现,使得设备运行时会进入软件中断BAEB处,这时就需要__use_no_semihosting_swi这 个声明,使程序遇到这些文件操作函数时不停在此中断处,具体操作如下,将下列程序加入你的工程中: #pragmaimport(__use_no_semihosting_swi)#pragmaimport(_main_redirection)constchar__stdin_name[150]
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved