本例程主要作为作者的学习记录,意义在于E2PROM使用页缓冲器连续读写,基于STM32,作用51也很好移植,只需改动端口定义
#ifndef AT24CXX_H
#define AT24CXX_H
#include "stm32f10x.h"
#include "sys.h"
#include "delay.h"
#include "stdio.h"
#define E2PROM_I2C_SDA_RE PBin(11)
#define E2PROM_I2C_SDA_WR PBout(11)
#define E2PROM_I2C_SCL PBout(10)
#define I2C_SetOut_Mode() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=0X00003000;}
#define I2C_SetIn_Mode() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=0X00008000;GPIOB->ODR|=0X01<11;}
#define PROM_device_addr 0xa0
#define AT24cxxpage_size 8 //字节页写缓冲器大小
#define AT24CXX_size 256 //E2PROM容量大小 BYTE
void E2PROM_I2C_PORT_Init(void);
void I2C_delay(void);
void E2PROM_I2C_start(void);
void E2PROM_I2C_stop(void);
u8 E2PROM_I2C_check_ack(void);
void E2PROM_I2C_ack(void);
void E2PROM_I2C_NoAck(void);
void E2PROM_I2C_write_char(u8 dat);
u8 E2PROM_I2C_read_char(void);
void AT24CXX_Read(u8 DeviceAddr,u8 *pbuffer,u16 ReadAddr,u16 length,u16 *readed);
void AT24CXX_Write_Page(u8 DeviceAddr,u8 *pbuffer,u8 Write_Addr,u8 length);
void AT24CXX_Write(u8 DeviceAddr,u8 *pbuffer,u8 Write_Addr,u16 length,u16 *written);
#endif
#include "at24cxx.h"
void E2PROM_I2C_PORT_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10|GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_11|GPIO_Pin_10);
}
void I2C_delay(void)
{
u16 i;
/*
下面的时间是通过逻辑分析仪测试得到的。
工作条件:CPU主频72MHz ,MDK编译环境,1级优化
循环次数为10时,SCL频率 = 205KHz
循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us
循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us
*/
for(i=0;i<3;i++);
}
void E2PROM_I2C_start(void)
{
I2C_SetOut_Mode();
E2PROM_I2C_SCL=0;
E2PROM_I2C_SDA_WR=1;
E2PROM_I2C_SCL=1;
I2C_delay();
E2PROM_I2C_SDA_WR=0;
E2PROM_I2C_SCL=0;
I2C_delay();
}
void E2PROM_I2C_stop(void)
{
I2C_SetOut_Mode();
E2PROM_I2C_SCL=0;
E2PROM_I2C_SDA_WR=0;
E2PROM_I2C_SCL=1;
I2C_delay();
E2PROM_I2C_SDA_WR=1;
E2PROM_I2C_SCL=0;
I2C_delay();
E2PROM_I2C_SDA_WR=1;//拉高时钟和数据线,降低功耗
E2PROM_I2C_SCL=1;
}
u8 E2PROM_I2C_check_ack(void)
{
u8 ack_status=0X01;
I2C_SetIn_Mode();
E2PROM_I2C_SCL=0;
E2PROM_I2C_SDA_WR=1;
E2PROM_I2C_SCL=1;
I2C_delay();
ack_status=0x01&E2PROM_I2C_SDA_RE;
E2PROM_I2C_SCL=0;
I2C_delay();
return ack_status;
}
void E2PROM_I2C_ack(void)
{
I2C_SetOut_Mode();
E2PROM_I2C_SCL=0;
E2PROM_I2C_SDA_WR=0;
E2PROM_I2C_SCL=1;
I2C_delay();
E2PROM_I2C_SCL=0;
I2C_delay();
E2PROM_I2C_SDA_WR=1;
}
void E2PROM_I2C_NoAck(void)
{
I2C_SetOut_Mode();
E2PROM_I2C_SCL=0;
E2PROM_I2C_SDA_WR=1;
I2C_delay();
E2PROM_I2C_SCL=1;
I2C_delay();
E2PROM_I2C_SCL=0;
I2C_delay();
}
void E2PROM_I2C_write_char(u8 dat)
{
u8 i=0;
E2PROM_I2C_SCL=0;
I2C_SetOut_Mode();
for(i=0;i<8;i++)
{
if(dat&0x80) E2PROM_I2C_SDA_WR=1;
else E2PROM_I2C_SDA_WR=0;
I2C_delay();
E2PROM_I2C_SCL=1;
I2C_delay();
E2PROM_I2C_SCL=0;
dat<<=1;
}
}
u8 E2PROM_I2C_read_char(void)
{
u8 i=0,dat=0;
E2PROM_I2C_SCL=0;
I2C_SetIn_Mode();
for(i=0;i<8;i++)
{
dat<<=1;
E2PROM_I2C_SCL=1;
I2C_delay();
if(E2PROM_I2C_SDA_RE) dat|=0x01;
E2PROM_I2C_SCL=0;
I2C_delay();
}
return dat;
}
void AT24CXX_Read(u8 DeviceAddr,u8 *pbuffer,u16 ReadAddr,u16 length,u16 *readed)
{
u16 i=0;
*readed=0;
if(length>AT24CXX_size) length=AT24CXX_size; /*避免读数据超出容易*/
if(length+ReadAddr>AT24CXX_size) length=AT24CXX_size-ReadAddr;
E2PROM_I2C_start();
E2PROM_I2C_write_char(DeviceAddr);
E2PROM_I2C_check_ack();
E2PROM_I2C_write_char(ReadAddr);
E2PROM_I2C_check_ack();
E2PROM_I2C_start();
E2PROM_I2C_write_char(DeviceAddr|0x01);
E2PROM_I2C_check_ack();
for(i=0;i=length) break;
E2PROM_I2C_ack();
}
*readed+=length;
E2PROM_I2C_NoAck();
E2PROM_I2C_stop();
}
//使用页写缓冲器写入,以提高速度
//在指定地址开始写入最大T24cxxpage_size字节的数据
//pbuffer:数据存储区
//Write_Addr:开始写入的地址
//length:要写入的字节数(最大T24cxxpage_size),该数不应该超过该页的剩余字节数!!!
void AT24CXX_Write_Page(u8 DeviceAddr,u8 *pbuffer,u8 Write_Addr,u8 length)
{
u16 i=0;
E2PROM_I2C_start();
E2PROM_I2C_write_char(DeviceAddr);
E2PROM_I2C_check_ack();
E2PROM_I2C_write_char(Write_Addr);
E2PROM_I2C_check_ack();
for(i=0;iAT24CXX_size) length=AT24CXX_size; /*避免写数据超出容量*/
if(length+Write_Addr>AT24CXX_size) length=AT24CXX_size-Write_Addr;
PageRmain=AT24cxxpage_size-Write_Addr%AT24cxxpage_size;//单页剩余的字节数
if(length<=PageRmain) PageRmain=length;
while(1)
{
AT24CXX_Write_Page(DeviceAddr,pbuffer,Write_Addr,PageRmain);
*written+=PageRmain; //累加被写入的字节数
if(PageRmain==length) break;
else
{
pbuffer+=PageRmain;
Write_Addr+=PageRmain;
length-=PageRmain;
if(length>AT24cxxpage_size) PageRmain=AT24cxxpage_size;
else PageRmain=length;
}
}
}
#include "stm32f10x.h"
#include "delay.h"
#include "at24cxx.h"
#include "usart.h"
#define USART1_Bound 115200
u8 E2PROM_buffer[256];
u8 E2PROM_buffer2[256];
int main(void)
{
u16 i,j,k;
u16 timer2_data_us,timer2_data_ms;
u16 count=0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Delay_Init();
MY_USART1_Init(USART1_Bound);
E2PROM_I2C_PORT_Init();
for(i=0;i<256;i++)
{
E2PROM_buffer[i]= i;
}
AT24CXX_Write(PROM_device_addr,E2PROM_buffer,0,256,&e2prom_count);
printf("write number:%d\r\n",e2prom_count);
AT24CXX_Read(PROM_device_addr,E2PROM_buffer_read,0,256,&e2prom_count);
printf("read number:%d\r\n",e2prom_count);
for(i=0;i<16;i++)
{
for(j=0;j<16;j++)
{
printf("%d ",E2PROM_buffer2[i*16+j]);
}
printf("\r\n");
}
for(i=0;i<255;i++)
{
if((E2PROM_buffer_read[i]-E2PROM_buffer_read[i+1]!=1 )&&
E2PROM_buffer_read[i+1]-E2PROM_buffer_read[i]!=1)
break;
}
if(i>=255) printf("\r\n E2PROM test OK \r\n");
else printf("\r\n E2PROM test error!! %d \r\n",E2PROM_buffer_read[i]);
while(1);
}