Hi all,
MSP430F5418A在用I2C通信过程中,需要将slave的地址装到寄存器中,我用的是7位地址模式,但是还有一位读/写位放在什么位置呢?
是和地址放到一起吗?
还有,如果我是想从slave中读数据,那么先要将地址写入,之后再写入要读去哪个寄存器,才开始读。整个过程中是不是需要读和写的过程转换?如果需要的话,应该如何
转换数据方向?
谢谢
Nick
Nick wang:
Hi
还是我,另外一个问题,当slave收到数据之后,会给master一个ACK,这个ACK是slave自动发的吧?master在检测到
ACK之后,才会继续发送下一个数据吗?
谢谢
Nick
Young Hu:
回复 Nick wang:
还是我,另外一个问题,当slave收到数据之后,会给master一个ACK,这个ACK是slave自动发的吧?master在检测到
ACK之后,才会继续发送下一个数据吗?
1、ACK是由slave自动发送的;
2、ACK是一个握手标志,如果没有检测到ACK,那么说明从机通信失败,需要重新建立通信过程。
Nick wang:
回复 Young Hu:
Hi,
十分感谢您及时的回复。
Nick
Nick wang:
回复 Young Hu:
Hi,
我在用i2c通信过程又遇到了以下问题:
我在发送数据过程中,为什么只发送了几个byte就从ISR中跳出来了?而且在发送数据过程中,STAT寄存器中SCLLOW
位始终置位,这是对的吗?
我的程序如下所示:
#include "msp430x54xA.h"
unsigned char *PTxData; // Pointer to TX data
unsigned char TXByteCtr;
#define VCC3P3_PwrOn (P8OUT |= BIT5)
#define VCC3P3_PwrGood (P8IN & BIT6)
#define LED_ON (P3OUT &= ~(BIT6))
#define LED_OFF (P3OUT |= BIT6)
const unsigned char TxData[] = // Table of data to transmit
{
0x01,
0x0b,
0x02,
0x00,
0x00,
0x03,
0x32,
0x00,
};
void test_mcu_port_init(void);
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
test_mcu_port_init();
VCC3P3_PwrOn;
while(!(VCC3P3_PwrGood))
{
;
}
LED_ON;
P3SEL |= 0x80; // Assign I2C pins to USCI_B0
P5SEL |= 0x10;
UCB1CTL1 |= UCSWRST; // Enable SW reset
UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB1CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB1BR0 = 12; // fSCL = SMCLK/12 = ~100kHz
UCB1BR1 = 0;
UCB1I2CSA = 0x4a; // Slave Address is 048h
UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB1IE |= UCTXIE; // Enable TX interrupt
// while (1)
// {
__delay_cycles(50); // Delay required between transaction
PTxData = (unsigned char *)TxData; // TX array start address
// Place breakpoint here to see each
// transmit operation.
TXByteCtr = sizeof TxData; // Load TX byte counter
UCB1CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
__bis_SR_register(GIE); // Enter LPM0, enable interrupts
__no_operation(); // Remain in LPM0 until all data
// is TX'd
while (UCB1CTL1 & UCTXSTP); // Ensure stop condition got sent
// }
}
void test_mcu_port_init(void)
{
/*将所有端口恢复到初始值*/
P1OUT &= 0x00;
P2OUT &= 0x00;
P3OUT &= 0x00;
/*LED为关闭状态*/
LED_OFF;
P4OUT &= 0x00;
/*I/O扩展芯片中断管脚拉高*/
P4OUT |= BIT6;
P5OUT &= 0x00;
P6OUT &= 0x00;
P7OUT &= 0x00;
/*关闭1.8V的MOSFET*/
P7OUT |= BIT4;
P8OUT |= 0x00;
/*定义所有端口方向和功能选择*/
P1SEL |= 0x00;
P1DIR |= 0x5b;
P2SEL |= 0x00;
P2DIR |= 0xe7;
P3SEL |= 0xbf;
P3DIR |= 0x40;
P4SEL |= 0x59;
P4DIR |= 0xae;
P5SEL |= 0xd0;
P5DIR |= 0x25;
P6SEL |= 0x03;
P6DIR |= 0x78;
P7SEL |= 0x0b;
P7DIR |= 0xb4;
P8SEL |= 0x00;
P8DIR |= 0x3f;
}
//——————————————————————————
// The USCIAB0TX_ISR is structured such that it can be used to transmit any
// number of bytes by pre-loading TXByteCtr with the byte count. Also, TXData
// points to the next byte to transmit.
//——————————————————————————
#pragma vector = USCI_B1_VECTOR
__interrupt void USCI_B1_ISR(void)
{
switch(__even_in_range(UCB1IV,12))
{
case 0: break; // Vector 0: No interrupts
case 2: break; // Vector 2: ALIFG
case 4: break; // Vector 4: NACKIFG
case 6: break; // Vector 6: STTIFG
case 8: break; // Vector 8: STPIFG
case 10: break; // Vector 10: RXIFG
case 12: // Vector 12: TXIFG
if (TXByteCtr) // Check TX byte counter
{
UCB1TXBUF = *PTxData++; // Load TX buffer
TXByteCtr–; // Decrement TX byte counter
}
else
{
UCB1CTL1 |= UCTXSTP; // I2C stop condition
UCB1IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag
}
default: break;
}
}
请帮忙解答一下
Thx
Nick
Young Hu:
回复 Nick wang:
Nick,您好,
建议您参考一下TI最近刚推出的一个MSP430的一个驱动库,其中就包括了I2C的使用,可以参考一下这部分代码。
www.ti.com.cn/…/msp430ware
Xiaowei Bai1:
Hi,
1,当写数据的时候,Master每发送完8个数据位,Slave设备如果还有空间接受下一个字节回答“ACK”,如果没有空间接收数据了,就不会发“ACK”,所以是需要检测到“ACK”后再发送下个数据个Slave.
Hardy Hu:
回复 Nick wang:
是的,ACK是slave发送,发完第8bit后,master会release SDA给slave,等待ACK,如果slave不把SDA拉低,则会触发NACK,如果拉低会触发UCB0TXIFG,因为我们一般在NCAK中断中放置STOP或者重发,在TXIFG被置位后说明slave收到了改数据,才再开始发送下一个数据
Hardy Hu:
回复 Xiaowei Bai1:
实现这个功能可以这样做,不接受数据了,在RXIFG中断中read RXBUF,然后generate NACK。
Hardy Hu:
回复 Hardy Hu:
这是从机这边的程序。
在主机端,接收到NACK时generate stop就行了。