我有一个TIVA tm4c123G我一直在尝试使用I2C协议在它和我的ADXL345传感器之间建立通信,我成功地写入并从加速度计读取设备地址的读数和我刚刚写入的寄存器值这意味着一切都运行良好。但是我已经尝试了在keil中逐步调试它并且它工作正常但是如果我运行程序它将一直给出零并且我不知道为什么?我应该在寄存器的写入和读取之间添加延迟还是在我的代码中出错?
这是我的代码附件
我正在为系统使用80 MHZ的时钟,我认为这可能是问题,但是因为代码执行下一次发送太快而应该有一些延迟?我不确定我只是猜猜请帮忙谢谢!
我对adxl的连接是
#include "tm4c123gh6pm.h"
#include "stdint.h"
void EnableI2CModule0(void);
uint8_t ReadRegister(uint8_t RegisterAddress);
void PLL_Init(void);
void WriteRegister(uint8_t RegisterAddress,uint8_t Data);
volatile uint8_t X_Axis1,X_Axis2,Y_Axis1,Y_Axis2,Z_Axis1,Z_Axis2=0;
int main()
{
volatile long temp;
PLL_Init();
EnableI2CModule0();
temp=ReadRegister(0x00);
WriteRegister(0x2D,0x08);
temp=ReadRegister(0x2D);
WriteRegister(0x31,0x0B);
temp=ReadRegister(0x31);
while(1)
{
X_Axis1=ReadRegister(0x32);
X_Axis2=ReadRegister(0x33);
Y_Axis1=ReadRegister(0x34);
Y_Axis2=ReadRegister(0x35);
Z_Axis1=ReadRegister(0x36);
Z_Axis2=ReadRegister(0x37);
}
}
void PLL_Init(void){
// 0) Use RCC2
SYSCTL_RCC2_R |= 0x80000000; // USERCC2
// 1) bypass PLL while initializing
SYSCTL_RCC2_R |= 0x00000800; // BYPASS2, PLL bypass
// 2) select the crystal value and oscillator source
SYSCTL_RCC_R = (SYSCTL_RCC_R &~0x000007C0) // clear XTAL field, bits 10-6
+ 0x00000540; // 10101, configure for 16 MHz crystal
SYSCTL_RCC2_R &= ~0x00000070; // configure for main oscillator source
// 3) activate PLL by clearing PWRDN
SYSCTL_RCC2_R &= ~0x00002000;
// 4) set the desired system divider
SYSCTL_RCC2_R |= 0x40000000; // use 400 MHz PLL
SYSCTL_RCC2_R = (SYSCTL_RCC2_R&~ 0x1FC00000) // clear system clock divider
+ (4<<22); // configure for 80 MHz clock
// 5) wait for the PLL to lock by polling PLLLRIS
while((SYSCTL_RIS_R&0x00000040)==0){}; // wait for PLLRIS bit
// 6) enable use of PLL by clearing BYPASS
SYSCTL_RCC2_R &= ~0x00000800;
}
void EnableI2CModule0(void)
{
volatile int Delay=0;
SYSCTL_RCGCI2C_R|=0x00000001; //set i2c module 0 clock active
Delay=SYSCTL_RCGCI2C_R; //delay allow clock to stabilize
SYSCTL_RCGCGPIO_R |=0x00000002; //i2c module 0 is portB so activate clock for port B
Delay = SYSCTL_RCGCGPIO_R; //delay allow clock to stabilize
GPIO_PORTB_AFSEL_R|= 0x0000000C; //enable alternate functions for PB2 and PB3
GPIO_PORTB_ODR_R |= 0x00000008; //set PB3 (I2C SDA) for open drain
GPIO_PORTB_DEN_R |= 0xFF; //Enable digital on Port B
GPIO_PORTB_PCTL_R |=0x03;
I2C0_PP_R |= 0x01;
I2C0_MTPR_R |= 0x00000027; //set SCL clock
I2C0_MCR_R |= 0x00000010; //intialize mcr rigester with that value given in datasheet
}
uint8_t ReadRegister(uint8_t RegisterAddress)
{
volatile uint8_t result=0;
I2C0_MSA_R = 0x000000A6; //write operation
I2C0_MDR_R = RegisterAddress; //place data to send mdr register
I2C0_MCS_R = 0x00000007; //stop start run
while((I2C0_MCS_R &= 0x00000040)==1); //poll busy bit
I2C0_MSA_R = 0x000000A7; // read operation
I2C0_MCS_R = 0x00000007; // stop start run
while((I2C0_MCS_R &= 0x00000040)==1); //poll busy bit
result = I2C0_MDR_R;
return result;
}
void WriteRegister(uint8_t RegisterAddress,uint8_t Data)
{
I2C0_MSA_R = 0x000000A6; //write operation
I2C0_MDR_R = RegisterAddress; //place register address to set in mdr register
I2C0_MCS_R = 0x00000003; //burst send ( multiple bytes send )
while((I2C0_MCS_R &= 0x00000040)==1); //poll busy bit
I2C0_MDR_R = Data; //place data to be sent in mdr register
I2C0_MCS_R = 0x00000005; // transmit followed by stop state
while((I2C0_MCS_R &= 0x00000040)==1); //poll busy bit
}
答案 0 :(得分:2)
您的WriteRegister
和ReadRegister
函数不遵循TM4C123G数据表中定义的流程图。除了不检查或处理MCS ERROR标志外,图16-10 多个数据字节的主发送表明在写入MCS寄存器时,应该在写入时断言特定位。所有位,您应该执行读 - 修改 - 写:
I2C0_MCS_R = 0x00000003; //burst send ( multiple bytes send )
应该是:
// I2CMCS = ---0-011
uint32_t mcs = I2C0_MCS_R ;
msc &= ~0x00000014; // ---0-0--
mcs |= 0x00000003; // ------11
I2C0_MCS_R = mcs ;
同样地:
I2C0_MCS_R = 0x00000005; // transmit followed by stop state
应该是
// I2CMCS = ---0-101
mcs = I2C0_MCS_R ;
mcs &= ~0x00000012; // ---0--0-
mcs |= 0x00000005; // -----1-1
I2C0_MCS_R = mcs ;
ReadRegister()
有类似的问题(虽然在这种情况下不太可能出现问题):
I2C0_MCS_R = 0x00000007; //stop start run
应严格:
// I2CMCS = ---00111
uint32_t mcs = I2C0_MCS_R ;
mcs &= ~0x00000018; // ---00---
mcs |= 0x00000007; // -----111
I2C0_MCS_R = mcs ;
数据表建议使用位31:5:
软件不应该依赖保留位的值。提供 与未来产品的兼容性,保留位的值应该是 在读 - 修改 - 写操作中保留。
上述代码可以做到这一点,但实际上对于这个特定的产品不一定是必要的,但无论如何都是好的做法。
无论如何,您应该添加推荐的错误处理代码。可能没有设置错误标志,但我们不知道除非你检查它,否则这样做至少会帮助调试 - 而不是踩代码,你可以简单地设置一个断点错误处理然后全速运行。这将缩小可能性的数量。
答案 1 :(得分:1)
正如@Clifford解释说我应该遵循流程图,尽管他的答案是完全正确的,但它并没有给我任何结果(以前在步入函数时给出了值,之后给了零)但是,我发现了一些东西在我之前没有注意到的流程图中,与数据表中的初始化和配置部分相矛盾
现在正如在步骤11中所说的那样,你应该在MCS寄存器中查询总线忙位但是这是错误的并且与流程图相矛盾,流程图更正确,因为你应该检查总线是否正忙发送任何内容然后检查主忙位,然后再从MDR寄存器读取或继续执行和进一步的步骤
基本上初始化和配置中的正确步骤应该是: 在步骤10之前轮询总线忙位,以防任何其他主机正在发送,在单个主机
的情况下可以省略在步骤10之后,在读取之前轮询忙碌位或进行任何进一步的步骤以判断发送是否已完成且主机是否空闲
对不起,我觉得自己现在是一个完整的白痴,因为我没有仔细阅读流程图,但我跟着另一个部分,即初始化和配置部分接受了一个不存在的事实,两者都应该暗示相同的事情。< / p>
我还发现它在流程图之后的tivaware API中正常工作,而不是数据表中的其他部分,但是我不想使用Tivaware API,因为我期待这样的问题导致更好地理解事物的运作方式
再次感谢你的帮助@Clifford欢呼!