STM32 I2C AT24C02驱动

发布者:Harmonious222最新更新时间:2015-10-30 来源: eefocus关键字:STM32  I2C  AT24C02驱动 手机看文章 扫描二维码
随时随地手机看文章
    如果搞过51的I2C的同志,再来看看STM32的I2C驱动,一定有相见恨晚的感觉。STM32自带I2C硬件模块,再配合ST的官方库函数,I2C在STM32这里可以玩得如火的地步。这里的这个I2C驱动算是很完整了的,可以直接拿来用到项目开发中去。好,不废话,上图:

    工程结构图:

   STM32 <wbr>I2C <wbr>AT24C02驱动

    1、main.c

#include"stm32f10x.h"
#include"usart1.h"
#include"led.h"
#include"i2c_at24c02.h"
#include



struct Contact{
  u8 Name[15];       //姓名
  u8 Phone[11];    //电话
  u8 BirthDay[10];   //生日
}WgchnlnContact[3],NewContact;
struct Contact WgchnlnContact[3]={
{
  "wgchnln",
  "18682101373",
  "1987-02-19",
},
{
  "hezepan",
  "18528473728",
  "1987-10-28",
},
{
  "lixiaowei",
  "13527492729",
  "1988-12-02",
}};


#ifdef Test

void I2C_Test(void)
{
 u16 i;
 u8 I2c_Buf[256];
 
    printf("写入的数据 ");
   
 //填充缓冲
 for(i=0;i<=255;i++)
    
        I2c_Buf[i]=i;
        printf("0x%x ",I2c_Buf[i]);
        if(i == 9)
        {
            printf(" ");
        }
    }
    printf(" ");
   
 I2C_AT24Cx_Writes(0,I2c_Buf,256); //将I2C_Buf中顺序递增的数据写入EERPOM中 

 
 //清缓冲
 for(i=0;i<=255;i++)
    
  I2c_Buf[i]=0;
    }
   
    printf("读出的数据 ");
 I2C_AT24Cx_Reads(0,I2c_Buf,256);//将EEPROM读出数据顺序保持到I2C_Buf中 

    //将I2C_Buf中的数据通过串口打印
 for(i=0;i<256;i++)
 
  if(I2c_Buf[i]!=i)
  {
            printf("错误:I2C EEPROM写入与读出的数据不一致 ");
   while(1);
  }
        printf("0x%X ", I2c_Buf[i]);
        if(i == 9)
        {
            printf(" ");
        }
 }
}
#endif

int main(void)
{
  u8 ReadBuffer[36];
  u8 i=0;
  u8 j=0;
  USART_Config();           //串口1初始化
  printf(" 这是一个I2C-EEPROM-AT24C02演示实验 ");

  //Led_Init();            //LED初始化

  I2C_AT24Cx_Init();          //I2C初始化

#ifdef Test
  I2C_Test();
#endif

 
  printf(" 写入联系人 ");
  for(j=0;j<3;j++)
  {
    I2C_AT24Cx_Writes(0+j*36,WgchnlnContact[j].Name,15);
    I2C_AT24Cx_Writes(15+j*36,WgchnlnContact[j].Phone,11);
    I2C_AT24Cx_Writes(26+j*36,WgchnlnContact[j].BirthDay,10);
  }
  j=0;
 
  printf(" 读出联系人 ");
  for(j=0;j<3;j++)
  {
    I2C_AT24Cx_Reads(j*36,ReadBuffer,36);
   
    for(i=0;i<15;i++)
    {
     NewContact.Name[i]=ReadBuffer[i];
    }
    i=0;
    printf(" 姓名:%s ",NewContact.Name);
   
    for(i=0;i<11;i++)
    {
     NewContact.Phone[i]=ReadBuffer[i+15];
    }
    i=0;
    printf("电话:%s ",NewContact.Phone);//为什么打印第二个联系人的号码电话会把第一个联系人的生日一同打印出来
   
    for(i=0;i<10;i++)
    {
     NewContact.BirthDay[i]=ReadBuffer[i+26];
    }
    i=0;
    printf("生日:%s ",NewContact.BirthDay);
 
          
  while(1);          
}

 2、今天的主角:i2c_at24c02.c

#include"stm32f10x.h"
#include"i2c_at24c02.h"


#define AT24Cx_Address           0xa0        //I2C芯片地址 EEPROM
#define AT24Cx_PageSize                 //芯片内部一页容量


static void I2C_ATC24x_GPIO_Config(void)
{
  GPIO_InitTypeDef               GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(I2C_SCL_GPIO_RCC,ENABLE);            //没有外部中断,没有重映射,所以不需要开启复用功能
  
 
  GPIO_InitStructure.GPIO_Pin    =I2C_SCL_Pin|I2C_SDA_Pin;
  GPIO_InitStructure.GPIO_Speed  =GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode   =GPIO_Mode_AF_OD;            //设置管脚为复用功能开漏输出 SDA是输入输出引脚

  GPIO_Init(I2C_SCL_GPIO, &GPIO_InitStructure);
}



static void I2C_Config(void)
{
  I2C_InitTypeDef            I2C_InitStructure;

 
  RCC_APB1PeriphClockCmd(I2C_RCC,ENABLE);

 
  I2C_DeInit(I2C);

  I2C_InitStructure.I2C_ClockSpeed          =100000;    //100KHz I2C时钟频率
  I2C_InitStructure.I2C_Mode                =I2C_Mode_I2C;   //I2C模式
  I2C_InitStructure.I2C_DutyCycle           =I2C_DutyCycle_2; //时钟占空比
  I2C_InitStructure.I2C_OwnAddress1         =0x30;     //主机地址 可以任意的
  I2C_InitStructure.I2C_Ack                 =I2C_Ack_Enable;  //开启ACK应答响应
  I2C_InitStructure.I2C_AcknowledgedAddress =I2C_AcknowledgedAddress_7bit;//7位地址模式 非10为地址模式

 
  I2C_Init(I2C,&I2C_InitStructure);

 
  I2C_Cmd(I2C,ENABLE);

 
  I2C_AcknowledgeConfig(I2C,ENABLE);
}



void I2C_AT24Cx_Init(void)
{
  I2C_ATC24x_GPIO_Config();

  I2C_Config();
}


void I2C_AT24Cx_Reads(u8 Address,u8 *ReadBuffer,u16 ReadNumber)
{
  if(ReadNumber==0)                           //没有需要读取的数据
    return;

 
  while(I2C_GetFlagStatus(I2C,I2C_FLAG_BUSY));

 
  I2C_AcknowledgeConfig(I2C, ENABLE);

 
  I2C_GenerateSTART(I2C,ENABLE);
  while(!I2C_CheckEvent(I2C,I2C_EVENT_MASTER_MODE_SELECT));                 //检查是不是主模式与起始位已经发送 备注:这样做的目的就是为了清空该事件

 
  I2C_Send7bitAddress(I2C,AT24Cx_Address, I2C_Direction_Transmitter);
  while (!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//检查数据是不是已经发送地址完成

 
  I2C_SendData(I2C, Address);
  while (!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));         //检查数据是不是已经发送完成
 
                  //需要读取数据,这个时候需要变换数据传输方向,就要主机重新发送起始位
  I2C_GenerateSTART(I2C, ENABLE);
  while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_MODE_SELECT));
 
 
  I2C_Send7bitAddress(I2C,AT24Cx_Address, I2C_Direction_Receiver);         //再一次发送EEPROM地址
  while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

 
  while(ReadNumber)
  {
   
 if(ReadNumber==1)
 {
   I2C_AcknowledgeConfig(I2C, DISABLE);         //关闭应答
   I2C_GenerateSTOP(I2C,ENABLE);           //使能停止功能
 }

 while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_BYTE_RECEIVED));            //检查是不是接受到了数据
 *ReadBuffer=I2C_ReceiveData(I2C);
 ReadBuffer++;
 ReadNumber--;
  }
  I2C_AcknowledgeConfig(I2C, ENABLE);          //允许应答模式
}



static void I2C_AT24Cx_WaitForComplete(void)
{
  vu16 SR1_Tmp;
  do
  {
   
    I2C_GenerateSTART(I2C1, ENABLE);                                       //一旦发送起始位,主机等待读取SR1,然后发送地址
   
    SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1);        //也是为了清除该事件
   
 I2C_Send7bitAddress(I2C1,AT24Cx_Address, I2C_Direction_Transmitter);
  }while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));            //直到地址发送完成
 
 
  I2C_ClearFlag(I2C, I2C_FLAG_AF);                                        //前面如果出现过忙碌 就会出现应答错误现象
     
  I2C_GenerateSTOP(I2C, ENABLE);
}



void I2C_AT24Cx_WriteByte(u8 Address,u8 WriteData)
{
 
  I2C_GenerateSTART(I2C, ENABLE);
  while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_MODE_SELECT)); 

 
  I2C_Send7bitAddress(I2C,AT24Cx_Address, I2C_Direction_Transmitter);
  while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //实际就是等待收到EEPROM的ACK应答信号(收到ACK后,硬件会做相应的置位)
 
 
  I2C_SendData(I2C, Address);
  while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

 
  I2C_SendData(I2C, WriteData);
  while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
 
 
  I2C_GenerateSTOP(I2C, ENABLE);                                        //这里的设置停止为与接收时不同 这里是写入最后一个数据之后设置停止位
 
  I2C_AT24Cx_WaitForComplete();
}



void I2C_AT24Cx_WritePage(u8 Address,u8 *WriteData,u16 WriteNumber)
{
  while(I2C_GetFlagStatus(I2C, I2C_FLAG_BUSY));

 
  I2C_GenerateSTART(I2C, ENABLE);
  while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_MODE_SELECT));

 
  I2C_Send7bitAddress(I2C,AT24Cx_Address, I2C_Direction_Transmitter);
  while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
 
 
  I2C_SendData(I2C,Address);
  while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  while(WriteNumber--) 
  {
 I2C_SendData(I2C,*WriteData);
 WriteData++;
 while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
  }
 
 
  I2C_GenerateSTOP(I2C, ENABLE);
}



void I2C_AT24Cx_Writes(u8 Address,u8 *WriteData,u16 WriteNumber)
{
  u8 Temp;
 
 
  Temp=Address%AT24Cx_PageSize; 
  if(Temp)            //存在页不对齐的现象
  {
    Temp=AT24Cx_PageSize-Temp;       //求出页不对齐的数量
 I2C_AT24Cx_WritePage(Address,WriteData,Temp);
 Address+=Temp;
 WriteData+=Temp;
 WriteNumber-=Temp;
 I2C_AT24Cx_WaitForComplete(); 
  }

  while(WriteNumber)
  {
   
    if(WriteNumber>=AT24Cx_PageSize)
    {
     I2C_AT24Cx_WritePage(Address,WriteData,AT24Cx_PageSize);
   Address+=AT24Cx_PageSize;
   WriteData+=AT24Cx_PageSize;
   WriteNumber-=AT24Cx_PageSize;
   I2C_AT24Cx_WaitForComplete();
    }
   
    else
    {
     I2C_AT24Cx_WritePage(Address,WriteData,WriteNumber);
   WriteNumber=0;
   I2C_AT24Cx_WaitForComplete();
    }
  }
}

 

    i2c_at24c02.h


#ifndef _I2C_AT24C02_H
#define _I2C_AT24C02_H

#include"stm32f10x.h"


#define I2C                   I2C1
#define I2C_RCC               RCC_APB1Periph_I2C1

#define I2C_SCL_GPIO_RCC      RCC_APB2Periph_GPIOB
#define I2C_SCL_GPIO          GPIOB
#define I2C_SCL_Pin           GPIO_Pin_6

#define I2C_SDA_GPIO_RCC      RCC_APB2Periph_GPIOB
#define I2C_SDA_GPIO          GPIOB
#define I2C_SDA_Pin           GPIO_Pin_7

void I2C_AT24Cx_Init(void);                                          //I2C外设与AT24C02初始化

void I2C_AT24Cx_Reads(u8 Address,u8 *ReadBuffer,u16 ReadNumber);     //从AT24C02中读取数据 EEPROM

void I2C_AT24Cx_WriteByte(u8 Address,u8 WriteData);                  //写入一字节数据

void I2C_AT24Cx_WritePage(u8 Address,u8 *WriteData,u16 WriteNumber);  //写入一页之内数据

void I2C_AT24Cx_Writes(u8 Address,u8 *WriteData,u16 WriteNumber);     //写入任意数量的数据 流程:写入也不对齐部分--写入整页部分(假如需要)--写入最后不足一页的
#endif

 

   剩下的串口驱动与LED驱动分别见:《STM32 串口例程之查询收发》、《STM32 基于库函数控制按键 蜂鸣器 LED显示》完全一样的。这里就不在重复上代码了。

 

以上,结束。

关键字:STM32  I2C  AT24C02驱动 引用地址:STM32 I2C AT24C02驱动

上一篇:STM32 SPI W25X16驱动
下一篇:STM32 RTC之日历显示

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

STM32的ADC采样周期确定
一 STM32 ADC 采样 频率的确定 1. : 先看一些资料,确定一下ADC 的 时钟: (1),由 时钟控制器提供的ADCCLK 时钟和PCLK2(APB2 时钟)同步。CLK 控制器为ADC 时钟提供一个专用的可编程预分频器。 (2) 一般情况下在程序 中将 PCLK2 时钟设为 与系统时钟 相同 RCC_HCLKConfig(RCC_SYSCLK_Div1); RCC_PCLK2Config(RCC_HCLK_Div1); RCC_PCLK1Config(RCC_HCLK_Div2); (3)在时钟配置寄存器(RCC_CFGR) 中
[单片机]
1.10.6_I2C_EEPROM编程和测试代码_P
根据AT24cxx手册,可以得到地址信息,还需要对照2440的原理图查看A0,A1,A2分别接到哪个引脚。 由于AT24cxx在SPI模块上,而SPI模块目前停售,所以本节只编写一个可以正常运行的程序,了解原理和使用过程即可。 根据AT24cxx的原理图可以看到,使用的型号是AT24C02A,其中A0,A1,A2都接到地。 所以使用的是2K(256字节,256bytes*8=2048bits)大小的EEPROM设备,设备地址为0x50(写)或0x51(读),最低位为读写标志位,IIC协议规定,0表示读,1表示写。 然后仿照nor flash的测试函数,写出AT24cxx的测试函数,实现读和写的功能。 读数
[单片机]
1.10.6_I2C_EEPROM编程和测试代码_P
STM32学习笔记(2):外部中断的使用
中断对于开发嵌入式系统来讲的地位绝对是毋庸置疑的,在C51单片机时代,一共只有5个中断,其中2个外部中断,2个定时/计数器中断和一个串口中断,但是在STM32中,中断数量大大增加,而且中断的设置也更加复杂。今天就将来探讨一下关于STM32中的中断系统。 1 基本概念 ARM Coetex-M3内核共支持256个中断,其中16个内部中断,240个外部中断和可编程的256级中断优先级的设置。STM32目前支持的中断共84个(16个内部+68个外部),还有16级可编程的中断优先级的设置,仅使用中断优先级设置8bit中的高4位。 STM32可支持68个中断通道,已经固定分配给相应的外部设备,每个中断通道都具备自己的中断优先级控制字节PR
[单片机]
STM32定时器不准确启动时钟的问题
用STM32 F407IG 开发一硬件控制器,需要精准的定时器。我使用了IIM2,可上电启动。有时候准确,有时候开机 定时器,很慢,比如定时500MS 闪烁一次,可能3秒才闪烁一次。源代码如下。 int main(void) { GPIO_Configuration(); TIM_Config(); NVIC_TIM_Config(); while(1) { } } void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(LED1_RCC_AHBPeriph|LED2_RC
[单片机]
基于I2C总线的MSP430单片机应用系统设计
串行护展总线技术是新一代单片机技术发展的一个显著特点。其中PHILIPS公司推出的I2C总线最为著名,它包括一个两端接口,通过一个带有缓冲区的接口,数据可以被I2C发送或接收,控制和状态信息则通过一套内存映射寄存器来传送。与并行扩展总线相比,串行扩展总线有突出的优点:电路结构简单,程序编写方便,易于实现用户系统软硬件的模块化、标准化等。本文是把I2C总线应用到MSP430单片机温度控制系统中的一个典型实例。 I2C总线是用2根双向I/O信号线(串行时钟线SCL和串行数据线SDA)把多种器件连接起来,并实现器件之间的串行通讯。 MSP430是TI公司一种具有超低功耗的功能强大的16位单片机,MSP430F169是该系列中的一
[单片机]
基于<font color='red'>I2C</font>总线的MSP430单片机应用系统设计
STM32 TM1640芯片驱动程序
以下为.h文件: #ifndef __TM1640_H__ #define __TM1640_H__ #include stm32f10x.h #define ADDR_START1640 0XC0 #define DSP1640_DIS 0 #define DSP1640_ENB 1 /* 控制显示 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f 分别对应 1/16, 2/16, 4/16, 10/16, 11/16, 12/16, 13/16, 14/16 设置数据,0x40,0x44分别对应地址自动加一和固定地址模式 */
[单片机]
<font color='red'>STM32</font> TM1640芯片<font color='red'>驱动</font>程序
STM32的SPI问题。
问题描述: 之前一直使用的单片机是LPC2109,对其SPI很熟悉。基本就是原本拿来稍作修改就用。 由于某种原因需要使用STM32,然后设备的驱动是之前写好的,只修改了一些硬件控制端口,由于硬件驱动使用到了SPI接口,而我是把SPI接口提供了出来,本来以为简单修改SPI配置到对应单片机就行了。简单看了STM3的SPI配置,轻车熟路改代码,瞬间体现了良好的接口有哈。 编译,生成目标文件,下载运行。 并没有出现预想的结果。由于之前的设备驱动是能用的,所以排除设备驱动问题。 开始以为是由于对STM32端口配置的不熟悉导致的、看手册,看别人代码,没发现问题。 debug........ 问题定在SPI代码上。查看配置,一样啊。郁闷!!! 把
[单片机]
<font color='red'>STM32</font>的SPI问题。
STM32串口通信过程详解
按照数据传送方向分类: 单工:数据传输只支持数据在一个方向上传输; 半双工:允许数据在两个方向上传输。但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;它不需要独立的接收端和发送端,两者可以合并一起使用一个端口; 全双工:允许数据同时在两个方向上传输。因此,全双工通信是两个单工通信方式的结合,需要独立的接收端和发送端。 分别如下图中的a、b、c所示: 按照通信方式分类: 同步通信:带时钟同步信号传输。比如:SPI,IIC通信接口; 异步通信:不带时钟同步信号。比如:UART(通用异步收发器),单总线; 在同步通讯中,收发设备上方会使用一根信号线传输信号,在时钟信号的驱动下双方进行协调,同步数
[单片机]
<font color='red'>STM32</font>串口通信过程详解
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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