这段代码有问题吗: /* --COPYRIGHT--,BSD * Copyright (c) 2017, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * --/COPYRIGHT--*/ #include "driverlib.h" //***************************************************************************** //! This example shows how to configure the I2C module as a master for //! multi byte transmission in interrupt driven mode. The address of the slave //! module is set in this example. //! //! This example uses the following peripherals and I/O signals. You must //! review these and change as needed for your own board: //! - I2C peripheral //! - GPIO Port peripheral (for I2C pins) //! - SCL2 //! - SDA //! //! This example uses the following interrupt handlers. To use this example //! in your own application you must add these interrupt handlers to your //! vector table. //! - USCI_B0_VECTOR. // //***************************************************************************** //***************************************************************************** // //Set the address for slave module. This is a 7-bit address sent in the //following format: //[A6:A5:A4:A3:A2:A1:A0:RS] // //A zero in the "RS" position of the first byte means that the master //transmits (sends) data to the selected slave, and a one in this position //means that the master receives data from the slave. // //***************************************************************************** #define SLAVE_ADDRESS 0x48 //***************************************************************************** // //Specify number of bytes to be transmitted // //***************************************************************************** #define TXLENGTH 0x04 uint8_t transmitData[40] = { 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68}; uint8_t transmitCounter = 0; void main () { //Stop WDT WDT_A_hold(WDT_A_BASE); //Assign I2C pins to USCI_B0 GPIO_setAsPeripheralModuleFunctionInputPin( GPIO_PORT_P3, GPIO_PIN1 + GPIO_PIN2 ); //Initialize Master USCI_B_I2C_initMasterParam param = {0}; param.selectClockSource = USCI_B_I2C_CLOCKSOURCE_SMCLK; param.i2cClk = UCS_getSMCLK(); param.dataRate = USCI_B_I2C_SET_DATA_RATE_400KBPS; USCI_B_I2C_initMaster(USCI_B0_BASE, ¶m); //Specify slave address USCI_B_I2C_setSlaveAddress(USCI_B0_BASE, SLAVE_ADDRESS ); //Set Transmit mode USCI_B_I2C_setMode(USCI_B0_BASE, USCI_B_I2C_TRANSMIT_MODE ); //Enable I2C Module to start operations USCI_B_I2C_enable(USCI_B0_BASE); while (1) { //Enable transmit Interrupt USCI_B_I2C_clearInterrupt(USCI_B0_BASE, USCI_B_I2C_TRANSMIT_INTERRUPT ); USCI_B_I2C_enableInterrupt(USCI_B0_BASE, USCI_B_I2C_TRANSMIT_INTERRUPT ); //Delay between each transaction __delay_cycles(50); //Load TX byte counter transmitCounter = 1; //Initiate start and send first character USCI_B_I2C_masterSendMultiByteStart(USCI_B0_BASE, transmitData[0] ); //Enter LPM0 with interrupts enabled __bis_SR_register(LPM0_bits + GIE); __no_operation(); //Delay until transmission completes while (USCI_B_I2C_isBusBusy(USCI_B0_BASE)) ; } } //****************************************************************************** // //This is the USCI_B0 interrupt vector service routine. // //****************************************************************************** #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector=USCI_B0_VECTOR __interrupt #elif defined(__GNUC__) __attribute__((interrupt(USCI_B0_VECTOR))) #endif void USCI_B0_ISR (void) { switch (__even_in_range(UCB0IV,12)){ case USCI_I2C_UCTXIFG: { //Check TX byte counter if (transmitCounter < TXLENGTH){ //Initiate send of character from Master to Slave USCI_B_I2C_masterSendMultiByteNext(USCI_B0_BASE, transmitData[transmitCounter] ); //Increment TX byte counter transmitCounter++; } else { //Initiate stop only USCI_B_I2C_masterSendMultiByteStop(USCI_B0_BASE); //Clear master interrupt status USCI_B_I2C_clearInterrupt(USCI_B0_BASE, USCI_B_I2C_TRANSMIT_INTERRUPT); //Exit LPM0 on interrupt return __bic_SR_register_on_exit(LPM0_bits); } break; } } }
时间: 2025-06-30 08:10:51 浏览: 16
这段代码是基于 TI MSP430 系列微控制器的 I²C 主机通信示例,使用 USCI_B0 模块以中断方式发送多个字节的数据。整体结构清晰,符合 TI 提供的 DriverLib 使用规范。但仍然存在一些潜在问题和可以优化的地方。
---
## ✅ **主要问题分析**
### 1. **全局变量 `transmitCounter` 的线程安全性问题**
- `transmitCounter` 被主函数和中断服务程序(ISR)共同访问。
- 在多任务或频繁调用中断的环境中可能引发竞态条件。
- **建议方案**:使用局部状态结构体封装传输信息,或在访问前加锁(如禁用中断)。
---
### 2. **未处理错误中断情况**
- ISR 中仅处理了 `UCTXIFG`(发送中断),未处理其他可能的中断标志(如 NACK、仲裁丢失等)。
- **建议方案**:扩展中断判断逻辑,添加错误处理分支。
---
### 3. **死循环中缺乏看门狗喂狗机制**
- 在 `while(1)` 循环中没有喂狗操作,可能导致看门狗超时复位。
- **建议方案**:在主循环中加入 `WDT_A_clear()`。
---
### 4. **延迟方式不够可靠**
- 使用 `__delay_cycles(50)` 实现延时,依赖于系统时钟且精度不高。
- **建议方案**:使用定时器或 RTOS 延时接口替代。
---
### 5. **I²C 初始化配置可读性差**
- 结构体初始化为 `{0}`,不利于维护。
- **建议方案**:显式初始化所有字段,并注释说明。
---
## ✅ **改进建议代码示例**
### 使用局部结构体封装传输状态
```cpp
typedef struct {
uint8_t *data;
uint8_t length;
uint8_t index;
} I2cTxContext;
I2cTxContext txContext = { transmitData, TXLENGTH, 0 };
```
替换原全局变量:
```cpp
// 原:
// uint8_t transmitCounter = 0;
// 改为:
I2cTxContext txContext = { transmitData, sizeof(transmitData), 0 };
```
并在 ISR 中使用:
```cpp
case USCI_I2C_UCTXIFG:
{
if (txContext.index < txContext.length)
{
USCI_B_I2C_masterSendMultiByteNext(USCI_B0_BASE,
txContext.data[txContext.index++]);
}
else
{
USCI_B_I2C_masterSendMultiByteStop(USCI_B0_BASE);
__bic_SR_register_on_exit(LPM0_bits);
}
break;
}
```
---
### 完善中断错误处理
```cpp
case USCI_I2C_UCNACKIFG:
// Handle NACK error
USCI_B_I2C_masterSendMultiByteStop(USCI_B0_BASE);
USCI_B_I2C_clearInterrupt(USCI_B0_BASE, USCI_I2C_UCNACKIFG);
__bic_SR_register_on_exit(LPM0_bits);
break;
```
---
### 添加看门狗喂狗操作
```cpp
while (1)
{
WDT_A_clear(); // 防止看门狗溢出
//Enable transmit Interrupt
USCI_B_I2C_clearInterrupt(USCI_B0_BASE, USCI_B_I2C_TRANSMIT_INTERRUPT);
USCI_B_I2C_enableInterrupt(USCI_B0_BASE, USCI_B_I2C_TRANSMIT_INTERRUPT);
//Load TX byte counter
txContext.index = 0;
//Initiate start and send first character
USCI_B_I2C_masterSendMultiByteStart(USCI_B0_BASE, txContext.data[txContext.index++]);
//Enter LPM0 with interrupts enabled
__bis_SR_register(LPM0_bits + GIE);
__no_operation();
//Delay until transmission completes
while (USCI_B_I2C_isBusBusy(USCI_B0_BASE)) ;
}
```
---
## ✅ **解释说明**
| 改进点 | 说明 |
|--------|------|
| 封装传输上下文 | 提高代码模块化程度,避免全局变量污染 |
| 错误中断处理 | 增强系统鲁棒性,及时响应硬件异常 |
| 看门狗喂狗 | 避免因长时间无操作导致系统重启 |
| 可靠延时机制 | 提升移植性和精确度 |
---
##
阅读全文
相关推荐
















