I2C总线一根数据线,一根时钟线,起始和终止条件如下:
AT24C32是一款4K字节的EEPROM,它的字节写如下图:
具体的文字描述结合我的程序一看就明白了,我的程序注释非常丰富
/*****************************************
*文件名:at24c32.c *
*功能:EEPROM读写程序 *
******************************************/
#include "at24c32.h"
void at24c32_write (uint8_t device_address, uint8_t data_high_address, uint8_t data_low_address, uint8_t data_);
uint8_t at24c32_read (uint8_t device_address, uint8_t data_high_address, uint8_t data_low_address);
/**************************************************
*函数名:at24c32_initialize *
*功能: EEPROM初始化 *
*出口参数:无 *
*入口参数:无 *
**************************************************/
void at24c32_initialize (void)
{
uint8_t temp_data = 0;
DrvGPIO_InitFunction (E_FUNC_I2C1); //PA.10,PA.11设置为I2C
DrvSYS_UnlockProtectedReg (); //解锁受保护的系统寄存器
DrvSYS_SetIPClock (E_SYS_I2C1_CLK, 1); //使能I2C端口1的核心时钟
DrvSYS_LockProtectedReg (); //对系统寄存器上锁
DrvI2C_Open (I2C_PORT1, 100000); //使能I2C端口1,时钟为100KHz
//由于所有I2C端口共用一个时钟分频器,所以每个I2C端口的时钟频率必须设为一致,且不能超过1MHz
delay (100); //延迟使时钟稳定
temp_data = at24c32_read (DEVICE_ADDRESS, EEPROM_INITIALIZED_HIGH_ADDRESS, EEPROM_INITIALIZED_LOW_ADDRESS);
if (temp_data != 0xfe)
{
at24c32_write(DEVICE_ADDRESS, EEPROM_INITIALIZED_HIGH_ADDRESS, EEPROM_INITIALIZED_LOW_ADDRESS, 0xfe); //对最后一个地址写数据表明EEPROM已被初始化
at24c32_write(DEVICE_ADDRESS, RADIO_MAIN_HIGH_ADDRESS, RADIO_MAIN_LOW_ADDRESS, RADIO_MAIN_DEFAULT);
at24c32_write(DEVICE_ADDRESS, ENABLE_PTT_LIMIT_HIGH_ADDRESS, ENABLE_PTT_LIMIT_LOW_ADDRESS, ENABLE_PTT_LIMIT_DEFAULT);
at24c32_write(DEVICE_ADDRESS, PTT_LIMIT_TIME_HIGH_ADDRESS, PTT_LIMIT_TIME_LOW_ADDRESS, PTT_LIMIT_TIME_DEFAULT);
at24c32_write(DEVICE_ADDRESS, POWER_VALUE_HIGH_ADDRESS, POWER_VALUE_LOW_ADDRESS, POWER_VALUE_DEFAULT);
at24c32_write(DEVICE_ADDRESS, MODULATION_VALUE_HIGH_ADDRESS, MODULATION_VALUE_LOW_ADDRESS, MODULATION_VALUE_DEFAULT);
at24c32_write(DEVICE_ADDRESS, ENABLE_ERROR_HIGH_ADDRESS, ENABLE_ERROR_LOW_ADDRESS, ENABLE_ERROR_DEFAULT);
at24c32_write(DEVICE_ADDRESS, FREQUENCY_HIGH_ADDRESS, FREQUENCY_LOW_ADDRESS, FREQUENCY_DEFAULT);
at24c32_write(DEVICE_ADDRESS, CHANNEL_SPACE_HIGH_ADDRESS, CHANNEL_SPACE_LOW_ADDRESS, CHANNEL_SPACE_DEFAULT);
}
}
/**************************************************
*函数名:at24c32_write *
*功能: EEPROM写程序 *
*出口参数:无 *
*入口参数:设备8位地址,写数据高8位地址, *
* 低8位地址,8位数据 *
**************************************************/
void at24c32_write (uint8_t device_address, uint8_t data_high_address, uint8_t data_low_address, uint8_t data_)
{
DrvI2C_Ctrl (I2C_PORT1, 1, 0, 0, 0); //I2C端口1发送一个起始标志(注释若有不明白的,参芯片手册中文版216页起好好看看)
while ((DrvI2C_GetIntFlag (I2C_PORT1)) == 0) //查询中断标志位SI,当起始已被发送时,SI为0x08
{
}
DrvI2C_WriteData (I2C_PORT1, device_address); //将at24c32设备地址(高7位)+写命令(0)存入I2CDAT中
DrvI2C_Ctrl (I2C_PORT1, 0, 0, 1, 0); //清除中断标志位,准备发送地址+写命令(0)
while ((DrvI2C_GetIntFlag (I2C_PORT1)) == 0) //查询中断标志位,当从机地址+W已被发送且收到ACK时SI 不为0,为0x18
{
}
DrvI2C_WriteData (I2C_PORT1, data_high_address); //将数据高8位地址(前四位任意)存入I2CDAT中
DrvI2C_Ctrl (I2C_PORT1, 0, 0, 1, 0); //清除中断标志位,准备发送数据高8位地址
while ((DrvI2C_GetIntFlag (I2C_PORT1)) == 0) //查询中断标志位,当高8位地址已被发送且收到ACK时SI 不为0,为0x28
{
}
DrvI2C_WriteData (I2C_PORT1, data_low_address); //将数据低8位地址存入I2CDAT中
DrvI2C_Ctrl (I2C_PORT1, 0, 0, 1, 0); //清除中断标志位,准备发送数据低8位地址
while ((DrvI2C_GetIntFlag (I2C_PORT1)) == 0) //查询中断标志位,当高8位地址已被发送且收到ACK时SI 不为0,为0x28
{
}
DrvI2C_WriteData (I2C_PORT1, data_); //将要写的数据存入I2CDAT中
DrvI2C_Ctrl (I2C_PORT1, 0, 0, 1, 0); //清除中断标志位,准备发送要写入的数据
while ((DrvI2C_GetIntFlag (I2C_PORT1)) == 0) //查询中断标志位,当高8位地址已被发送且收到ACK时SI 不为0,为0x28
{
}
DrvI2C_Ctrl (I2C_PORT1, 0, 1, 1, 0); //I2C端口1发送一个结束标志且清除SI
delay(MINIMUM_DELAY); //at24c32写数据之后要给至少10ms才能再写一个数据,在此给40ms延迟
}
/**************************************************
*函数名: at24c32_read *
*功能: EEPROM读程序 *
*出口参数:读取的8位数据 *
*入口参数:读数据高8位地址,低8位地址 *
*************************************************/
uint8_t at24c32_read (uint8_t device_address, uint8_t data_high_address, uint8_t data_low_address)
{
uint8_t data_read;
DrvI2C_Ctrl (I2C_PORT1, 1, 0, 0, 0); //I2C端口1发送一个起始标志
while ((DrvI2C_GetIntFlag (I2C_PORT1)) == 0) //查询中断标志位SI,当起始已被发送时,SI为0x08
{
}
DrvI2C_WriteData (I2C_PORT1, device_address); //将at24c32设备地址(高7位)+写命令(0)存入I2CDAT中
DrvI2C_Ctrl (I2C_PORT1, 0, 0, 1, 0); //清除中断标志位,准备发送地址+写命令(0)
while ((DrvI2C_GetIntFlag (I2C_PORT1)) == 0); //查询中断标志位,当从机地址+W已被发送且收到ACK时SI 不为0,为0x18
{
}
DrvI2C_WriteData (I2C_PORT1, data_high_address); //将数据高8位地址(前四位任意)存入I2CDAT中
DrvI2C_Ctrl (I2C_PORT1, 0, 0, 1, 0); //清除中断标志位,准备发送数据高8位地址
while ((DrvI2C_GetIntFlag (I2C_PORT1)) == 0); //查询中断标志位,当高8位地址已被发送且收到ACK时SI 不为0,为0x28
{
}
DrvI2C_WriteData (I2C_PORT1, data_low_address); //将数据低8位地址存入I2CDAT中
DrvI2C_Ctrl (I2C_PORT1, 0, 0, 1, 0); //清除中断标志位,准备发送数据低8位地址
while ((DrvI2C_GetIntFlag (I2C_PORT1)) == 0); //查询中断标志位,当高8位地址已被发送且收到ACK时SI 不为0,为0x28
{
}
DrvI2C_Ctrl (I2C_PORT1, 1, 0, 1, 0); //发送一个再开始标志并清SI
while ((DrvI2C_GetIntFlag (I2C_PORT1)) == 0); //查询中断标志位SI,当再开始起始已被发送时,SI为0x10
{
}
DrvI2C_WriteData (I2C_PORT1, device_address+1); //将at24c32设备地址+读命令(1),+1表示读存入I2CDAT中
DrvI2C_Ctrl (I2C_PORT1, 0, 0, 1, 0); //清除SI准备发送从机地址+读命令
while ((DrvI2C_GetIntFlag (I2C_PORT1)) == 0); //查询中断标志位,当从机地址+读命令已发送且收到ACK时,SI不为0,为0x40
{
}
DrvI2C_Ctrl (I2C_PORT1, 0, 0, 1, 0); //清除中断标志位,不设置ACK,因为24C32读数据不会回传ACK应答
while ((DrvI2C_GetIntFlag (I2C_PORT1)) == 0); //查询中断标志位,若已收到数据且无ACK时,SI不为0,为0x58
{
}
data_read = DrvI2C_ReadData (I2C_PORT1); //读取数据
DrvI2C_Ctrl (I2C_PORT1, 0, 1, 1, 0); //清除SI且发生结束标志
return (data_read);
}
头文件如下:
#ifndef at24c32_h
#define at24c32_h
#include "stdint.h"
#include "common_variables.h"
#include "DrvGPIO.h"
#include "DrvI2C.h"
#include "DrvSYS.h"
#include "delay.h"
#define MINIMUM_DELAY 150 //at24c32写数据最低延迟时间10ms,在此给15ms
//定义AT24C32的地址单元
#define DEVICE_ADDRESS 0xa0 //EEPROM地址,1010 0000,前四位固定,地址为000,最后一位写是0,读是1
#define EEPROM_INITIALIZED_HIGH_ADDRESS 0xff //判断EEPROM是否以及被初始化的地址单元
#define EEPROM_INITIALIZED_LOW_ADDRESS 0xff
#define RADIO_MAIN_HIGH_ADDRESS 0xf0
#define RADIO_MAIN_LOW_ADDRESS 0x01
#define RADIO_MAIN_DEFAULT 0x00
#define ENABLE_PTT_LIMIT_HIGH_ADDRESS 0xf0
#define ENABLE_PTT_LIMIT_LOW_ADDRESS 0x02
#define ENABLE_PTT_LIMIT_DEFAULT 0x01
#define PTT_LIMIT_TIME_HIGH_ADDRESS 0xf0
#define PTT_LIMIT_TIME_LOW_ADDRESS 0x03
#define PTT_LIMIT_TIME_DEFAULT 0x01
#define POWER_VALUE_HIGH_ADDRESS 0xf0
#define POWER_VALUE_LOW_ADDRESS 0x04
#define POWER_VALUE_DEFAULT 0x32
#define MODULATION_VALUE_HIGH_ADDRESS 0xf0
#define MODULATION_VALUE_LOW_ADDRESS 0x05
#define MODULATION_VALUE_DEFAULT 0x5a
#define ENABLE_ERROR_HIGH_ADDRESS 0xf0
#define ENABLE_ERROR_LOW_ADDRESS 0x06
#define ENABLE_ERROR_DEFAULT 0x01
#define FREQUENCY_HIGH_ADDRESS 0xf0
#define FREQUENCY_LOW_ADDRESS 0x07
#define FREQUENCY_DEFAULT 0x76
#define CHANNEL_SPACE_HIGH_ADDRESS 0xf0
#define CHANNEL_SPACE_LOW_ADDRESS 0x08
#define CHANNEL_SPACE_DEFAULT 0x01
extern void at24c32_initialize (void); //初始化at24c32
extern void at24c32_write (uint8_t device_address, //EEPROM地址
uint8_t data_high_address, //写数据高8为地址,前四位任意
uint8_t data_low_address, //写数据低8位地址
uint8_t data_); //8位数据
extern uint8_t at24c32_read (uint8_t device_address, //EEPROM地址
uint8_t data_high_address, //读数据高8位地址
uint8_t data_low_address); //读数据低8为地址
#endif
注意!!!
对AT24C32连续写数据时,每写一个字节要等待10ms,否则会写入失败,这是由芯片特性决定的,
可以参看DATASHEET。