大家好、
我不熟悉这一点、如果可以的话、请您解释一下、而不是多说少。 )
我需要设置与传感器的连接、以便通过 I2C 进行距离测量。 我已经编写了用于初始化和范围测量的函数、只是一组简单的寄存器读取和写入执行。 现在、我 要修改此示例以符合我的目的:
/文件: I2C_ex2_EEPROM.c
//
//包含的文件
//
#include "driverlib.h"
#include "device.h"
//
//定义
//
#define SLAVE_ADDRESS 0x50 //我的新地址为0x29
#define EEPROM_HIGH_ADDR 0x00 //为了进行初始化、我有大约30个高地址和低地址
#define EEPROM_LOW_ADDR 0x30 //要写入保存在结构中使用的数组中的值
在 本例中为#define NUM_Bytes 8 // Just 1
#define MAX_BUFFER_SIZE 14 //目前最大值为14,原因是
// 2个地址字节和16字节
// FIFO
//
// I2CMsg 结构的 I2C 消息状态
//
#define MSG_STATUS_INACTIVE 0x0000 //消息未使用,请勿发送
#define MSG_STATUS_SEND_WITHSTOP 0x0010 //发送带有停止位的消息
#define MSG_STATUS_WRITE_BUSY 0x0011 //已发送消息,等待 STOP
#define MSG_STATUS_SEND_NOSTOP 0x0020 //发送无停止位的消息
#define MSG_STATUS_SEND_NOSTOP_BUSY 0x0021 //已发送消息,等待 ARDY
#define MSG_STATUS_RESTART 0x0022 //准备成为主接收器
#define MSG_STATUS_READ_BUSY 0x0023 //在读取数据之前等待 STOP
//
//读取和写入函数的错误消息
//
#define ERROR_BUS_BUS_BUSY 0x1000
#define ERROR_STOP_NOT_READY 0x5555
#define SUCCESS 0x0000
//
// Typedefs
//
结构 I2CMsg
{
uint16_t msgStatus; //字指示 msg 处于何种状态。
//参见上面的 MSG_STATUS_*定义。
uint16_t slaveAddr; //绑定到消息的从器件地址。
uint16_t numBytes; //消息中有效字节的数量。
uint16_t memoryHighAddr; //相关数据的 EEPROM 地址
//带有消息(高字节)。
uint16_t memoryLowAddr; //相关数据的 EEPROM 地址
//带有消息(低字节)。
uint16_t msgBuffer[MAX_Buffer_SIZE];//阵列保存消息数据。
};
//
//全局
//
struct I2CMsg i2cMsgOut ={MSG_STATUS_SEND_WITHSTOP、
Slave_address、
num_Bytes、
EEPROM_HIGH_ADDR、/更高 版本、我将为每次通信定义新结构
EEPROM_LOW_ADDR、
0x01、 //消息字节
0x23、
0x45、
0x67、
0x89、
0xAB、
0xCD、
0xEF};
struct I2CMsg i2cMsgIn ={MSG_STATUS_SEND_NOSTOP、
Slave_address、
num_Bytes、
EEPROM_HIGH_ADDR、//later 我将为每次通信定义新结构
EEPROM_LOW_ADDR};
struct I2CMsg *currentMsgPtr; //用于中断
uint16_t passCount = 0;//我不需要
uint16_t failcount = 0;
//
//函数原型
//
void initI2C (void);
uint16_t ReadData (struct I2CMsg *msg);
uint16_t writeData (struct I2CMsg *msg);
void fail (void);//我不需要
void pass (void);
_interrupt void i2cAISR (void);
//
//主函
//
void main (void)
{
uint16_t 错误;
uint16_t i;
//
//初始化设备时钟和外设
//
device_init();
//
//禁用引脚锁定并启用内部上拉。
//
DEVICE_initGPIO();
//
//初始化 GPIO 32和33,分别用作 SDA 和 SCL A
//
GPIO_setPinConfig (GPIO_32_SDAA);
GPIO_setPadConfig (32、GPIO_PIN_TYPE_PULLUP);
GPIO_setQualificationMode (32、GPIO_QUAL_ASYNCx);
GPIO_setPinConfig (GPIO_33_SCLA);
GPIO_setPadConfig (33、GPIO_PIN_TYPE_PULLUP);
GPIO_setQualificationMode (33、GPIO_QUAL_异 步);
//
//初始化 PIE 并清除 PIE 寄存器。 禁用 CPU 中断。
//
interrupt_initModule();
//
//使用指向 shell 中断的指针初始化 PIE 矢量表
//服务例程(ISR)。
//
interrupt_initVectorTable();
//
//此示例中使用的中断被重新映射到 ISR 函数
//在此文件中找到。
//
interrupt_register (INT_I2CA、&i2cAISR);//我认为这里的中断被设置到 i2cAISR 函数上以进行中断处理
//
//设置 I2C 使用,将其初始化为 FIFO 模式
//
initi2C();
//
//清除传入消息缓冲区
//
对于(I = 0;I < MAX_BUFFER_SIZE;I++)
{
i2cMsgIn.msgBuffer[i]= 0x0000;
}
//
//将中断中使用的消息指针设置为指向传出消息
//
currentMsgPtr =&i2cMsgOut;
//
//启用此示例所需的中断
//
INTERRUPT_ENABLE (INT_I2CA);
//
//启用全局中断(INTM)和实时中断(DBGM)
//
EINT;
ERTM;
//
//无限循环
//
while (1)
{
//
//****将数据写入 EEPROM 部分****
//
//检查外发消息是否应发送。 在这里
//示例它被初始化以使用停止位发送。
//
if (i2cMsgOut.msgStatus = MSG_STATUS_SEND_WITHSTOP)
{
//
//将数据发送到 EEPROM
//
错误= writeData (&i2cMsgOut);
//
//如果通信已正确启动,请将 msg 状态设置为忙
//并更新中断服务例程的当前 MsgPtr。
//否则,不执行任何操作,然后重试下一个循环。 发送一条消息
//启动后、I2C 中断将处理其余中断。 请参阅
//函数 i2cAISR()。
//
if (错误==成功)
{
currentMsgPtr =&i2cMsgOut;
i2cMsgOut.msgStatus = MSG_STATUS_WRITE_BUSY;
}
}
//
//****从 EEPROM 部分读数据****
//
//检查外发消息状态。 如果状态为、则绕过读取段
//未处于非活动状态。
//
if (i2cMsgOut.msgStatus = MSG_STATUS_INACTIVE)
{
//
//检查传入消息状态
//
if (i2cMsgIn.msgStatus = MSG_STATUS_SEND_NOSTOP)
{
//
//发送 EEPROM 地址设置
//
while (ReadData (&i2cMsgIn)!=成功)
{
//
//可以设置一个尝试计数器来打破无穷大
// while 循环。 EEPROM 会在它发出否定应答时发回一个否定应答
//执行写操作。 即使是写入
//此时已完成,EEPROM 仍可以
//繁忙的数据编程。 因此、多个
//必须尝试。
//
}
//
//更新当前消息指针和消息状态
//
currentMsgPtr =&i2cMsgIn;
i2cMsgIn.msgStatus = MSG_STATUS_SEND_NOSTOP_BUSY;
}
//
//一旦消息经过设置内部地址的过程
//在 EEPROM 中、发送重新启动以从读取数据字节
// EEPROM。 完成公报并停留一会。 msgStatus 为
//在中断服务例程中更新。
//
否则、if (i2cMsgIn.msgStatus = MSG_STATUS_RESTART)
{
//
//读取数据部分
//
while (ReadData (&i2cMsgIn)!=成功)
{
//
//可以设置一个尝试计数器来打破无穷大
// while 循环。
//
}
//
//更新当前消息指针和消息状态
//
currentMsgPtr =&i2cMsgIn;
i2cMsgIn.msgStatus = MSG_STATUS_READ_BUSY;
}
}
}
}
//
// initI2C -用于在 FIFO 模式中配置 I2C A 的函数。
//
无效
initi2C()
{
//
//必须在配置 I2C 之前将其复位
//
I2C_DisableModule (I2CA_BASE);
//
// I2C 配置。 使用占空比为33%的400kHz I2CCLK。
//
I2C_initMaster (I2CA_BASE、DEVICE_SYSCLK_FREQ、400000、I2C_DUTYCYCLE _33);
I2C_setBitCount (I2CA_BASE、I2C_BITCOUNT_8);
I2C_setSlaveAddress (I2CA_BASE、SLAVE_ADDRESS);
I2C_setEmulationMode (I2CA_BASE、I2C_emulation_free_run);
//
//启用停止条件和寄存器访问就绪中断
//
I2C_enableInterrupt (I2CA_BASE、I2C_INT_STOP_Condition |
I2C_INT_REG_ACCESS_RDY);
//
// FIFO 配置
//
I2C_enableFIFO (I2CA_BASE);
I2C_clearInterruptStatus (I2CA_BASE、I2C_INT_RXFF | I2C_INT_TXFF);
//
//配置完成。 启用模块。
//
I2C_enableModule (I2CA_BASE);
}
//
// writeData -发送要写入 EEPROM 的数据的函数
//
uint16_t
writeData (struct I2CMsg *msg)
{
uint16_t i;
//
//等待 STP 位从任何先前的主设备清零
//通信。 模块将该位清零的时间延迟到之后
// SCD 位被置位。 如果在启动新的之前没有检查该位
//消息、I2C 可能会被混淆。
//
if (I2C_getStopConditionStatus (I2CA_BASE))
{
返回(ERROR_STOP_NOT _READY);
}
//
//设置从地址
//
I2C_setSlaveAddress (I2CA_BASE、SLAVE_ADDRESS);
//
//检查总线是否占线
//
IF (I2C_isBusy (I2CA_BASE))
{
return (error_bus_busy);
}
//
//设置要发送 msgBuffer 和地址的字节数
//
I2C_setDataCount (I2CA_BASE、(msg->numBytes + 2));
//
//设置要发送的数据
//
i2C_putData (I2CA_BASE、msg->memoryHighAddr);
i2C_putData (I2CA_BASE、msg->memoryLowAddr);
对于(i = 0;i < msg->numBytes;i++)//仅为我的目的使用1个字节
{
I2C_putData (I2CA_BASE、msg->msgBuffer[i]);
}
//
//将 START 作为主发送器发送
//
I2C_setConfig (I2CA_BASE、I2C_MASTER_SEND_MODE);
I2C_sendStartCondition (I2CA_BASE);
I2C_sendStopCondition (I2CA_BASE);
返回(成功);
}
//
// ReadData -准备从 EEPROM 读取的数据的函数
//
uint16_t
ReadData (struct I2CMsg *msg)
{
//
//等待 STP 位从任何先前的主设备清零
//通信。 模块将该位清零的时间延迟到之后
// SCD 位被置位。 如果在启动新的之前没有检查该位
//消息、I2C 可能会被混淆。
//
if (I2C_getStopConditionStatus (I2CA_BASE))
{
返回(ERROR_STOP_NOT _READY);
}
//
//设置从地址
//
I2C_setSlaveAddress (I2CA_BASE、SLAVE_ADDRESS);
//
//如果我们处于地址设置阶段,则发送地址时不使用
//停止条件。
//
if (msg->msgStatus =MSG_STATUS_SEND_NOSTOP)
{
//
//检查总线是否占线
//
IF (I2C_isBusy (I2CA_BASE))
{
return (error_bus_busy);
}
//
//将数据发送到设置 EEPROM 地址
//
I2C_setDataCount (I2CA_BASE、2);
i2C_putData (I2CA_BASE、msg->memoryHighAddr);
i2C_putData (I2CA_BASE、msg->memoryLowAddr);
I2C_setConfig (I2CA_BASE、I2C_MASTER_SEND_MODE);
I2C_sendStartCondition (I2CA_BASE);
}
否则(msg->msgStatus =MSG_STATUS_RESTART)
{
//
//地址设置阶段已完成。 现在设置预期的字节数
//并将重新启动作为主接收器发送。
//
I2C_setDataCount (I2CA_BASE、(msg->numBytes));
I2C_setConfig (I2CA_BASE、I2C_MASTER_Receive_MODE);
I2C_sendStartCondition (I2CA_BASE);
I2C_sendStopCondition (I2CA_BASE);
}
返回(成功);
}
//
// i2cAISR - I2C A ISR (非 FIFO)
//
_interrupt void
i2cAISR (空)
{
I2C_InterruptSource intSource;
uint16_t i;
//
//读取中断源
//
intSource = I2C_getInterruptSource (I2CA_BASE);
//
//中断源=检测到停止条件
//
if (intSource = I2C_INTSRC_STOP_Condition)
{
//
//如果已完成的消息正在写入数据,则将 msg 重置为非活动状态
//
if (currentMsgPtr ->msgStatus =MSG_STATUS_WRITE_BUSY)
{
currentMsgPtr ->msgStatus = MSG_STATUS_INACTIVE;
}
其他
{
//
//如果在的地址设置部分收到 NACK 消息
// EEPROM 读取、下面的代码进一步包含在寄存器中
//访问就绪中断源代码将生成停止
//条件。 在接收到停止条件后(此处)、设置
//要重试的消息状态。 用户可能希望限制该数字
//在生成错误之前重试次数。
//
if (currentMsgPtr ->msgStatus = MSG_STATUS_SEND_NOSTOP_BUSY)
{
currentMsgPtr ->msgStatus = MSG_STATUS_SEND_NOSTOP;
}
//
//如果已完成消息正在读取 EEPROM 数据,则将消息重置为
//处于非活动状态并从 FIFO 读取数据。
//
否则 if (currentMsgPtr ->msgStatus =MSG_STATUS_READ_BUSY)
{
currentMsgPtr ->msgStatus = MSG_STATUS_INACTIVE;
for (i=0;i < NUM_bytes;i++)
{
currentMsgPtr ->msgBuffer[i]= I2C_getData (I2CA_BASE);
}
//
//检查接收到的数据//我不需要
//
for (i=0;i < NUM_bytes;i++)
{
if (i2cMsgIn.msgBuffer[i]=i2cMsgOut.msgBuffer[i])
{
PassCount++;
}
其他
{
failcount++;
}
}
if (passCount =NUM_Bytes)
{
pass();
}
其他
{
fail();
}
}
}
}
//
//中断源=寄存器访问就绪
//
//此中断用于确定何时设置 EEPROM 地址
//读取数据通信的部分已完成。 因为没有停止位
//为命令,此标志告诉我们何时发送了消息
//而不是 SCD 标志。
//
否则、如果(intSource = I2C_INTSRC_REG_ACCESS_RDY)
{
//
//如果接收到 NACK,清除 NACK 位并命令停止。
//否则,继续到通信的读取数据部分。
//
if ((I2C_getStatus (I2CA_BASE)& I2C_STS_NO_ACK)!= 0)
{
I2C_sendStopCondition (I2CA_BASE);
I2C_clearStatus (I2CA_BASE、I2C_STS_NO_ACK);
}
否则 if (currentMsgPtr -> msgStatus = MSG_STATUS_SEND_NOSTOP_BUSY)
{
currentMsgPtr ->msgStatus = MSG_STATUS_RESTART;
}
}
其他
{
//
//从无效的中断源生成一些错误
//
asm (" ESTOP0");
}
//
//发出 ACK 以启用将来的组8中断
//
INTERRUPT_clearACKGROUP (INTERRUPT_ACK_group8);
}
//
//传递-如果写入的数据与读取的数据匹配,则调用的函数//无目的
//
无效
通过(无效)
{
asm (" ESTOP0");
for (;;);
}
//
//失败-如果写入的数据与读取的数据不匹配,则调用的函数
//
失效失败(无效)
{
asm (" ESTOP0");
for (;;);
}
//
//圆角结束/稍后我将为每次通信定义新结构
//
我将所有内容标记为红色、我已经修改了这些内容。 现在我的问题是、如果我使用自己的主循环、说我会将其部分用于简单的读取和写入目的、我可以这么做吗? 已经声明了所有中断和状态? 我希望尽可能少地进行修改。 或者我是否需要修改中断功能? 我不太明白、何时发生 i2c 中断、因此无法完全理解代码。
以后使用时、我想在传感器的 GPIO 中断被置位时写入一个函数。 因此、我想在其中一个引脚上设置一个中断、如果新的测量准备就绪并且没有读取寄存器、则该中断会将引脚拉高。 有什么提示吗?