历史上的今天
返回首页

历史上的今天

今天是:2025年05月19日(星期一)

正在发生

2018年05月19日 | STM32单片机(13) I2C读写AT24Cxx存储器实验

2018-05-19 来源:eefocus

本程序主要利用I2C串行总线,实现AT24Cxx系列EEPROM存储器(此处是AT24C02)的读写,将数据写入,再读出发送至串口

可利用EEPROM存储器数据断电不消失性质存储一些配置数据等。

主程序

/******************************************************************************* 

*    

* 软件功能:  I2C读写AT24Cxx系列EEPROM存储器 

*  

*******************************************************************************/  

#include "stm32f10x.h"  

#include  

#include "delay.h"  

#include "I2C.h"  

#include "AT24Cxx.h"  

    

void RCC_Configuration(void);  

void GPIO_Configuration(void);  

void USART1_Configuration(void);  

void Uart1_PutChar(u8 ch);  

void Uart1_PutString(u8* buf , u8 len);  

int fputc(int ch, FILE *f);  

                              

/************************************************* 

函数: int main(void) 

功能: main主函数 

参数: 无 

返回: 无 

**************************************************/  

int main(void)  

{  

  u16 tempdata=0;  

  u16 i=0;  

  RCC_Configuration();  

  GPIO_Configuration();  

  delay_init(72);  

  USART1_Configuration();  

  I2C_Configuration();  

  delay_ms(1);  

  

  

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

  {  

      AT24Cxx_WriteOneByte(i,i);  

  }             

  

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

  {  

      tempdata=AT24Cxx_ReadOneByte(i);  

      printf("%x ",tempdata);  

  }  

    

  

  //AT24Cxx_WriteTwoByte(0,0x1234);  

  //tempdata=AT24Cxx_ReadTwoByte(0);  

 // printf("两个字节 dt=%x\n",tempdata);  

  

  while(1);  

}  

  

/************************************************* 

函数: void RCC_Configuration(void) 

功能: 复位和时钟控制 配置 

参数: 无 

返回: 无 

**************************************************/  

void RCC_Configuration(void)  

{  

  ErrorStatus HSEStartUpStatus;                    //定义外部高速晶体启动状态枚举变量  

  RCC_DeInit();                                    //复位RCC外部设备寄存器到默认值  

  RCC_HSEConfig(RCC_HSE_ON);                       //打开外部高速晶振  

  HSEStartUpStatus = RCC_WaitForHSEStartUp();      //等待外部高速时钟准备好  

  if(HSEStartUpStatus == SUCCESS)                  //外部高速时钟已经准别好  

  {  

    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //开启FLASH预读缓冲功能,加速FLASH的读取。所有程序中必须的用法.位置:RCC初始化子函数里面,时钟起振之后  

    FLASH_SetLatency(FLASH_Latency_2);                    //flash操作的延时  

          

    RCC_HCLKConfig(RCC_SYSCLK_Div1);               //配置AHB(HCLK)时钟等于==SYSCLK  

    RCC_PCLK2Config(RCC_HCLK_Div1);                //配置APB2(PCLK2)钟==AHB时钟  

    RCC_PCLK1Config(RCC_HCLK_Div2);                //配置APB1(PCLK1)钟==AHB1/2时钟  

           

    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);  //配置PLL时钟 == 外部高速晶体时钟 * 9 = 72MHz  

    RCC_PLLCmd(ENABLE);                                   //使能PLL时钟  

     

    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)    //等待PLL时钟就绪  

    {  

    }  

    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);            //配置系统时钟 = PLL时钟  

    while(RCC_GetSYSCLKSource() != 0x08)                  //检查PLL时钟是否作为系统时钟  

    {  

    }  

  }  

    

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_GPIOB | RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO, ENABLE);  //允许 GPIOA、GPIOB、USART1、AFIO时钟  

}  

  

/************************************************* 

函数: void GPIO_Configuration(void) 

功能: GPIO配置 

参数: 无 

返回: 无 

**************************************************/  

void GPIO_Configuration(void)  

{  

    

  GPIO_InitTypeDef GPIO_InitStructure;        //定义GPIO初始化结构体  

  

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;   

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复合推挽输出     

  GPIO_Init(GPIOA, &GPIO_InitStructure);       //PA9串口输出  

    

}  

  

  

/******************************************************************************* 

    函数名:USART1_Configuration 

    输  入: 

    输  出: 

    功能说明: 

    初始化串口硬件设备,启用中断 

    配置步骤: 

    (1)打开GPIO和USART1的时钟 

    (2)设置USART1两个管脚GPIO模式 

    (3)配置USART1数据格式、波特率等参数 

    (4)使能USART1接收中断功能 

    (5)最后使能USART1功能 

*/  

void USART1_Configuration(void)   //串口配置   详见《STM32的函数说明(中文).pdf》P346  

{  

    USART_InitTypeDef USART_InitStructure;  

    USART_InitStructure.USART_BaudRate=9600;   //波特率为9600  

    USART_InitStructure.USART_WordLength=USART_WordLength_8b;  //数据位为8  

    USART_InitStructure.USART_StopBits=USART_StopBits_1; //在帧结尾传输 1 个停止位  

    USART_InitStructure.USART_Parity=USART_Parity_No; //校验模式:奇偶失能  

    USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //硬件流控制失能  

    USART_InitStructure.USART_Mode=USART_Mode_Tx | USART_Mode_Rx; //USART_Mode 指定了使能或者失能发送和接收模式:发送使能|接收失能  

    USART_Init(USART1, &USART_InitStructure);     //初始化配置  

  

    USART_Cmd(USART1,ENABLE);   //使能或者失能 USART 外设  

    USART_ClearFlag(USART1, USART_FLAG_TC);//清除传输完成标志位,否则可能会丢失第1个字节的数据.USART_FLAG_TC为发送完成标志位  

}  

  

  

//发送一个字符  

void Uart1_PutChar(u8 ch)  

{  

    USART_SendData(USART1, (u8) ch);  

    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//等待发送完成  

}  

  

//发送一个字符串 Input : buf为发送数据的地址 , len为发送字符的个数  

void Uart1_PutString(u8* buf , u8 len)  

{     

    u8 i;  

    for(i=0;i

    {  

        Uart1_PutChar(*(buf++));  

    }  

}  

  

int fputc(int ch, FILE *f)  

{  

Uart1_PutChar((u8)ch);  //此处为自定义函数,参见串口中断通信,请勿盲目复制  

return (ch);  


I2C.h

#ifndef __I2C_H  

#define __I2C_H                  

#include "stm32f10x.h"  

  

//如果移植程序时只要改一下三个地方就行了  

#define I2C_SCL GPIO_Pin_6  

#define I2C_SDA GPIO_Pin_7  

#define GPIO_I2C GPIOB  

  

#define I2C_SCL_H GPIO_SetBits(GPIO_I2C,I2C_SCL)  

#define I2C_SCL_L GPIO_ResetBits(GPIO_I2C,I2C_SCL)  

  

#define I2C_SDA_H GPIO_SetBits(GPIO_I2C,I2C_SDA)  

#define I2C_SDA_L GPIO_ResetBits(GPIO_I2C,I2C_SDA)  

  

void I2C_Configuration(void);  

void I2C_SDA_OUT(void);  

void I2C_SDA_IN(void);  

void I2C_Start(void);  

void I2C_Stop(void);  

void I2C_Ack(void);  

void I2C_NAck(void);  

u8   I2C_Wait_Ack(void);  

void I2C_Send_Byte(u8 txd);  

u8   I2C_Read_Byte(u8 ack);  

#endif 


I2C.c

#include "delay.h"  

#include "I2C.h"  

  

void I2C_Configuration(void)  

{  

    GPIO_InitTypeDef GPIO_InitStructure;      

      

    GPIO_InitStructure.GPIO_Pin=I2C_SCL|I2C_SDA;  

    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;  

    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;  

    GPIO_Init(GPIOB,&GPIO_InitStructure);  

  

    I2C_SCL_H;  

    I2C_SDA_H;  

}  

  

void I2C_SDA_OUT(void)  

{  

    GPIO_InitTypeDef GPIO_InitStructure;      

      

    GPIO_InitStructure.GPIO_Pin=I2C_SDA;  

    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;  

    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;  

    GPIO_Init(GPIOB,&GPIO_InitStructure);  

}  

  

void I2C_SDA_IN(void)  

{  

    GPIO_InitTypeDef GPIO_InitStructure;      

      

    GPIO_InitStructure.GPIO_Pin=I2C_SDA;  

    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;  

    GPIO_Init(GPIOB,&GPIO_InitStructure);  

}  

  

//产生起始信号  

void I2C_Start(void)  

{  

    I2C_SDA_OUT();  

      

    I2C_SDA_H;  

    I2C_SCL_H;  

    delay_us(5);  

    I2C_SDA_L;  

    delay_us(6);  

    I2C_SCL_L;  

}  

  

//产生停止信号  

void I2C_Stop(void)  

{  

   I2C_SDA_OUT();  

  

   I2C_SCL_L;  

   I2C_SDA_L;  

   I2C_SCL_H;  

   delay_us(6);  

   I2C_SDA_H;  

   delay_us(6);  

}  

  

//主机产生应答信号ACK  

void I2C_Ack(void)  

{  

   I2C_SCL_L;  

   I2C_SDA_OUT();  

   I2C_SDA_L;  

   delay_us(2);  

   I2C_SCL_H;  

   delay_us(5);  

   I2C_SCL_L;  

}  

  

//主机不产生应答信号NACK  

void I2C_NAck(void)  

{  

   I2C_SCL_L;  

   I2C_SDA_OUT();  

   I2C_SDA_H;  

   delay_us(2);  

   I2C_SCL_H;  

   delay_us(5);  

   I2C_SCL_L;  

}  

//等待从机应答信号  

//返回值:1 接收应答失败  

//        0 接收应答成功  

u8 I2C_Wait_Ack(void)  

{  

    u8 tempTime=0;  

  

    I2C_SDA_IN();  

  

    I2C_SDA_H;  

    delay_us(1);  

    I2C_SCL_H;  

    delay_us(1);  

  

    while(GPIO_ReadInputDataBit(GPIO_I2C,I2C_SDA))  

    {  

        tempTime++;  

        if(tempTime>250)  

        {  

            I2C_Stop();  

            return 1;  

        }      

    }  

  

    I2C_SCL_L;  

    return 0;  

}  

//I2C 发送一个字节  

void I2C_Send_Byte(u8 txd)  

{  

    u8 i=0;  

  

    I2C_SDA_OUT();  

    I2C_SCL_L;//拉低时钟开始数据传输  

  

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

    {  

        if((txd&0x80)>0) //0x80  1000 0000  

            I2C_SDA_H;  

        else  

            I2C_SDA_L;  

  

        txd<<=1;  

        I2C_SCL_H;  

        delay_us(2); //发送数据  

        I2C_SCL_L;  

        delay_us(2);  

    }  

}  

  

//I2C 读取一个字节  

  

u8 I2C_Read_Byte(u8 ack)  

{  

   u8 i=0,receive=0;  

  

   I2C_SDA_IN();  

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

   {  

        I2C_SCL_L;  

        delay_us(2);  

        I2C_SCL_H;  

        receive<<=1;  

        if(GPIO_ReadInputDataBit(GPIO_I2C,I2C_SDA))  

           receive++;  

        delay_us(1);      

   }  

  

    if(ack==0)  

        I2C_NAck();  

    else  

        I2C_Ack();  

  

    return receive;  

}  

AT24Cxx.h

#ifndef _AT24Cxx_H  

#define _AT24Cxx_H  

#include "stm32f10x.h"  

#include "I2C.h"  

#include "delay.h"  

  

#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  AT24C02  

  

u8 AT24Cxx_ReadOneByte(u16 addr);  

u16 AT24Cxx_ReadTwoByte(u16 addr);  

void AT24Cxx_WriteOneByte(u16 addr,u8 dt);  

void AT24Cxx_WriteTwoByte(u16 addr,u16 dt);  

  

  

#endif  


AT24Cxx.c

#include "AT24Cxx.h"  

  

  

u8 AT24Cxx_ReadOneByte(u16 addr)  

{  

    u8 temp=0;  

  

    I2C_Start();  

      

    if(EE_TYPE>AT24C16)  

    {  

        I2C_Send_Byte(0xA0);  

        I2C_Wait_Ack();  

        I2C_Send_Byte(addr>>8);   //发送数据地址高位  

    }  

    else  

    {  

       I2C_Send_Byte(0xA0+((addr/256)<<1));//器件地址+数据地址  

    }  

  

    I2C_Wait_Ack();  

    I2C_Send_Byte(addr%256);//双字节是数据地址低位          

                            //单字节是数据地址低位  

    I2C_Wait_Ack();  

  

    I2C_Start();  

    I2C_Send_Byte(0xA1);  

    I2C_Wait_Ack();  

  

    temp=I2C_Read_Byte(0); //  0   代表 NACK  

    I2C_Stop();  

      

    return temp;      

}  

  

u16 AT24Cxx_ReadTwoByte(u16 addr)  

{  

    u16 temp=0;  

  

    I2C_Start();  

      

    if(EE_TYPE>AT24C16)  

    {  

        I2C_Send_Byte(0xA0);  

        I2C_Wait_Ack();  

        I2C_Send_Byte(addr>>8);   //发送数据地址高位  

    }  

    else  

    {  

       I2C_Send_Byte(0xA0+((addr/256)<<1));//器件地址+数据地址  

    }  

  

    I2C_Wait_Ack();  

    I2C_Send_Byte(addr%256);//双字节是数据地址低位          

                            //单字节是数据地址低位  

    I2C_Wait_Ack();  

  

    I2C_Start();  

    I2C_Send_Byte(0xA1);  

    I2C_Wait_Ack();  

  

    temp=I2C_Read_Byte(1); //  1   代表 ACK  

    temp<<=8;  

    temp|=I2C_Read_Byte(0); //  0  代表 NACK  

  

    I2C_Stop();  

      

    return temp;      

}  

  

  

void AT24Cxx_WriteOneByte(u16 addr,u8 dt)  

{  

    I2C_Start();  

  

    if(EE_TYPE>AT24C16)  

    {  

        I2C_Send_Byte(0xA0);  

        I2C_Wait_Ack();  

        I2C_Send_Byte(addr>>8);   //发送数据地址高位  

    }  

    else  

    {  

       I2C_Send_Byte(0xA0+((addr/256)<<1));//器件地址+数据地址  

    }  

  

    I2C_Wait_Ack();  

    I2C_Send_Byte(addr%256);//双字节是数据地址低位          

                            //单字节是数据地址低位  

    I2C_Wait_Ack();  

  

    I2C_Send_Byte(dt);  

    I2C_Wait_Ack();  

    I2C_Stop();  

  

    delay_ms(10);  

}  

  

void AT24Cxx_WriteTwoByte(u16 addr,u16 dt)  

{  

    I2C_Start();  

  

    if(EE_TYPE>AT24C16)  

    {  

        I2C_Send_Byte(0xA0);  

        I2C_Wait_Ack();  

        I2C_Send_Byte(addr>>8);   //发送数据地址高位  

    }  

    else  

    {  

       I2C_Send_Byte(0xA0+((addr/256)<<1));//器件地址+数据地址  

    }  

  

    I2C_Wait_Ack();  

    I2C_Send_Byte(addr%256);//双字节是数据地址低位          

                            //单字节是数据地址低位  

    I2C_Wait_Ack();  

  

    I2C_Send_Byte(dt>>8);  

    I2C_Wait_Ack();  

  

    I2C_Send_Byte(dt&0xFF);  

    I2C_Wait_Ack();  

  

    I2C_Stop();  

  

    delay_ms(10);  

}  



推荐阅读

史海拾趣

弘凯光电(BRIGHTEK)公司的发展小趣事

弘凯光电股份有限公司,自2001年成立以来,便以光电半导体封装与解决方案提供商的身份,开始在电子行业中崭露头角。早期,公司以台湾为基地,凭借对技术的不断追求和对市场的敏锐洞察,逐步在光电半导体领域积累了宝贵的经验。通过持续的研发和创新,弘凯光电逐渐形成了自己的核心竞争力,为后续的快速发展奠定了坚实基础。

Esterline Technologies Corporation公司的发展小趣事

随着技术的不断进步和市场的逐步打开,弘凯光电开始将业务拓展至全球范围。公司的客户群迅速扩大,遍布60多个国家和地区,同时在欧洲、北美、南美、东南亚和中东地区均设立了经销网点。此外,弘凯光电还积极寻求国际认证,以证明其产品的品质和可靠性。通过取得ISO9001质量保证体系、ISO14001国际环境管理体系认证等一系列认证,公司进一步提升了品牌形象和市场竞争力。

Alpha Industries公司的发展小趣事

随着互联网技术的普及,电子商务成为了越来越多消费者的首选购物方式。Alpha Industries抓住这一机遇,积极拓展电子商务平台。公司在各大电商平台上开设官方旗舰店,并通过社交媒体进行品牌推广。此外,Alpha Industries还开发了自己的官方网站和移动应用,为消费者提供更加便捷的购物体验。电子商务平台的拓展使得Alpha Industries的产品能够更好地触达消费者,进一步提升了品牌知名度和市场占有率。

鸿展光电(GPO)公司的发展小趣事

随着电子技术的飞速发展,军事装备也在不断升级。Alpha Industries敏锐地捕捉到了这一趋势,开始将电子技术应用于其军事服装设计中。例如,公司研发了一款带有GPS定位功能的飞行夹克,帮助飞行员在复杂环境中快速定位。此外,Alpha Industries还利用电子传感器技术,开发出能够监测士兵体温和心率的战地风衣,为军队提供更为全面的保障。

Decawave公司的发展小趣事

在2015年的微软室内定位大赛中,Decawave的UWB技术大放异彩。公司凭借其高精度、低误差的UWB定位解决方案,在激烈的竞争中脱颖而出,荣获最佳无线电定位解决方案奖。这一荣誉不仅证明了Decawave在UWB技术领域的领先地位,也为其在市场上的推广和应用奠定了坚实的基础。

Dell公司的发展小趣事

在2015年的微软室内定位大赛中,Decawave的UWB技术大放异彩。公司凭借其高精度、低误差的UWB定位解决方案,在激烈的竞争中脱颖而出,荣获最佳无线电定位解决方案奖。这一荣誉不仅证明了Decawave在UWB技术领域的领先地位,也为其在市场上的推广和应用奠定了坚实的基础。

问答坊 | AI 解惑

大家谁在大学参加过电子设计大赛啊?

本帖最后由 paulhyde 于 2014-9-15 09:15 编辑 大家谁在大学参加过电子设计大赛啊?希望大家一起讨论啊  …

查看全部问答>

RF典型电路分析讲义.ppt

匹配网络(Matching) 收发双工器(Diplexer) 声表面波滤波器(SAW) 平衡网络(Balance) 锁相环(PLL) 收发器(Transceiver) 衰减网络(Attenuation) 功率控制环路(APC) 滤波网络(Filter) 其它 …

查看全部问答>

FAT文件系统高手来帮忙解答,小弟将不胜感激涕零

我在嵌入式平台上移植的FAT32文件系统,自己写MBR区域以及DBR区域和后继的文件系统等。 发现一个问题,实在不知道如何解答和处理。 首先说一下,我的MBR区域、DBR区域以及相关情况: 1.我用的是80G的硬盘,扇区总数为156301488. 2.我在MBR ...…

查看全部问答>

如何提高Powerpc 8270嵌入式系统性能?

现在将原来在台式机p4 2.4G linux下的c语言程序移植到Powerpc 8270 450MHz的嵌入式linux下执行,性能大约是原来的二十分之一到十分之一,请问有没有什么办法可以提高程序的性能?设计程序方面有什么技巧和需要注意的地方,我觉得这两种cpu的性能不 ...…

查看全部问答>

关于随机序列产生器

需要一个随机序列产生器的设计方案.希望大家可以帮助我.谢谢.Gold或Kasami.…

查看全部问答>

工程师常用电子工具

  功能如下:1:解方程式2:电阻并串联计算3:色环电阻识别4:有源滤波设计5:电源和基准设计:317,4316:空心电感设计7:环形变压器设计8:EI变压器设计9:分频设计10:补偿和衰减设计11:差分LPF12:RC常数13:普通变压器设计   愿 ...…

查看全部问答>

请问STM8单片机开发环境及工具?

                                 那位熟悉STM8的开发环境,给介绍一下!…

查看全部问答>

断点调试诡异问题

以前在断点调试程序的时候,程序莫名其妙地进入系统汇编代码_HwPktPoll死在那里,我也曾发过求助的帖子,一直没有得到解答。最近我发现,如果断点设置得比较少的话(比如1,2个)就运行正常,要是多设一个断点可能就会在下一个断点执行后死在_HwPkt ...…

查看全部问答>

博世用LM3S6911,不知道它的供货怎么样?

博世用LM3S6911,不知道它的供货怎么样?…

查看全部问答>

【聊聊DSP】我与DSP的那些事儿

       我接触的第一个微控制器就是DSP了,掐指一算,这也是8年前的事情了。用有缘无份来形容一点都不为过,后来一头扎进ARM阵营,把DSP更是束之高阁,不曾珍惜也不曾拥有。但DSP的身影却伴随我的学习和工作,偶尔的调戏一下她 ...…

查看全部问答>