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.
大家好、
我不熟悉这一点、如果可以的话、请您解释一下、而不是多说少。 )
我需要设置与传感器的连接、以便通过 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 中断被置位时写入一个函数。 因此、我想在其中一个引脚上设置一个中断、如果新的测量准备就绪并且没有读取寄存器、则该中断会将引脚拉高。 有什么提示吗?
您好、Alexander、
您正在处理的 I2C EEPROM 示例代码被写入以与 CAT24WC256 EEPROM 存储器件或需要相同协议的类似 I2C EEPROM 一起使用。 默认情况下、该示例将数据写入指定的 EEPROM 存储器地址(高/低地址字节)、然后读回写入的数据。 SW 主要由中断驱动、并包含一个状态机、因此很难跟随。
[引用 user="Alexander Laub">稍后使用时、我希望在设置传感器的 GPIO 中断时编写一个函数。 因此、我想在其中一个引脚上设置一个中断、如果新的测量准备就绪并且没有读取寄存器、则该中断会将引脚拉高。 有什么提示吗?[/引述]
如果您的最终目标是上述内容、我认为使用 I2C DriverLib 函数(在 i2c.h 内)编写新软件比尝试利用示例的状态机更简单。 用于此中断的引脚将是 C2000器件的输入还是输出? 从传感器器件配置和读取测量值的顺序是什么?
最棒的
Kevin
// //包含的文件 // #include "driverlib.h" #include "device.h" #include "stdio.h" // 定义 // #define SLAVE_ADDRESS 0x29 //#define EEPROM_HIGH_ADDR 0x00 //#define EEPROM_LOW_ADDR 0x30 #define NUM_Bytes 1 #define MAX_BUFFER_SIZE 14. //目前最大值为14,原因是 // 2个地址字节和16字节 // FIFO // //距离连续模式所需的函数 // #define SYSRANGE_INTERMEASUREMENT_PERIOD 0x01B #define SYSTEM_MODE_GPIO1 0x011 #define system_interrupt_config_GPIO 0x014 #define SYSRANGE_START 0x018 #define RESULT_RANGE_RAW 0x064 #define system_interrupt_clear 0x015 typedef uint16_t VL6180xDev_t; VL6180xDev_t dev = slave_address; uint16_t n = 0; // I2CMsg Struct// #define MSG_STATUS_INACTIVE 的 I2C 消息状态 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 //在读取数据之前等待停止 // //读取和写入函数的错误消息 // #define ERROR_BUS_BUS_BUSY 0x1000 #define ERROR_STOP_NOT_READY 0x5555 #define SUCCESS 0x0000 // // Typedefs // struct I2CMsg { uint16_t msgStatus; //字说明 msg 处于什么状态。 //参见上面的 MSG_STATUS_*定义。 uint16_t slaveAddr; //绑定到消息的从器件地址。 uint16_t numBytes; //消息中有效字节的数量。 uint16_t memoryHighAddr[30]; //相关数据的 EEPROM 地址 //带有消息(高字节)。 uint16_t memoryLowAddr[30]; //相关数据的 EEPROM 地址 //带有消息(低字节)。 uint16_t msgBuffer[30]; //阵列保存消息数据。 }; // // Globals // /* struct I2CMsg i2cMsgOut ={MSG_STATUS_SEND_WITHSTOP, Slave_address、 num_Bytes、 ArrayMemoryHighAddr[n]、 ArrayMemoryLowAddr[n]、 ArrayAddrValue[n]}; struct I2CMsg i2cMsgIn ={MSG_STATUS_SEND_NOSTOP、 Slave_address、 num_Bytes、 ArrayMemoryHighAddr[n]、 ArrayMemoryLowAddr[n]}; */ struct I2CMsg * currentMsgPtr; //在中断中使用 // 函数原型 // void initI2C (void); void initVL6180X (void); uint16_t ReadData (struct I2CMsg *msg); uint16_t writeData (struct I2CMsg *msg); int Rang6180x_Init (struct I2CMsg *msg);uintvr6180x_int_int_intvr6_int_intvr6_int_intvr6_intvr18x_int_int_intvr6_intvr6_intvr6_intvr6_int_intvr6_int_intvr6_int_intvr6_int uint16_t GPIOIntOn、uint16_t ActiveHigh); int VL6180x_RangeConfigInterrupt (VL6180xDev_t dev、uint16_t LevelLow、uint16_t LevelHigh、 uint16_t OutOfWindow、uint16_t NewSample); int VL6180x_RangeStartContinuousMode (VL6180xDev_t dev、uint16_t ContMode、uint16_t StartMode); int VL6180x_RangeGetMeasurement (VL6180xDev_t dev、Int32_t * pRange_mm); int VL6180x_ClearAllInterrupt (VL6180xDev_t dev、uint16_t ClearRange、uint16_t ClearALS、 uint16_t ClearError); __interrupt void i2cAISR (void); // // Main // void main (void) { //uint16_t i; // //初始化设备时钟和外设 // device_init(); // //禁用引脚锁定并启用内部上拉。 // DEVICE_initGPIO(); // //初始化 GPIO 32和33,分别用作 SDA 和 SCL A // GPIO_setPinConfig (GPIO_104_SDAA); GPIO_setPadConfig (104、GPIO_PIN_TYPE_PULLUP); GPIO_setQualificationMode (104、GPIO_QUAL_异 步); GPIO_setPinConfig (GPIO_105_SCLA); GPIO_setPadConfig (105、GPIO_PIN_TYPE_PULLUP); GPIO_setQualificationMode (105、GPIO_QUAL_ASYNC_A); // //初始化 PIE 并清除 PIE 寄存器。 禁用 CPU 中断。 // interrupt_initModule(); // //使用指向 shell 中断的指针初始化 PIE 矢量表 //服务例程(ISR)。 // interrupt_initVectorTable(); // //此示例中使用的中断被重新映射到 ISR 函数 //在此文件中找到。 // interrupt_register (INT_I2CA、&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; INT STATUS = VL6180x_Init (dev); DEVICE_DELAY_US (1000); 状态= VL6180x_RangeSetInterMeasuriod (dev、1000); DEVICE_DELAY_US (1000); 状态= VL6180x_SetupGPIO1 (dev、1、1); DEVICE_DELAY_US (1000); 状态= VL6180x_RangeConfigInterrupt (dev、0、0、0、1); DEVICE_DELAY_US (1000); 状态= VL6180x_RangeStartContinuousMode (dev、1、1); DEVICE_DELAY_US (1000); int32_t 范围= 0; while (true){ 状态= VL6180x_RangeGetMeasurement (dev、&range); DEVICE_DELAY_US (1000000); //fprintf ("%c\n"、&range); 状态= VL6180x_ClearAllInterrupt (dev、1、0、1); } } // // initI2C -用于在 FIFO 模式中配置 I2C A 的函数。 // void 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 Mask // uint16_t I2CwriteData (struct I2CMsg *msg){ uint16_t 错误; if (msg->msgStatus =MSG_STATUS_SEND_WITHSTOP){ 错误= writeData (msg); if (error = success){ currentMsgPtr = msg; MSG->msgStatus = MSG_STATUS_WRITE_BUSY; 返回0; } } 否则{ 返回1; } 返回0; } // // writeData -发送要写入 EEPROM 的数据的函数 // uint16_t writeData (struct I2CMsg *msg) { //uint16_t i; // //等待 STP 位从任何先前的主设备清零 //通信。 模块将该位清零的时间延迟到之后 // SCD 位被置位。 如果在启动新的之前没有检查该位 //消息、I2C 可能会被混淆。 // if (I2C_getStopConditionStatus (I2CA_BASE)) { return (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[n]); i2C_putData (I2CA_BASE、msg->memoryLowAddr[n]); //for (i = 0;i < msg->numBytes;i++) //{ I2C_putData (I2CA_BASE、msg->msgBuffer[n]); //} // //将 START 作为主发送器发送 // I2C_setConfig (I2CA_BASE、I2C_MASTER_SEND_MODE); I2C_sendStartCondition (I2CA_BASE); I2C_sendStopCondition (I2CA_BASE); return (Success); } // // ReadData Mask // uint16_t I2CreadData (struct I2CMsg *msg) { while (true){ if (msg->msgStatus =MSG_STATUS_SEND_NOSTOP){ while (ReadData (msg)!=成功){ } currentMsgPtr = msg; MSG->msgStatus = MSG_STATUS_SEND_NOSTOP_BUSY; } 否则 if (msg->msgStatus =MSG_STATUS_RESTART){ while (ReadData (msg)!=成功){ } currentMsgPtr = msg; MSG->msgStatus = MSG_STATUS_READ_BUSY; 中断; } } 返回0; } // // ReadData -准备从 EEPROM 读取的数据的函数 // uint16_t ReadData (struct I2CMsg *msg) { // //等待 STP 位从任何先前的主设备清零 //通信。 模块将该位清零的时间延迟到之后 // SCD 位被置位。 如果在启动新的之前没有检查该位 //消息、I2C 可能会被混淆。 // if (I2C_getStopConditionStatus (I2CA_BASE)) { return (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[0]); I2C_putData (I2CA_BASE、msg->memoryLowAddr[0]); 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); } return (Success); } // // i2cAISR - I2C A ISR (非 FIFO) // _interrupt void i2cAISR (void) { 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); } } } // //中断源=寄存器访问就绪 // //此中断用于确定何时设置 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); } // VL6180X 寄存器初始化 // int VL6180x_Init (VL6180xDev_t dev){ uint16_t ArrayMemoryHighAddr[30]={0x02、0x02、0x00、0x00、0x00、 0x00、0x00、0x00、0x00、0x00、 0x00、0x00、0x00、0x00、0x00、 0x00、0x00、0x00、0x00、0x00、 0x01、0x01、0x01、0x00、0x01、 0x01、0x01、0x01、0x01、0x00}; uint16_t ArrayMemoryLowAddr[30] ={0x07、0x08、0x96、0x97、0xE3、 0xE4、0xE5、0xE6、0xE7、0xf5、 0xD9、0xDB、0xDC、0xDD、0x9F、 0xA3、0xB7、0xBB、0xB2、0xCA、 0x98、0xB0、0xAD、0xFF、0x00、 0x99、0xA6、0xAC、0xA7、0x30}; uint16_t ArrayAddrValue[30] ={0x01、0x01、0x00、0xFD、0x00、 0x04、0x02、0x01、0x03、0x02、 0x05、0xCE、0x03、0xf8、0x00、 0x3C、0x00、0x3C、0x09、0x09、 0x01、0x17、0x00、0x05、0x05、 0x05、0x1B、0x3E、0x1F、0x00}; uint16_t n = 0; INT STATUS = 0; struct I2CMsg I2CMsgInit ={MSG_STATUS_SEND_WITHSTOP、 Slave_address、 num_Bytes}; 对于(n = 0;n < 30;n++){
I2CMsgInit.memoryHighAddr[n]= ArrayMemoryHighAddr[n];
I2CMsgInit.memoryLowAddr[n]= ArrayMemoryLowAddr[n];
I2CMsgInit.msgBuffer[n]= ArrayAddrValue[n];
} 对于(n = 0;n < 30;n++){ I2CMsgInit.msgStatus = MSG_STATUS_SEND_WITHSTOP; 状态= I2CwriteData (&I2CMsgInit); DEVICE_DELAY_US (1000); } if (status){ fprintf (stderr、"初始化写入失败\n"); } 返回状态; } // // VL6180X 内部测量周期时间设置 // int VL6180x_RangeSetInterMeasPeriod (VL6180xDev_t dev、uint32_t InterMeasure Time_msec) { uint16_t settime = 0; INT STATUS = 0; if (InterMeasure Time_msec <= 2550 && InterMeasure Time_msec >=10){ settime =(uint16_t)(InterMeasure Time_msec / 10); struct I2CMsg I2CMsgOut ={MSG_STATUS_SEND_WITHSTOP、 Slave_address、 num_Bytes、 {0x00}、 {SYSRANGE_INTERMEASUREMENT_PERIOD}、 settime}; 状态= I2CwriteData (&I2CMsgOut); //status = I2CWrite (dev、SYSRANGE_INTERMEASUREMENT、settime); if (status){ fprintf (stderr、"SYSRANGE_INTERMEASUREMENT_PERIOD 写入失败"); } }否则{ fprintf (stderr、"InterMeasTime_msec 超出范围"); 状态= 1; } 返回状态; } // // VL6180X GPIO1中断设置 // int VL6180x_SetupGPIO1 (VL6180xDev_t dev、uint16_t GPIOIntOn、uint16_t ActiveHigh) { uint16_t 值= 0; INT STATUS = 0; if ((GPIOIntOn <= 0x01)&&(ActiveHigh <= 0x01)){ 值= ActiveHigh << 5; 值|= GPIOIntOn << 4; struct I2CMsg I2CMsgOut ={MSG_STATUS_SEND_WITHSTOP、 Slave_address、 num_Bytes、 {0x00}、 {SYSTEM_MODE_GPIO1}、 值}; 状态= I2CwriteData (&I2CMsgOut); //status = I2CWrite (dev、system_mode_GPIO1、value); if (status){ fprintf (stderr、"system_mode_gpio1写入失败"); } }否则{ fprintf (stderr、"GPIOIntOn 或 ActiveHigh 超出范围"); 状态= 1; } 返回状态; } // // VL6180X 范围中断配置 // int VL6180x_RangeConfigInterrupt (VL6180xDev_t dev、uint16_t LevelLow、uint16_t LevelHigh、uint16_t OutOfWindow、uint16_t NewSample) { uint16_t 值= 0; INT STATUS = 0; if ((LevelLow <= 0x01)&&(LevelHigh <= 0x01)&&(OutOfWindow <= 0x01)&&(NewSample <= 0x01)){ 值=低电平; 值|= LevelHigh << 1; if (OutOfWindow = 0x01){ 值|= 0x03; } 值|= NewSample <<2; struct I2CMsg I2CMsgOut ={MSG_STATUS_SEND_WITHSTOP、 Slave_address、 num_Bytes、 {0x00}、 {SYSTEM_INTERRUPT_CONFIG_GPIO}、 值}; 状态= I2CwriteData (&I2CMsgOut); //status = I2CWrite (dev、system_interrupt_config_GPIO、value); if (status){ fprintf (stderr、"system_interrupt_config_GPIO 写入失败"); } }否则{ fprintf (stderr、"ConfigGpioInt Out of range"); 状态= 1; } 返回状态; } // // VL6180X 范围连续模式集 // int VL6180x_RangeStartContinuousMode (VL6180xDev_t dev、uint16_t ContMode、uint16_t StartMode) { uint16_t 值= 0; INT STATUS = 0; /* FIXME 我们不会通过@A VL6180x_RangeWaitDeviceReady 检查设备是否就绪 *因此、如果调用返回到真正的 FAST、我们不会进行检查 *如果之前的模式"置位"被吸收=>位0必须为0才能工作 * if ((ContMode <= 0x01)&&(StartMode <= 0x01)){ 值= ContMode << 1; struct I2CMsg I2CMsgOut ={MSG_STATUS_SEND_WITHSTOP、 Slave_address、 num_Bytes、 {0x00}、 {SYSRANGE_START}、 值}; 状态= I2CwriteData (&I2CMsgOut); //status = I2CWrite (dev、SYSRANGE_START、Value); DEVICE_DELAY_US (100); 值|= StartMode; I2CMsgOut.msgBuffer[0]=值; I2CMsgOut.msgStatus = MSG_STATUS_SEND_WITHSTOP; 状态= I2CwriteData (&I2CMsgOut); //status = I2CWrite (dev、SYSRANGE_START、Value); if (status){ fprintf (stderr、"SYSRANGE_START 写失败"); } }否则{ fprintf (stderr、"模式或启动模式超出范围"); 状态= 1; } 返回状态; } // // VL6180X 范围获取测量 // int VL6180x_RangeGetMeasurement (VL6180xDev_t dev、int32_t *pRange_mm) { INT STATUS = 0; Int16_t RawRange = 0; struct I2CMsg I2CMsgIn ={MSG_STATUS_SEND_NOSTOP、 Slave_address、 num_Bytes、 {0x00}、 {RESULT_RANGE_RAW}、 RawRange}; 状态= I2CreadData (&I2CMsgIn); //status = I2CRead (dev、Result_range_raw、&RawRange); if (status){ fprintf (stderr、"result_range_raw 读取失败"); } 否则{ *pRange_mm =(int32_t) I2CMsgIn.msgBuffer[0]; } 返回状态; } // // VL6180X 清除中断配置 // int VL6180x_ClearAllInterrupt (VL6180xDev_t dev、uint16_t ClearRange、uint16_t ClearALS、uint16_t ClearError) { uint16_t 值= 0; INT STATUS = 0; if ((ClearRange <= 1)&&(ClearALS <= 1)&&(ClearError <= 1)){ 值= ClearError << 2; 值|= ClearALS <<1; Value |= ClearRange; struct I2CMsg I2CMsgOut ={MSG_STATUS_SEND_WITHSTOP、 Slave_address、 num_Bytes、 {0x00}、 {system_interrupt_clear}、 值}; 状态= I2CwriteData (&I2CMsgOut); //status = I2CWrite (dev、system_interrupt_clear、value); if (status){ fprintf (stderr、"system_interrupt_clear write failed"); } }否则{ fprintf (stderr、"ClearRange 或 ClearALS 或 ClearError 超出范围"); 状态= 1; } 返回状态; }
我知道您的意思、但我使用的传感器似乎使用相同的协议、每个地址具有2个字节、依此类推。 传感器是 VL6180x、这是飞行时间距离传感器。 在下面、我插入了我的当前代码、该代码正在运行、但未读出当前距离、这是我当前的目标。
我将尝试解释我的更改。 传感器在通电时处于待机状态。 然后、它需要一个寄存器写入序列进行初始化。
VL6180x_Init 为初始化写入30个寄存器。
VL6180x_RangeSetInterMeasPeriod 写入1个寄存器来设置距离测量之间的周期。
VL6180x_SetupGPIO1会设置中断引脚、稍后、当新测量准备就绪但当前未使用时、该引脚将为高电平
VL6180x_RangeConfigInterrrupt 写入1个寄存器以设置、为什么应在此处设置 GPIO1上的中断、此时新测量准备就绪、但当前未使用、稍后会如此
VL6180x_RangeStartContinuousMode 写入1个寄存器来设置连续测距模式
VL6180x_RangeMeasurement 应该读取一个寄存器、并将其设置为我要读取的变量、主函数中的变量范围(void)
VL6180x_ClearAllInterrupt 写入1个寄存器来清除中断
我仍然使用了 msg 结构、所以我不必修改太多代码、就像您想的那样。
VL6180xDev_t 类型只是单个传感器使用中从地址的整数。
我将引脚104和105用于数据 apin 和时钟引脚。
I2Cwrite/ReadData 只是掩码函数、用于在不修改原始 write/ReadData 的情况下使用 VL6180x 函数、并使用状态变量、以便中断可以正常运行。
所以一切都正常工作、代码正在运行并且没有错误、唯一的问题是 VL6180x_RangeMeasurement 不能为我提供范围测量。 有人知道原因吗? 我在每个步骤中都使用了 brakpoints、到目前为止、它没有在我的.msgbuffer[0]中放置一个值。
我知道您的意思、但我使用的传感器似乎使用相同的协议、每个地址具有2个字节、依此类推。 传感器是 VL6180x、这是飞行时间距离传感器。 下面我插入了我的当前代码、该代码正在运行、但未读出当前距离、这是我的目标。我将尝试解释我的更改。 传感器在通电时处于待机状态。
然后、它需要一个寄存器写入序列进行初始化。
VL6180x_Init 为初始化写入30个寄存器。
VL6180x_RangeSetInterMeasPeriod 写入1个寄存器来设置距离测量之间的周期。
VL6180x_SetupGPIO1会设置中断引脚、稍后、当新测量准备就绪但当前未使用时、该引脚将为高电平
VL6180x_RangeConfigInterrrupt 写入1个寄存器以设置、为什么应在此处设置 GPIO1上的中断、此时新测量准备就绪、但当前未使用、稍后会如此
VL6180x_RangeStartContinuousMode 写入1个寄存器来设置连续测距模式
VL6180x_RangeMeasurement 应该读取一个寄存器、并将其设置为我要读取的变量、主函数中的变量范围(void)
VL6180x_ClearAllInterrupt 写入1个寄存器来清除中断
我仍然使用了 msg 结构、所以我不必修改太多代码、就像您想的那样。
VL6180xDev_t 类型只是单个传感器使用中从地址的整数。
我将引脚104和105用于数据 apin 和时钟引脚。
I2Cwrite/ReadData 只是掩码函数、用于在不修改原始 write/ReadData 的情况下使用 VL6180x 函数、并使用状态变量、以便中断可以正常运行。
所以一切都正常工作、代码正在运行并且没有错误、唯一的问题是 VL6180x_RangeMeasurement 不能为我提供范围测量。
有人知道原因吗?
我在执行每个步骤后都有断点、它到目前为止并没有在.msgbuffer[0]中放置一个值。
您好、Alexander、
使用 I2C 逻辑分析仪通常可以更轻松地调试类似的内容。 您是否有机会使用您可以使用的设备?
您能否发布您遇到问题的代码段? 否则很难进行审查。
最棒的
Kevin