不使用固件库,直接控制寄存器写读eeprom,出现不能读的问题。请各位帮忙看看。(iar5.2 ,j-linkv7调试)
#include "stm32f10x_lib.h"
volatile unsigned int SR1,SR2;
volatile unsigned int DataInEeprom;
void Delay (void)
{
volatile unsigned int i;
for(i=0;i<0xf;i++);
}
void I2C_Configuration(void)
{
I2C1->CR1|=(1<<1);//I2C模式
I2C1->CCR&=0x0000;//I2C标准模式时钟
I2C1->CCR|=0x28;//分频系数为40
I2C1->TRISE|=0x0009;//最大上升时间
I2C1->CR2|=0x0008;//设置I2C的时钟为8
I2C1->CR1|=(1<<0);//I2C模块使能
}
void RCC_Configuration(void)
{
FLASH->ACR=0x32;//设置flash等待周期为2,否则设置为72M系统时钟时就会跑飞
RCC->CR|=(1<<16);//使能外部高速时钟
while(!((RCC->CR>>17)&0x00000001));//等待外部高速时钟稳定
RCC->CFGR|=0x00010020;//PLL倍频设置为2倍(外部时钟12M,PLL输出24M)
//HSE不分频
//HSE选作做为PLL时钟源输入
//APB1设置为2分频
RCC->CR|=(1<<24); //启动PLL
while((RCC->CR>>26)&0x00000001);//等待PLL稳定
RCC->CFGR|=(1<<1);//选择PLL输出为时钟源
RCC->APB2ENR|=(1<<3);//始能GPIOB口时钟
RCC->APB2ENR|=(1<<0);//始能GPIOB口时钟
RCC->APB1ENR|=(1<<21);//使能I2C1设备
}
void i2c_cur_add_read(unsigned char DevAddr) //读取当前地址一个字节
{
I2C_Configuration();
I2C1->CR1|=(1<<10);//ACK
I2C1->CR1|=(1<<8);//启动I2C1总线
while(!((I2C1->SR1)&0x0001));//not recommanded, stupid way
SR1=I2C1->SR1;
I2C1->DR = DevAddr;//从设备地址
while(((I2C1->SR1)&0x0002));// 检测到ADDR位
//I2C1->DR=0x0000;
SR1=I2C1->SR1;SR2=I2C1->SR2;
Delay();
while(!((I2C1->SR1)&0x0040));//get data !!!!!!!!调试是程序只能运行到改位置
DataInEeprom=I2C1->DR;//将接收到的数据存到DataInEeprom中
I2C1->CR1&=0xF9FF;//stop I2C1 bus
}
void i2c_24c_byte_write(unsigned char Byte, unsigned char WriteAddr,unsigned char DevAddr)//写入一个字节
{
I2C_Configuration();
I2C1->CR1|=(1<<8);//启动I2C1总线
while(!((I2C1->SR1)&0x0001));//not recommanded, stupid way
I2C1->DR = DevAddr;
while(!((I2C1->SR1)&0x0002));// 检测到ADDR位
Delay();
SR1=I2C1->SR1;SR2=I2C1->SR2;
I2C1->DR = WriteAddr;
while(((I2C1->SR1)&0x0080));// when get ACK, means Set Success
Delay();
I2C1->DR = Byte;
while(((I2C1->SR1)&0x0080));// when get ACK, means Set Success
Delay();
I2C1->CR1|=(1<<9);//stop I2C1 bus
}
void GPIO_Configuration(void)
{
GPIOB->CRL=0xEE344444;//6,7脚复用开漏,5脚通用推挽
}
int main()
{
RCC_Configuration();
GPIO_Configuration();
i2c_24c_byte_write(0xAA, 0x07,0xA0);
i2c_cur_add_read(0xA1);
while(DataInEeprom==0xAA)
//while(1)
{
GPIOB->BRR=(1<<5);
Delay();
GPIOB->BSRR|=(1<<5);
Delay();
}
while(1)
{GPIOB->BSRR|=(1<<5);
}
}
因为不能读取,具体写函数是否正确也不太清楚~请各位前辈帮忙看看。请问是否也有用寄存器直接控制的方法使用eeprom的仁兄,可否让小弟欣赏你下您的程序
我打错字了
我打错字了,请问lut1lut,如果我想往特定的eeprom地址读/写好像你那个就不行。还有读eeprom的的从设备地址应该是0xA1把?
e2prom的地址的低三位取决于
e2prom的三个地址引脚如何连接的。我那个项目是跑在万历板子上的,三个地址引脚都接低电平,所以e2prom的地址是0xA0
“往特定的地址读/写”指的就是e2prom的偏移量吧。在函数的参数第三个参数指定。我试了各种都可以的。
项目中,读写操作有对5和0这两个偏移量操作的。
re1=I2C_Comm_MasterWrite(I2C1, 0xa0, 5, Tx1_Buffer, 2);
re2=I2C_Comm_MasterRead(I2C1, 0xa0, 5, Rx1_Buffer, 2);
re3 = I2C_Comm_MasterWrite(I2C1, 0xa0, 0, Tx1_Buffer, 8);
re4 = I2C_Comm_MasterRead(I2C1, 0xa0, 0, Rx1_Buffer, 8);
说说看怎么个不行法,返回什么样的错误代码?如果有拉示波器看,波形哪里不正确。
是我没说清楚,不好意思
根据Atmel的AT24C02数据手册里的设备地址为
1 0 1 0 A2 A1 A0 R/W 最后一位如果是读操作时应该为高电平,而写操作是则为低电平。
那个往特定地址读写是我表达不清。
你说地偏移量相对的起始地址应该是相对
#define EEPROM_WriteAddress1 0x05(从eeprom0x05开始写入数据)
#define EEPROM_ReadAddress1 0x05(从eeprom0x05开始读出数据)而言的吧?
没有不行,是我搞错了不好意思~
还想弱弱的问一下,该封装是不是stm32运行在任何频率上都可以的?
如果工作频率不同,读写速率不同是不是需要做些修改呢?
谢谢lut1lut 和香版。
除了参考手册上的两条rule要遵守
1. The peripheral input clock frequency must be at least:
● 2 MHz in Standard mode
● 4 MHz in Fast mode
2. FPCLK1 is the multiple of 10 MHz required to generate the Fast clock at 400 kHz.
除此之外,适用于任何合理范围内的CPU频率和I2C总线速度。
呵
我的是读写FM24LC64没问题
写RTC8025没问题
但是读RTC8025不行
搞了一天,现在还没有搞出来
郁闷
void I2C_Configuration(void)
{
I2C_InitTypeDef I2C_InitStructure;
I2C_Cmd(I2C1, DISABLE);
// 恢复I2C总线状态,硬件I2C不能自恢复
I2C_SCL_SDA_Reset(); // 置I2C接口为IO并置高
// 初始化I2C1
I2C_StructInit(&I2C_InitStructure);
I2C_DeInit(I2C1);
// 配置I2C1
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = FM24LC64;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;
// 使能I2C1
I2C_Cmd(I2C1, ENABLE);
// 初始化I2C1配置
I2C_Init(I2C1, &I2C_InitStructure);
#if I2C_WorkMode
// 使能I2C1事件/缓存中断
I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF,ENABLE);
#endif
void I2C_SCL_SDA_Reset(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_WriteBit(GPIOB,GPIO_Pin_8 | GPIO_Pin_9,Bit_SET);
// 重新指定I2C功能
GPIO_PinRemapConfig(GPIO_Remap_I2C1,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
/*
/////////////////////////////////////////////////////////////////////////////////////
//
// 函数名称: I2C_WriteNByte()
//
// 输 入: 从器件地址devaddr
// 子地址类型suba_type 1-单字节地址 2-双字节地址
// 此函数不检查,为了移植方便而加
// 子地址addr,
// 写入的内容放入pBuffer指向的存储区
// 需要读的字节个数在num中
// 输 出: state
// 创 建:
// 创建日期:
// 功能描述: 向有子地址器件写入多字节数据
// 修改日期:
// 修改备注:
//
/////////////////////////////////////////////////////////////////////////////////////
*/
uint8 I2C_WriteNByte( uint8 devaddr,uint8 suba_type,uint32 addr,uint8 *pBuffer,uint32 len )
{
uint8 state;
#if I2C_WorkMode
/* 中断方式 */
I2C1_COM.Addr = addr;
I2C1_COM.DataLen = len;
I2C1_COM.BuffAddr = pBuffer;
I2C1_COM.Direct = Transmitter;
I2C1_COM.AddrType = suba_type;
I2C1_COM.Direct = 0;
I2C1_COM.I2CEnd = 0;
if( devaddr == FM24LC64 ){
I2C1->OAR1 = ( I2C_AcknowledgedAddress_7bit | FM24LC64 );
I2C1_COM.DevAddr = FM24LC64;
}else{
I2C1->OAR1 = ( I2C_AcknowledgedAddress_7bit | RX8025 );
I2C1_COM.DevAddr = RX8025;
}
// 发送启动条件
I2C_GenerateSTART( I2C1, ENABLE );
// 等待结束
while( !I2C1_COM.I2CEnd ){
// 加入超时
;
}
if( I2C1_COM.I2CEnd ){
state = 1;
}else{
state = 0;
}
#else
/* 查询方试 */
if ( len > 0 ){
if( devaddr == FM24LC64 ){
I2C1->OAR1 = ( I2C_AcknowledgedAddress_7bit | FM24LC64 );
}else{
I2C1->OAR1 = ( I2C_AcknowledgedAddress_7bit | RX8025 );
}
// I2C_WaitStandbyState( devaddr );
// 发送启动位
I2C_GenerateSTART( I2C1, ENABLE );
/* Test on EV5 and clear it */
while( ( ( ( (u32)I2C1->SR2 ) << 16 ) | ((u32)I2C1->SR1)&0x00FFFFBF ) != I2C_EVENT_MASTER_MODE_SELECT );
// 发送从机地址
I2C_Send7bitAddress( I2C1,devaddr,I2C_Direction_Transmitter );
/* Test on EV6 and clear it */
while( !I2C_CheckEvent( I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ) );
switch( suba_type ){
case 2:
// 发送子地址,先发送高8位
I2C_SendData(I2C1,(u8)( ( addr >> 8 ) & 0X001F ) );
/* Test on EV8 and clear it */
while( !I2C_CheckEvent( I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED ) );
case 1:
// 发送子地址,后发送低8位
I2C_SendData( I2C1,(u8)( addr & 0X00ff ) );
/* Test on EV8 and clear it */
while( !I2C_CheckEvent( I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED ) );
break;
}
// 开始发送数据
while( len-- ){
I2C_SendData(I2C1,*pBuffer);
pBuffer++;
while ( !I2C_CheckEvent( I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED ) );
}
state = 1;
}else{
state = 0;
}
// 发送停止位
I2C_GenerateSTOP( I2C1,ENABLE );
#endif
delayMs(2);
return(state);
}
/*
/////////////////////////////////////////////////////////////////////////////////////
//
// 函数名称: I2C_ReadNByte()
//
// 输 入: 从器件地址devaddr
// 子地址类型suba_type 1-单字节地址 2-双字节地址,
// 此函数不检查,为了移植方便而加
// 子地址addr,
// 写入的内容放入pBuffer指向的存储区
// 需要读的字节个数在num中
// 输 出: state
// 创 建:
// 创建日期:
// 功能描述: 向有子地址器件读取多字节数据
// 修改日期:
// 修改备注:
//
/////////////////////////////////////////////////////////////////////////////////////
*/
uint8 I2C_ReadNByte( uint8 devaddr,uint8 suba_type,uint32 addr,uint8 *pBuffer,uint32 len )
{
uint8 state;
#if I2C_WorkMode
I2C1_COM.I2CState = 1;
if( I2C_WriteNByte( devaddr,suba_type,addr,pBuffer,0 ) == 1 ){
I2C1_COM.Addr = addr;
I2C1_COM.DataLen = len;
I2C1_COM.BuffAddr = pBuffer;
I2C1_COM.Direct = Receiver;
I2C1_COM.AddrType = suba_type;
I2C1_COM.Direct = 1;
I2C1_COM.I2CEnd = 0;
if( devaddr == FM24LC64 ){
I2C1->OAR1 = ( I2C_AcknowledgedAddress_7bit | FM24LC64 );
I2C1_COM.DevAddr = FM24LC64;
}else{
I2C1->OAR1 = ( I2C_AcknowledgedAddress_7bit | RX8025 );
I2C1_COM.DevAddr = RX8025;
}
// 应答
I2C_AcknowledgeConfig( I2C1,ENABLE );
// 发送启动条件
I2C_GenerateSTART( I2C1, ENABLE );
// 等待结束
while( !I2C1_COM.I2CEnd ){
// 加入超时
;
}
}
if( I2C1_COM.I2CEnd ){
state = 1;
}else{
state = 0;
}
#else
if ( len > 0 ){
if( devaddr == FM24LC64 ){
I2C1->OAR1 = ( I2C_AcknowledgedAddress_7bit | FM24LC64 );
}else{
I2C1->OAR1 = ( I2C_AcknowledgedAddress_7bit | RX8025 );
}
// I2C_WaitStandbyState( devaddr );
// 发送起始位
I2C_GenerateSTART(I2C1,ENABLE);
/* Test on EV5 and clear it */
while( !I2C_CheckEvent( I2C1,I2C_EVENT_MASTER_MODE_SELECT ) );
/* In the case of a single data transfer disable ACK before reading the data */
if( len == 1 ){
I2C_AcknowledgeConfig(I2C1,DISABLE);
}
// 发送器件地址
I2C_Send7bitAddress( I2C1,devaddr,I2C_Direction_Transmitter );
/* Test on EV6 and clear it */
while( !I2C_CheckEvent( I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ) );
/* Clear EV6 by setting again the PE bit */
I2C_Cmd( I2C1, ENABLE );
switch( suba_type ){
case 2:
// 发送子地址,先发送高8位
I2C_SendData(I2C1,(u8)( ( addr >> 8 ) & 0X001F ) );
/* Test on EV8 and clear it */
while( !I2C_CheckEvent( I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED ) );
case 1:
// 发送子地址,后发送低8位
I2C_SendData( I2C1,(u8)( addr & 0X00ff ) );
/* Test on EV8 and clear it */
while( !I2C_CheckEvent( I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED ) );
break;
}
// 发送启动位
I2C_GenerateSTART( I2C1,ENABLE );
/* Test on EV5 and clear it */
while(!I2C_CheckEvent( I2C1,I2C_EVENT_MASTER_MODE_SELECT ) );
/* Send EEPROM address for read */
I2C_Send7bitAddress( I2C1,devaddr | 0x01,I2C_Direction_Receiver );
/* Test on EV6 and clear it */
while(!I2C_CheckEvent( I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ) );
/* While there is data to be read */
while( len ){
/* Test on EV7 and clear it */
if(I2C_CheckEvent( I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED ) ){
if( len == 2 ){
/* Disable Acknowledgement */
I2C_AcknowledgeConfig( I2C1,DISABLE );
}
if( len == 1 ){
/* Send STOP Condition */
I2C_GenerateSTOP( I2C1,ENABLE );
}
/* Read a byte from the EEPROM */
*pBuffer = I2C_ReceiveData( I2C1 );
/* Point to the next location where the byte read will be saved */
pBuffer++;
/* Decrement the read bytes counter */
len--;
}
}
/* Enable Acknowledgement to be ready for another reception */
I2C_AcknowledgeConfig( I2C1,ENABLE );
state = 1;
}else{
state = 0;
}
#endif
return(state);
}
void I2C_WaitStandbyState( uint8 devAddr )
{
do{
// 发送起始条件
I2C_GenerateSTART( I2C1,ENABLE );
// 读SR1
I2C_ReadRegister( I2C1,I2C_Register_SR1 );
// 发送器件地址
I2C_Send7bitAddress( I2C1,devAddr,I2C_Direction_Transmitter );
}while( !( I2C_ReadRegister(I2C1,I2C_Register_SR1) & I2C_FLAG_ADDR ) );
// 清AF标志
I2C_ClearFlag( I2C1,I2C_FLAG_AF );
}
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
#ifdef VECT_TAB_RAM
/* Set the Vector Table base location at 0x20000000 */
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else /* VECT_TAB_FLASH */
/* Set the Vector Table base location at 0x08000000 */
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
// I2C模式 中断,查询
#if I2C_WorkMode
// 配置优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
// 配置I2C事件中断
NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
#endif
}
void Borad_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/* I2C接口( PB8->SCL,PB9->SDA,将PB6,7的I2C唤射到PB8,9 )*/
GPIO_PinRemapConfig(GPIO_Remap_I2C1,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
void I2C1_EV_IRQHandler(void)
{
#if I2C_WorkMode
switch ( I2C_GetLastEvent( I2C1 ) ){
case I2C_EVENT_MASTER_MODE_SELECT: // EV5
if( !I2C1_COM.Direct ){
I2C_Send7bitAddress(I2C1,I2C1_COM.DevAddr,I2C_Direction_Transmitter);
}else{
I2C_Send7bitAddress(I2C1,I2C1_COM.DevAddr,I2C_Direction_Receiver);
}
break;
case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED: // EV8 just after EV6
switch( I2C1_COM.AddrType ){
case 1:
// 单字节子地址
I2C_SendData( I2C1,(u8)( I2C1_COM.Addr & 0X00ff ) );
break;
case 2:
// 先发送双字节子地址高8位
I2C_SendData(I2C1,(u8)( ( I2C1_COM.Addr >> 8 ) & 0X001F ) );
break;
}
break;
case I2C_EVENT_MASTER_BYTE_TRANSMITTING: // EV8
// 双字节子地址低8位
if( I2C1_COM.AddrType == 2 ){
I2C_SendData( I2C1,(u8)( I2C1_COM.Addr & 0X00ff ) );
I2C1_COM.AddrType--;
}else{
if( I2C1_COM.DataLen ){
// 开始发送数据
I2C_SendData( I2C1,*I2C1_COM.BuffAddr );
I2C1_COM.BuffAddr++;
I2C1_COM.DataLen--;
}
}
break;
case I2C_EVENT_MASTER_BYTE_TRANSMITTED: // EV8_2
if( I2C1_COM.I2CState ){
I2C1_COM.I2CState = 0;
}else{
I2C_GenerateSTOP( I2C1,ENABLE );
I2C_ITConfig( I2C1,I2C_IT_EVT | I2C_IT_BUF,ENABLE );
}
I2C1_COM.I2CEnd = 1; // 写完成标志
break;
case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED: // EV6
if( I2C1_COM.DataLen == 1 ){
I2C_AcknowledgeConfig(I2C1,DISABLE);
I2C_GenerateSTOP( I2C1,ENABLE );
}
break;
case I2C_EVENT_MASTER_BYTE_RECEIVED: // EV7
*I2C1_COM.BuffAddr = I2C_ReceiveData(I2C1);
I2C1_COM.BuffAddr++;
I2C1_COM.DataLen--;
if( I2C1_COM.DataLen == 1 ){
I2C_AcknowledgeConfig(I2C1,DISABLE);
I2C_GenerateSTOP( I2C1,ENABLE );
}
if( !I2C1_COM.DataLen ){
I2C1_COM.I2CEnd = 1;
}
break;
default:
break;
}
#endif
}
H文件
#ifndef __I2C_H
#define __I2C_H
#ifdef I2C_GLOBAL
#define I2C_EXT
#else
#define I2C_EXT extern
#endif
#define I2C_WorkMode 1 // I2C1的工作模式,1中断模式 0查询模式
#define I2C_Speed 400000 // I2C速率
#define RX8025 0x64 // RX8025器件从地址
#define FM24LC64 0xA0 // FM24LC64器件从地址
#define Transmitter 0x00
#define Receiver 0x01
#define ONE_BYTE_SUBA 1 // 单字节子地址
#define TWO_BYTE_SUBA 2 // 双字节子地址
/* 结构定义区*/
#if I2C_WorkMode
struct I2C_COMMAND{
uint8 DevAddr; // 设备地址
uint16 Addr; // 子地址
uint8 AddrType; // 子地址类型
uint8 *BuffAddr; // Buff地址
uint32 DataLen; // 长度
uint8 Direct; // 发送方向
uint8 I2CState; // 总线状态
uint8 I2CEnd; // 结束标志
};
#endif
/* 全局变量申明区*/
#if I2C_WorkMode
I2C_EXT struct I2C_COMMAND I2C1_COM;
#endif
/* 函数申明区*/
I2C_EXT void I2C_SCL_SDA_Reset(void);
I2C_EXT void I2C_Configuration(void);
I2C_EXT void I2C_WaitStandbyState(uint8 devAddr);
I2C_EXT uint8 I2C_WriteNByte( uint8 devaddr,uint8 suba_type,uint32 addr,uint8 *pBuffer,uint32 len );
I2C_EXT uint8 I2C_ReadNByte( uint8 devaddr,uint8 suba_type,uint32 addr,uint8 *pBuffer,uint32 len );
#if TestEeprom
I2C_EXT void test_EEPROM(void);
#endif
#endif