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.

[参考译文] CCS/TM4C123GE6PM:I2C 多读问题

Guru**** 2584225 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/864565/ccs-tm4c123ge6pm-i2c-multiple-read-issue

器件型号:TM4C123GE6PM

工具/软件:Code Composer Studio

你(们)好  

我已经编写了 I2C 代码来读取 TCS34725设备 ID 并能够发送命令和接收响应、但在我的响应中、我只获得读取地址响应、而下面的下一个字节不是我的代码和响应、我需要读取2字节响应、但我需要读取 只读1个字节、请告诉我错过了什么  

//
//
// slave_receive_int.c -演示简单 I2C 主消息的示例
//数据为时使用从机中断进行传输
//已收到。
//
//版权所有(c) 2010-2015 Texas Instruments Incorporated。 保留所有权利。
//软件许可协议
//
//以源代码和二进制形式重新分发和使用,有无
//如果满足以下条件,则允许进行修改
//满足:
//
//重新分发源代码必须保留上述版权
//注意、此条件列表和以下免责声明。
//
//二进制形式的重新分发必须复制上述版权
//注意、中的条件列表和以下免责声明
//随提供的文档和/或其他材料
//分布。
//
//德州仪器公司的名称和的名称都不是
//其贡献者可用于认可或推广衍生产品
//未经特定的事先书面许可,从该软件下载。
//
//本软件由版权所有者和作者提供
//“原样”以及任何明示或暗示的保证,包括但不包括
//限于对适销性和适用性的暗示保证
//一个特定的目的是免责的。 在任何情况下、版权均不得
//所有者或贡献者应对任何直接、间接、偶然、
//特殊、典型或必然的损害(包括但不包括)
//仅限于采购替代货物或服务;
//数据或利润;或业务中断)
//责任理论,无论是合同责任、严格责任还是侵权行为
//(包括疏忽或其他)以任何方式因使用而产生
//此软件,即使已被告知可能会发生此类损坏。
//
//这是 Tiva 固件开发包的版本2.1.1.71的一部分。
//
//

#include
#include
#include "inc/hw_i2c.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"

uint32_t I2CReceive (uint32_t SLAVE_addr、uint8_t reg);

//
//
//! \addtogroup i2c_examples_list
//!

从器件接收中断(SLAVE_Receive_int)


//!
//! 此示例展示了如何在从器件上配置接收中断
//! 模块。 这还包括将 I2C0模块设置为环回模式
//! 配置主模块和从模块。 内部回送模式
//! 将主从数据线和时钟线连接在一起。 地址
//! 设置为一个值、以便从接收数据
//! 主器件。
//!
//! 此示例使用以下外设和 I/O 信号。 您必须执行的操作
//! 查看这些内容并根据您自己的董事会的需要进行更改:
//! I2C0外设
//! - GPIO 端口 B 外设(用于 I2C0引脚)
//! - I2C0SCL - PB2
//! - I2C0SDA - PB3
//!
//! 以下 UART 信号仅配置为显示控制台
//! 消息。 I2C 操作不需要这些。
//! UART0外设
//! - GPIO 端口 A 外设(用于 UART0引脚)
//! - UART0RX - PA0
//! - UART0TX - PA1
//!
//! 此示例使用以下中断处理程序。 来使用该示例
//! 在您自己的应用程序中、您必须将这些中断处理程序添加到
//! 矢量表。
//! - INT_I2C0 - I2C0SlaveIntHandler
//
//

//
//
//设置从机模块的地址。 这是在中发送的7位地址
//以下格式:
//[A6:A5:A4:A3:A2:A1:A0:RS]
//
//第一个字节 R/S 位置的零表示主器件
//将数据发送(发送)到所选的从器件,并在该位置发送一个数据
//表示主器件从从器件接收数据。
//
//
#define SLAVE_ADDRESS 0x29

//
//
//用于保存已接收的 I2C 数据的全局变量。
//
//
静态 uint32_t g_ui32DataRx1;
静态 uint32_t g_ui32DataRx2;

静态 uint32_t g_ui32DataRx3;


静态 uint32_t data_count=2;
//
//
//这是在中断处理程序中设置的标志,用于指示
//发生中断。
//
//
静态 bool g_bIntFlag = false;

//
//
//此函数将 UART0设置为用于控制台显示信息
//因为示例正在运行。
//
//
无效
InitConsole (空)

//
//启用用于 UART0引脚的 GPIO 端口 A。
// TODO:将其更改为您正在使用的 GPIO 端口。
//
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);

//
//为端口 A0和 A1上的 UART0功能配置引脚复用。
//如果您的器件不支持引脚复用、则无需执行此步骤。
// TODO:更改此选项以选择您正在使用的端口/引脚。
//
GPIOPinConfigure (GPIO_PA0_U0RX);
GPIOPinConfigure (GPIO_PA1_U0TX);

//
//启用 UART0以便我们可以配置时钟。
//
SysCtlPeripheralEnable (SYSCTL_Periph_UART0);

//
//使用内部16MHz 振荡器作为 UART 时钟源。
//
UARTClockSourceSet (UART0_BASE、UART_CLOCK_PIOSC);

//
//为这些引脚选择替代(UART)功能。
// TODO:更改此选项以选择您正在使用的端口/引脚。
//
GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1);

//
//初始化控制台 I/O 的 UART
//
UARTStdioConfig (0、115200、16000000);

//
//
// I2C0数据从机中断的中断处理程序。
//
//
空 I2C0SlaveIntHandler (空)

//
//清除 I2C0中断标志。
//
I2CSlaveIntClear (I2C0_BASE);

//
//从从从器件读取数据。
//

G_ui32DataRX1= I2CSlaveDataGet (I2C0_BASE);
//
//设置一个标志来指示中断发生。
//
G_bIntFlag = true;

//
//
//配置 I2C0主机和从机,并使用环回模式连接它们。
//
//
内部
main (空)

#if defined (target_IS_TM4C129_RA0)||\
已定义(TARGET_IS_TM4C129_RA1)||\
已定义(TARGET_IS_TM4C129_RA2)
uint32_t ui32SysClock;
#endif
uint32_t ui32DataTx[3];

//
//将时钟设置为直接从外部晶振/振荡器运行。
// TODO:必须更改 SYSCTL_XTAL_VALUE 以匹配的值
板上的//晶体。
//
#if defined (target_IS_TM4C129_RA0)||\
已定义(TARGET_IS_TM4C129_RA1)||\
已定义(TARGET_IS_TM4C129_RA2)
ui32SysClock = SysCtlClockFreqSet ((SYSCTL_XTAL_25MHz |
SYSCTL_OSC_MAIN |
SYSCTL_USE_PLL)、25000000);
其他
SysCtlClockSet (SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
SYSCTL_XTAL_16MHz);
#endif

//
//使用前必须启用 I2C0外设。
//
SysCtlPeripheralEnable (SYSCTL_Periph_I2C0);

//
//对于本示例,I2C0与 PortB[3:2]一起使用。 实际端口和
//使用的引脚可能与您的器件不同、请参阅的数据表
//更多信息。 GPIO 端口 B 需要启用、因此这些引脚可以
//使用。
// TODO:将其更改为您正在使用的 GPIO 端口。
//
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOB);

//
//为端口 B2和 B3上的 I2C0功能配置引脚复用。
//如果您的器件不支持引脚复用、则无需执行此步骤。
// TODO:更改此选项以选择您正在使用的端口/引脚。
//
GPIOPinConfigure (GPIO_PB2_I2C0SCL);
GPIOPinConfigure (GPIO_PB3_I2C0SDA);

//
//为这些引脚选择 I2C 功能。 此函数也会
//为 I2C 操作配置 GPIO 引脚,将其设置为
//开漏操作,弱上拉。 请参阅数据表
//查看每个引脚分配了哪些功能。
// TODO:更改此选项以选择您正在使用的端口/引脚。
//
GPIOPinTypeI2CSCL (GPIO_PORTB_BASE、GPIO_PIN_2);
GPIOPinTypeI2C (GPIO_PORTB_BASE、GPIO_PIN_3);

//
//启用环回模式。 环回模式是一个内置的功能、它很有用
//用于调试 I2Cx 模块。 它在内部连接 I2C 主设备和
//从终端,这可以有效地让您以主设备和的方式发送数据
//作为从机接收数据。 注意:对于外部 I2C 操作、您将需要
//使用比内部上拉更快的外部上拉。
//有关更多信息,请参阅数据表。
//
HWREG (I2C0_BASE + I2C_O_MCR)|= 0x01;

//
//在处理器(NVIC)上启用 I2C0中断。
//
IntEnable (INT_I2C0);

//
//配置和打开 I2C0从机中断。 I2CSlaveIntEnableEx()
//使您能够仅启用特定中断。 在本例中为
//我们仅在从设备接收数据时中断。
//
I2CSlaveIntEnableEx (I2C0_BASE、I2C_SLAVE_INT_DATA);

//
//启用和初始化 I2C0主机模块。 使用的系统时钟
// I2C0模块。 最后一个参数设置 I2C 数据传输速率。
//如果为 false,则数据速率设置为100kbps,如果为 true,则数据速率将设置为
//设置为400kbps。 在本示例中、我们将使用100kbps 的数据速率。
//
#if defined (target_IS_TM4C129_RA0)||\
已定义(TARGET_IS_TM4C129_RA1)||\
已定义(TARGET_IS_TM4C129_RA2)
I2CMasterInitExpClk (I2C0_BASE、ui32SysClock、false);
其他
I2CMasterInitExpClk (I2C0_BASE、SysCtlClockGet ()、false);
#endif

//
//启用 I2C0从机模块。
//
I2CSlaveEnable (I2C0_BASE);

//
//将从地址设置为 SLAVE_ADDRESS。 在回送模式下、它是一个
//发送到的任意7位数(在上面的宏中设置)
// I2CMasterSlaveAddrSet 函数。
//
I2CSlaveInit (I2C0_BASE、SLAVE_ADDRESS);

//
//告诉主模块何时将在总线上放置什么地址
//与从设备通信。 将地址设置为 SLAVE_ADDRESS
//(在从机模块中设置)。 接收参数设置为 false
//表示 I2C 主设备正在向从设备发起写入操作。 如果
// true、这表示 I2C 主设备正在启动读取
//从器件。
//
I2CMasterSlaveAddrSet (I2C0_BASE、SLAVE_ADDRESS、FALSE);

//
//设置用于显示消息的串行控制台。 这只是
//对于此示例程序,正确的 I2C 操作不需要。
//
InitConsole();

//
//启用到处理器的中断。
//
// IntMasterEnable();

//
//在控制台上显示示例设置。
//
UARTprintf ("I2C 从机中断示例->");
UARTprintf ("\n 模块= I2C0");
UARTprintf ("\n 模式=从机模块上的接收中断");
UARTprintf ("\n 速率= 100kbps\n");

//
//初始化要发送的数据。
//

ui32DataTx[0]= 0x00;
ui32DataTx[1]= 0x01;
ui32DataTx[2]= 0x12;

while (1)

UARTprintf ("正在从主设备->从设备进行传输\n");
UARTprintf ("正在发送:"%x"、ui32DataTx[0]);
I2CMasterDataPut (I2C0_BASE、ui32DataTx[0]);
I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_SINGLE_SEND);
while (!I2CMasterBusy (I2C0_BASE));

UARTprintf ("正在从主设备->从设备进行传输\n");
UARTprintf ("正在发送:"%x"、ui32DataTx[1]);
I2CMasterDataPut (I2C0_BASE、ui32DataTx[1]);
I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_SINGLE_SEND);
while (!I2CMasterBusy (I2C0_BASE));


SysCtlDelay (1000000);
UARTprintf ("正在从主设备->从设备进行传输\n");
UARTprintf ("正在发送:"%x"、ui32DataTx[2]);
I2CMasterDataPut (I2C0_BASE、ui32DataTx[2]);
I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_SINGLE_SEND);
I2CMasterSlaveAddrSet (I2C0_BASE、SLAVE_ADDRESS、TRUE);
I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_Receive_start);

while (!I2CMasterBusy (I2C0_BASE));

G_ui32DataRx1 =(uint8_t) I2CMasterDataGet (I2C0_BASE);

while (!I2CMasterBusy (I2C0_BASE));
I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_SEND_CONT);

G_ui32DataRx2 =(uint8_t) I2CMasterDataGet (I2C0_BASE);
I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_Receive_finish);
while (!I2CMasterBusy (I2C0_BASE));
G_ui32DataRx3=(uint8_t) I2CMasterDataGet (I2C0_BASE);
I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_SEND_FINISH);
UARTprintf ("\n 接收到从机中断!\n");


UARTprintf ("已接收:'%x'\n\n"、g_ui32DataRx1);
UARTprintf ("已接收:'%x'\n\n"、g_ui32DataRx2);
UARTprintf ("已接收:'%x'\n\n"、g_ui32DataRx3);

SysCtlDelay (10000000);




来自 UART 终端的响应

I2C 从机中断示例->
模块= I2C0
MODE =从机模块上的接收中断
速率= 100kbps

正在从主设备->从设备传输
正在发送:"0"正在从主设备->从设备传输
正在发送:"1"正在从:主设备->从设备传输
发送:'12'
从机中断已接收!
已接收:'53'   //地址 OS 0x29导致读取的0x53  

已接收:"0"

已接收:"0"

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Nandish、

    您的代码设置不正确。 您需要执行相互独立的发送和接收操作。 我的意思是、当您执行 Receive_start 时、在接收完成之前不应发送。 如果需要在之间发送字节、则需要发送和接收单个字节而不是突发字节。 下面这部分代码是我发现该问题的地方、也是您需要解决的问题、方法   是确保在开始之前完成 I2C_MASTER_CMD_BURST_Receive_Finish 和 I2C_MASTER_CMD_BURST_SEND_FINISH -或改用 I2C_MASTER_CMD_SINGLE_Receive 和 I2C_MASTER_CMD_SINGLE_Receive。

    [引用用户="nanish HS"]

    I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_Receive_start);

    while (!I2CMasterBusy (I2C0_BASE));

    G_ui32DataRx1 =(uint8_t) I2CMasterDataGet (I2C0_BASE);

    while (!I2CMasterBusy (I2C0_BASE));
    I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_SEND_CONT);

    G_ui32DataRx2 =(uint8_t) I2CMasterDataGet (I2C0_BASE);
    I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_Receive_finish);
    while (!I2CMasterBusy (I2C0_BASE));
    G_ui32DataRx3=(uint8_t) I2CMasterDataGet (I2C0_BASE);
    I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_SEND_FINISH);
    UARTprintf ("\n 接收到从机中断!\n");

    [/报价]