This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] CCS/MSP430F5529:读取/写入24AA32AF EEPROM

Guru**** 1983025 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/889936/ccs-msp430f5529-reading-writing-to-24aa32af-eeprom

器件型号:MSP430F5529

工具/软件:Code Composer Studio

您好!

我只是尝试将一个字节写入24AA32AF EEPROM、然后读回该字节、但当我尝试此简单操作时、我无法正确读取和写入。 我已经从 TI 下载了 I2Croutines.c 和 I2Croutines.h 文件、其中包括 EEPROM 读取、写入和确认函数。  我将 SDA 更改为 P3.0、将 SCL 更改为 P3.1。 我还将从器件地址设置为0xA0、以与 b10100000的控制字节一致。 现在、我尝试运行一个简单的主程序、该程序应该写入和读取一个字节、但我没有得到正确的结果。  

#include 
#include "I2Croutines.h"
int main (void)
{
unsigned int i;
WDTCTL = WDTPW + WDTHOLD;//停止看门狗计时器
InitI2C (0xA0);

EEPROM_ByteWrite (0x0000,0x12);
EEPROM_AckPolling();

unsigned char read_val = EEPROM_RandomRead (0x0000);

while (1);

返回0;
} 

我很困惑为什么这不能正确地写入 EEPROM 和从 EEPROM 读取。 我从 TI 获得的用于 I2Croutines 的代码如下所示。

I2CRoutines.c:

#include "msp430f5418a.h"
#include "I2Croutines.h"

#define MAXPAGEWRITE 64

int PtrTransmit;
unsigned char I2CBufferArray[66];
unsigned char I2CBuffer;

/*--------------- */
//说明:
// I2C 模块的初始化
/*--------------- //
空 InitI2C (unsigned char EEPROM_i2c_address)

//对于10100000、I2C 地址= 0xA0?

{
I2C_PORT_DIR |= SDA_PIN + SCL_PIN;
I2C_PORT_SEL |= SDA_PIN + SCL_PIN; //将 I2C 引脚分配给 USCI_B0

//用户指南中显示的 I2C 模块的建议初始化步骤:
UCB0CTL1 |= UCSWRST; //启用 SW 复位
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C 主设备,同步模式
UCB0CTL1 = UCSSEL_2 + UCTR + UCSWRST; //使用 SMCLK、TX 模式、保持软件复位
UCB0BR0 = SCL_CLOCK_DIV; // fSCL = SMCLK/12 =~100kHz
UCB0BR1 = 0;
UCB0I2CSA = EEPROM_i2c_address; //定义从机地址
//在本例中为从地址
//定义控制字节
//发送到 EEPROM。
//UCB0I2COA = 0x01A5; //自己的地址。
// UCB0IE|=UCTXIE+UCRXIE;
UCB0CTL1 &=~UCSWRST; //清除 SW 复位、

如果(UCB0STAT 和 UCBBUSY)则恢复运行 //测试总线是否空
闲{ //否则手动时钟打开
//生成
I2C_PORT_SEL &=~SCL_PIN; //为 SCL 选择端口功能
I2C_PORT_OUT &=~SCL_PIN; //
I2C_PORT_DIR |= SCL_PIN; //将 SCL 驱动为低电平
I2C_PORT_SEL |= SDA_PIN + SCL_PIN; //选择的模块功能
//使用的 I2C 引脚
};
__enable_interrupt ();
}/*---------------

//
说明:
//初始化 I2C 模块以执行写操作。
/*------------------ */
void I2CWriteInit (void)
{
UCB0CTL1 |= UCTR; // UCTR=1 =>发送模式(R/W 位= 0)
UCB0IFG &&~UCTXIFG;
UCB0IE &&=~UCRXIE; //禁用接收就绪中断
UCB0IE|= UCTXIE; //启用发送就绪中断}/--><!--kadov_tag{{</spaces>}/--><!--kadov_tag{</spaces>}}-->


*/
/说明:
// I2C 模块初始化以执行读取操作。
/*------------------ */
void I2CReadInit (void)
{
UCB0CTL1 &=~UCTR; // UCTL=0 =>接收模式(R/W 位= 1)
UCB0IFG &&~UCRXIFG;
UCB0IE &&~UCTXIE; //禁用发送就绪中断
UCB0IE |= UCRXIE; //启用接收就绪中断}/--><!--kadov_tag{{</spaces>}/--><!--kadov_tag{</spaces>}}-->


*/
//说明:
//字节写入操作。 通过 I2C 总线与 EEPROM
//(2465)进行通信。 一个数据字节被写入一个用户定义的地址。
/*------------------ //
void EEPROM_ByteWrite (unsigned int Address、unsigned char Data)
{
unsigned char ADR_hi;
unsigned char ADR_lo;

while (UCB0STAT 和 UCBUSY); //等待 I2C 模块具有
//完成所有操作。

ADR_HI =地址>> 8; //计算高字节
ADR_LO =地址和0xFF; //和地址

I2CBufferArray[2]的低字节= ADR_HI; //低字节地址。
I2CBufferArray[1]= ADR_lo; //高字节地址。
I2CBufferArray[0]=数据;
PtrTransmit = 2; //设置 I2CBufferArray 指针

I2CWriteInit();
UCB0CTL1 |= UCTXSTT; //开始条件生成
//=> I2C 通信已启动
//_ bis_SR_register (LPM0_bits + GIE); //通过中断
while (UCB0CTL1 & UCTXSTP)输入 LPM0; //确保已发送停止条件}/*--><!--kadov_tag{{</spaces>}--><!--kadov_tag{</spaces>}--><!--kadov_tag{</spaces>}--><!--kadov_tag{</spaces>}--><!--kadov_tag{</spaces>}}-->


*/
//说明:
//页写操作。
通过 I2C 总线与 EEPROM //(24xx65)进行通信。 一个数据字节被写入一个用户定义的地址。
/*------------------ //
void EEPROM_PageWrite (unsigned int StartAddress、unsigned char * Data、unsigned char size)
{
volatile unsigned int i = 0;
volatile unsigned char counterI2cBuffer;
unsigned char ADR_hi;
unsigned char
currentAddress = StartAddress;
unsigned char currentSize = size;unsigned
char bufferPtr = 0;
unsigned char moreToDataRead = 1

while (UCB0STAT 和 UCBUSY); //等待 I2C 模块具有
//完成所有操作。

//执行直到数据缓冲区中没有更多数据
while (moreDataToRead)
{
ADR_HI =电流地址>> 8; //计算高字节
ADR_lo =电流地址和0xFF; //和低字节地址

//一次发送低至64字节数据包的斩波数据
//保持当前起始地址的指针
if (currentSize > MAXPAGEWRITE)
{
bufferPtr = bufferPtr + MAXPAGEWRITE;
counterI2cBuffer = MAXPAGEWRITE - 1;
PtrTransmit = MAXPAGEWRITE + 1; //设置 I2CBufferArray 指针
currentSize = currentSize - MAXPAGEWRITE;
currentAddress = currentAddress + MAXPAGEWRITE;

//获取起始地址
I2CBufferArray[MAXPAGEWRITE + 1]= ADR_HI;//高字节地址。
I2CBufferArray[MAXPAGEWRITE]= ADR_LO;//低字节地址
。}
其他
{
bufferPtr = bufferPtr + currentSize;
counterI2cBuffer =当前大小-1;
PtrTransmit = currentSize + 1; //设置 I2CBufferArray 指针。
MoreDataToRead = 0;
currentAddress = currentAddress + currentSize;

//获取起始地址
I2CBufferArray[currentSize + 1]= ADR_HI;//高字节地址。
I2CBufferArray[电流大小]= ADR_lo;//低字节地址
。}

//将数据复制到 I2CBufferArray
unsigned char temp;
for (i;i < bufferPtr;i++)
{
温度=数据[i]; //必需,否则 IAR 抛出
//警告[Pa082]
I2CBufferArray[counterI2cBuffer]= temp;
counterI2c 缓冲器--;
}

I2CWriteInit();
UCB0CTL1 |= UCTXSTT; //开始条件生成
//=> I2C 通信已启动
//_ bis_SR_register (LPM0_bits + GIE); //输入带中断的 LPM0
while (UCB0CTL1 & UCTXSTP); //确保发送了停止条件

EEPROM_AckPolling(); //确保数据被写入 EEPROM
}


}-->----------------- //
//说明:
//当前地址读取操作。 从 EEPROM 读取数据。
使用来自 EEPROM 的当前//地址。
/*------------------ //
unsigned char EEPROM_CurrentAddressRead (void)
{
while (UCB0STAT 和 UCBUSY); //等待 I2C 模块具有
//完成所有操作
I2CReadInit();

UCB0CTL1 |= UCTXSTT; // I2C 启动条件
while (UCB0CTL1 & UCTXSTT); //起始条件是否已发送?
UCB0CTL1 |= UCTXSTP; // I2C 停止条件
//_bis_SR_register (LPM0_bits + GIE); //通过中断
while (UCB0CTL1 & UCTXSTP)输入 LPM0; //确保停止条件已发送
返回 I2CBuffer;
}-->---------------

*/
//说明:
//随机读取操作。 从 EEPROM 读取数据。 EEPROM
//地址由参数 Address 定义。
/*------------------ //
unsigned char EEPROM_RandomRead (unsigned int Address)
{
unsigned char ADR_hi;
unsigned char ADR_lo;

while (UCB0STAT & UCBUSY); //等待 I2C 模块具有
//完成所有操作

ADR_HI =地址>> 8; //计算高字节
ADR_LO =地址和0xFF; //和地址

I2CBufferArray[1]的低字节= ADR_HI; //存储必须
包含 I2CBufferArray[0]= ADR_lo 的单字节; //在 I2CBuffer 中发送。
PtrTransmit = 1; //设置 I2CBufferArray 指针

//写入地址优先
I2CWriteInit();
UCB0CTL1 |= UCTXSTT; //开始条件生成
//=> I2C 通信已启动
//_bis_SR_register (LPM0_bits + GIE); //通过中断
while (UCB0CTL1 & UCTXSTP)输入 LPM0; //确保发送了停止条件

//读取数据字节
I2CReadInit();

UCB0CTL1 |= UCTXSTT; // I2C 启动条件
while (UCB0CTL1 & UCTXSTT); //起始条件是否已发送?
UCB0CTL1 |= UCTXSTP; // I2C 停止条件
//_bis_SR_register (LPM0_bits + GIE); //通过中断
while (UCB0CTL1 & UCTXSTP)输入 LPM0; //确保停止条件已发送
返回 I2CBuffer;
}-->---------------

*/
//说明:
//顺序读取操作。 数据从 EEPROM 以顺序
//形式从作为起点的参数地址读取。 指定
要读取的//大小并填充到数据缓冲区。
/*------------------ //
void EEPROM_SequentialRead (unsigned int Address、unsigned char * Data、unsigned int size)
{
unsigned char ADR_hi;
unsigned char ADR_lo;
unsigned int counterSize;

while (UCB0STAT 和 UCBUSY); //等待 I2C 模块具有
//完成所有操作

ADR_HI =地址>> 8; //计算高字节
ADR_LO =地址和0xFF; //和地址

I2CBufferArray[1]的低字节= ADR_HI; //存储必须
包含 I2CBufferArray[0]= ADR_lo 的单字节; //在 I2CBuffer 中发送。
PtrTransmit = 1; //设置 I2CBufferArray 指针

//写入地址优先
I2CWriteInit();
UCB0CTL1 |= UCTXSTT; //开始条件生成
//=> I2C 通信已启动
//_bis_SR_register (LPM0_bits + GIE); //通过中断
while (UCB0CTL1 & UCTXSTP)输入 LPM0; //确保发送停止条件

//读取数据字节
UCB0CTL1 &=~UCTR; // UCTL=0 =>接收模式(R/W 位= 1)
UCB0IFG &&~UCRXIFG;
UCB0IE &&~UCTXIE; //禁用发送就绪中断
UCB0IE |= UCRXIE; //启用接收就绪中断

UCB0CTL1 |= UCTXSTT; // I2C 启动条件
while (UCB0CTL1 & UCTXSTT); //起始条件是否已发送?

for (counterSize = 0;counterSize < size;counterSize++)
{
//_bis_SR_register (LPM0_bits + GIE); //输入带中断的 LPM0
DATA[counterSize]= I2CBuffer;
}
UCB0CTL1 |= UCTXSTP; // I2C 停止条件
//_bis_SR_register (LPM0_bits + GIE); //通过中断
while (UCB0CTL1 & UCTXSTP)输入 LPM0; //确保已发送停止条件}/*--><!--kadov_tag{{</spaces>}--><!--kadov_tag{</spaces>}--><!--kadov_tag{</spaces>}--><!--kadov_tag{</spaces>}--><!--kadov_tag{</spaces>}}-->


//
//说明:
//确认轮询。 如果写入周期为
//正在进行、EEPROM 将不会应答。 它可用于确定写入周期何时完成。
/*------------------ *
/ void EEPROM_AckPolling (void)
{
while (UCB0STAT 和 UCBUSY); //等待 I2C 模块具有
//完成所有操作
都执行
{
UCB0STAT = 0x00; //清除 I2C 中断标志
UCB0CTL1 |= UCTR; // I2CTRX=1 =>发送模式(R/W 位= 0)
UCB0CTL1 &=~UCTXSTT;
UCB0CTL1 |= UCTXSTT; //起始条件已生成
while (UCB0CTL1和 UCTXSTT) //等待 I2CSTT 位被清零
{
if (!(UCNACKIFG & UCB0STAT)) //如果收到 ACK 则分接
中断;
}
UCB0CTL1 |= UCTXSTP; //停止条件在之后生成
//发送从器件地址=> I2C 通信开始
while (UCB0CTL1 & UCTXSTP); //等待停止位被复位
_delay_cycles (500); //软件延迟
}while (UCNACKIFG & UCB0STAT);
}/--><!-------------------

*/
*中断服务例程 */
* 请注意、编译器版本在以下代码和*/
/*中进行检查 根据编译器版本、正确的中断服务 */
* 例程定义。 //
//#if __VER__< 200
//中断[USCIAB0TX_Vector] void TX_ISR_I2C (void)
//#else
#pragma vector = USCI_B0_Vector
__interrupt void USCI_B0_ISR (void)
//#endif
{
UCTXIFG & UCB0IFG}

UCB0TXBUF = I2CBufferArray[PtrTransmit];//加载 TX 缓冲区
PtrTransmit ----; //测量 TX 字节计数器
if (PtrTransmit < 0)
{
while (!(UCB0IFG & UCTXIFG));
UCB0CTL1 |= UCTXSTP; // I2C 停止条件
UCB0IE &=~UCTXIE; //禁用中断。
UCB0IFG &=~UCTXIFG; //清除 USCI_B0 TX int 标志
//__BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出 LPM0
}
}
否则、if (UCRXIFG & UCB0IFG)
{
I2CBuffer = UCB0RXBUF; //将接收到的数据存储在缓冲区中
//_BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出 LPM0
}

I2CRoutines.h:

#define I2C_PORT_SEL P3SEL
#define I2C_PORT_OUT P3OUT
#define I2C_PORT_REN P3REN
#define I2C_PORT_DIR P3DIR
#define SDA_PIN BIT0 // UCB0SDA 引脚
#define SCL_PIN BIT1 // UCB.S 引脚
#define SCL_CLOCK _DIV 0x12 // SCL 时钟偏差

void InitI2C (unsigned char EEPROM_i2c_address);
void EEPROM_ByteWrite (unsigned int Address、unsigned char
Data);
unsigned char EEPROM_RandomRead (unsigned int Address);void
char EEPROM_CurrentRead (unsigned
int Data);unsigned char unsigned char ine_RandomRead (unsigned int Data);unsigned char unsigned char unsigned int Resid_CurrentAddress(unsigned int Data);void int Res
void EEPROM_AckPolling (void); 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Gavin、

    我注意到您使用参数0xA0的函数 InitI2C()来尝试使 I2C 地址匹配1010000。 但实际上、您需要在这里传递0x50、因为 I2C 地址为7位、0xA0的最后一位用于读取/写入访问。 因此、实际上您需要将7 MSB 位传递到这里。

    用户指南中提供了一些详细信息:

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    除 Harry (正确)推荐的内容外:

    >    //__bis_SR_register(LPM0_bits + GIE);       // Enter LPM0 w/ interrupts

    这与 SLAA208A 的代码不匹配。 注释掉所有这些"等待完成"序列会改变流程、或多或少会保证故障。

    我建议您刷新原始代码(.pdf 中有一个链接)。

    未经请求:虽然" UCBUSY"(与"UCBBUSY"相比)的使用是原始的、但也有一些可疑的用途。 在 I2C 模式下、UCBUSY 始终读为0 [参考用户指南 SLAU208Q)表37-20和38-7]。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Harry 和 Bruce、大家好、

    感谢您的回复、您的建议非常有意义、因此我已将我的从地址更新为0x50、并对所有内容进行了取消注释  

    _bis_SR_register (LPM0_bits + GIE); 

    和  

    _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS); 

    线。 不过,我仍有问题。 当我尝试写入第一个字节时、代码仅进入 ISR 一次、并在执行下面的 PtrTransmit if 语句之前退出。  

    if (PtrTransmit < 0)
    {
    while (!(UCB0IFG & UCTXIFG));
    //UCB0CTL1 |= UCTXSTP; // I2C 停止条件
    UCB0IE &=~UCTXIE; //禁用中断。
    UCB0IFG &=~UCTXIFG; //清除 USCI_B0 TX int 标志
    _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出 LPM0
    } 

    查看调试器中的寄存器后、每当我填充 TX 缓冲区时、TX 中断标志就会被清除、并且在停止位被置位之前不会再次被置位。 如果我知道我还有更多字节要发送 EEPROM、或者是否有方法在停止位被置位前继续发送字节、我应该在中断中手动设置 TX 中断标志?

    再次感谢你的帮助。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您描述的序列听起来可疑、就像您在地址上遇到问题一样。  

    您将哪种类型的电路板用于 EEPROM? 我对 A0-A2引脚的配置方式特别感兴趣。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我确实得到了一个否定。 我检查了接线、连接到 VCC 的导线未连接到试验电路板上。 写入和读取操作现在工作正常。 感谢您的所有帮助!

x 出现错误。请重试或与管理员联系。