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.

清华大学TM4C123微处理器原理与实践例程-I2C实验程序解析



// I2C实验程序解析
//头文件
#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"

// 变量定义部分
#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

// UART0的配置及初始化部分。*
// UART0模块用于通过计算机虚拟串口显示过程信息,主要包括InitConsole
//函数和一些UARTprintf语句。
void InitConsole(void)
{
    // 由于UART0使用PA0、PA1两个引脚,因此需要使能GPIOA模块
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

	//将PA0和PA1两个引脚的功能选择为执行UART0模块的功能
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);

    // 将PA0和PA1两个引脚配置为UART功能
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    // UART的标准初始化
    UARTStdioConfig(0,115200,50000000);
}
// main 函数
// 将I2C0模块配置为一个主模块和一个从模块,并且通过LOOPBACK模式,
//将它们的时钟线和//数据线连接起来。由于在LOOPBACK模式下,
//主模块和从模块是在内部连接起来的。因此从//模块可以接收到主模块
//自己发送的数据。
int main(void)
{
	//使能FPU
	FPUEnable();
	FPULazyStackingEnable();

	//定义发送数据和接收数据的缓存
	ui32 ulDataTx[NUM_I2C_DATA];
	ui32 ulDataRx[NUM_I2C_DATA];
	ui32 ulindex;

	// 设置系统时钟为50MHz
SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);//错误
   
 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);//错误
    GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
    GPIOPinTypeI2C(GPIO_PORTB_BASE, 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);

    // 设置I2C0主模块将要放在总线上的从模块地址
    // false代表主模块发送,从模块接收
    I2CMasterSlaveAddrSet(I2C0_BASE, SLAVE_ADDRESS, false);

    // 使能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");

    // 主模块向从模块发送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_SCSR_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");
    return(0);
}