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.

关于TM4C123GH6PM I2C loopback模式下主模块和从模块之间的通信问题

这是一个i2c在loopback模式下,主模块向从模块发送数据以及从模块向主模块发送数据的源代码:

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_i2c.h"
#include "driverlib/i2c.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "utils/uartstdio.h"
#include "driverlib/rom.h"
#include "driverlib/fpu.h"
#include "driverlib/pin_map.h"
#include "driverlib/uart.h"
// 变量定义部分
#define NUM_I2C_DATA 3 // 定义要通过I2C发送的数据包的数目
// 设定slave(从)模块的地址,是一个7-bit的地址加上RS位,具体形式如下: [A6:A5:A4:A3:A2:A1:A0:RS]
// RS位是一个指示位,如果RS=0,则说明是主发送数据,从接收数据;RS=1说明是主接收数据,从发送数据
#define SLAVE_ADDRESS 0x3C //0111100

// UART0的配置及初始化部分。
//UART0模块用于通过计算机虚拟串口显示过程信息,主要包括InitConsole函数和一些UARTprintf语句。
void InitConsole(void)
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

GPIOPinConfigure(GPIO_PA0_U0RX);
GPIOPinConfigure(GPIO_PA1_U0TX);
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
//UART0/波特率115200/时钟频率50MHZ
UARTStdioConfig(0,115200,50000000);
}

// 将I2C0模块配置为一个主模块和一个从模块,并且通过LOOPBACK模式,将它们的时钟线和数据线连接起来。由于在LOOPBACK模式下,
//主模块和从模块是在内部连接起来的。因此从模块可以接收到主模块自己发送的数据。
int main(void)
{
//使能FPU
FPUEnable();
FPULazyStackingEnable();
//定义发送数据和接收数据的缓存
uint32_t ulDataTx[NUM_I2C_DATA];
uint32_t ulDataRx[NUM_I2C_DATA];
uint32_t ulindex;
// 设置系统时钟为50MHz
SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);

// 使能I2C0模块的时钟信号.
SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
// 由于I2C0使用PB2、PB3两个引脚,需要使能GPIOB模块对应的时钟信号
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
// 将PB2的功能选择为I2C0模块的时钟信号,将PB3选择为数据信号
GPIOPinConfigure(GPIO_PB2_I2C0SCL);
GPIOPinConfigure(GPIO_PB3_I2C0SDA);
// 对PB2和PB3两个引脚做有关I2C功能的配置
GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);

// 寄存器操作:将I2C0模块配置为运行于LOOPBACK模式。在LOOPBACK模式下,I2C0模块在内部连接了主、从模块的信号线。
// 因此既可以作为主模块发送数据,也可以作为从模块接收数据
HWREG(I2C0_BASE + I2C_O_MCR) |= 0x01;//直接对寄存器进行配置

// 使能并初始化I2C0的主模块,I2C0模块使用系统时钟。
//语句的最后一个参数是用来设定数据传输速率的。false表示传输速率是100kbps,true则意味着传输速率是400kbps。此处使用的是100kbps的传输速率
I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false);
// 使能I2C0从模块。注:只是为了测试使用。
I2CSlaveEnable(I2C0_BASE);
// 设置从模块的地址
I2CSlaveInit(I2C0_BASE, SLAVE_ADDRESS);

// 使能UART模块,只是为了显示信息用
InitConsole();
UARTprintf("I2C Loopback Example ->");
UARTprintf("\n Module = I2C0");
UARTprintf("\n Mode = Single Send/Receive");
UARTprintf("\n Rate = 100kbps\n\n");
// 设置要发送的数据
ulDataTx[0] = 'I';
ulDataTx[1] = '2';
ulDataTx[2] = 'C';

// 主模块向从模块发送3个数据。
// 初始化接收缓存区
for(ulindex = 0; ulindex < NUM_I2C_DATA; ulindex++)
{
ulDataRx[ulindex] = 0;
}

// 输出信息指示是主模块发送,从模块接收
UARTprintf("Tranferring from: Master -> Slave\n");
// 设置I2C0主模块将要放在总线上的从模块地址. false代表主模块发送,从模块接收
I2CMasterSlaveAddrSet(I2C0_BASE, SLAVE_ADDRESS, false);

// 主模块向从模块发送3个I2C数据
for(ulindex = 0; ulindex < NUM_I2C_DATA; ulindex++)
{
// 显示主模块正发送的数据
UARTprintf(" Sending: '%c' . . . ", ulDataTx[ulindex]);
// 把将发送的数据存入数据寄存器中
I2CMasterDataPut(I2C0_BASE, ulDataTx[ulindex]);
// 主模块开始发送数据 ,模式:主机发送单字节数据
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);
// 等待,直到从模块接收到数据,并且发送ACK信号回应该数据
while(!(I2CSlaveStatus(I2C0_BASE) & I2C_SLAVE_ACT_RREQ));
// 从从模块中读取接收到的数据
ulDataRx[ulindex] = I2CSlaveDataGet(I2C0_BASE);
// 等待主模块发送完毕
while(I2CMasterBusy(I2C0_BASE));
// 显示已接收到的数据
UARTprintf("Received: '%c'\n", ulDataRx[ulindex]);
}

// 从模块向主模块发送3个数据。
// 重置接收缓存区
for(ulindex = 0; ulindex < NUM_I2C_DATA; ulindex++)
{
ulDataRx[ulindex] = 0;
}
// 输出信息指示是从模块发送,主模块接收
UARTprintf("\n\nTranferring from: Slave -> Master\n");
// 更改数据传输方向,ture代表主模块接收,从模块发送
I2CMasterSlaveAddrSet(I2C0_BASE, SLAVE_ADDRESS, true);
// 一次虚假的接收,用于确保不会收到前面留下的垃圾数据
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
// 一次虚假的确认,以清除掉那些不该存在的flag,即指示信号
while(!(I2CSlaveStatus(I2C0_BASE) & I2C_SLAVE_ACT_TREQ));
// 从模块向主模块发送3个I2C数据
for(ulindex = 0; ulindex < NUM_I2C_DATA; ulindex++)
{
// 显示从模块正发送的数据
UARTprintf(" Sending: '%c' . . . ", ulDataTx[ulindex]);
// 把将发送的数据存入数据寄存器中
I2CSlaveDataPut(I2C0_BASE, ulDataTx[ulindex]);
// 主模块开始读取数据
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
// 等待,直到从模块完成了数据发送
while(!(I2CSlaveStatus(I2C0_BASE) & I2C_SLAVE_ACT_TREQ));
// 从主模块中读取已接收的数据
ulDataRx[ulindex] = I2CMasterDataGet(I2C0_BASE);
// 显示已接收到的数据
UARTprintf("Received: '%c'\n", ulDataRx[ulindex]);
}

// 输出程序完毕信息
UARTprintf("\nDone.\n\n");
}

把 主模块发送从模块接收 和 从模块发送主模块接收 两种模式单独拿出来跑后发现 从模块发送主模块接收 正常,但是 主模块发送从模块接收 跑起来之后程序就一直停在第一条红色语句上,说明主模块发送数据不成功。。。这是怎么回事,调试了一下午都没有解决。理论上两种模式的配置差不多。为什么一种可以另一种不可以?求大神们解答。