Forum: Mikrocontroller und Digitale Elektronik Drucksensor mit MSP430 über I2C ansteuern


von Marc (Gast)


Lesenswert?

Hallo liebes Forum,

ich sitze schon einige Tage an der Implementierung einer Druckmessung 
und komme hier nicht weiter.

Ich möchte einen ABPDANN005PG2A3 Drucksensor an einen MSP430G2553 über 
I2C auslesen.
Aus dem Datenblatt des Sensors entnehme ich
Pin1 - NGD
Pin2 - VDD
Pin3 - SS/INT
Pin4 - NC
Pin5 - SDA
Pin6 - SCL

Der MSP hat
Pin 1.6 - SCL
Pin 1.7 - SDA

Also verbinde ich die beiden SDA Pins miteinander, die beiden SCL Pins 
miteinander und schließe VDD an die 3.3V des MSP und GND and GND an. SCL 
und SDA schließe ich noch mit 10kOhm Pullup an VDD an. Soweit so 
richtig, hoffe ich.
Erste Frage: Was mache ich mit dem SS/INT-Pin? Es könnte auch sein, dass 
sich das auf einen anderen Sensor mit SPI bezieht (gemeinsames 
Datenblatt), aber vllt. weiß da ja jemand mehr.

Ich habe versucht, die TI_USCI_I2C_master.h/TI_USCI_I2C_master.h.c zu 
verwenden um keine Fehler zu machen.
Dabei habe ich, wie in der Anleitung beschrieben, die beiden Pins SDA 
und SCL neu definiert. Desweiteren habe ich in der ..master.c P3SEL 
durch P1SEL ersetzt, da der verwendete MSP ja am 1. Port kommunizieren 
soll (richtig?).
In der ersten Version der main.c habe ich versucht, eine LED an- und 
auszuschalten, je nachdem ob ein I2C-Client angeschlossen ist oder 
nicht. Jedoch bleibt die LED aus, weil die Schleife "while (UCB0CTL1 & 
UCTXSTP);" nicht verlassen wird.
In der zweiten Version habe ich dann versucht, etwas auszulesen. Leider 
macht es bei beiden Programmen keinen Unterschied, ob der Sensor 
angeschlossen ist oder nicht.

Könnt ihr mir sagen, was ich falsch mache oder habe ich ein grundlegend 
falsches Verständnis vom Code? Ich bin noch Anfänger.

Vielen Dank!


Der Code von beiden Dateien und der main.c sind unten angehängt.


main.c (V1):
1
#include <msp430g2553.h> 
2
#include "TI_USCI_I2C_master.h"
3
4
void main1(void)
5
{
6
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
7
    P1DIR  |= BIT0;          // P1.0 set as output
8
  P1OUT  &= ~(BIT0);        // P1.0 set low
9
    
10
    TI_USCI_I2C_transmitinit(0x28,0x3f);
11
12
    while(1)
13
    {
14
        if(TI_USCI_I2C_slave_present(0x28))   // check for slave
15
        {
16
            P1OUT |= BIT0;
17
        }
18
        else
19
        {
20
            P1OUT &= ~(BIT0);
21
        }
22
    }
23
}

main.c (V2)
1
#include <msp430g2553.h> 
2
#include "TI_USCI_I2C_master.h"
3
4
unsigned char array[5] = { 0, 0, 0, 0, 0 };
5
6
void main(void)
7
{
8
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
9
    
10
    _EINT(); // enable interrupts
11
    
12
    TI_USCI_I2C_receiveinit(0x28,0x3f); // initialize USCI and DMA module
13
    
14
    while ( TI_USCI_I2C_notready() ); // wait for bus to be free
15
    
16
    TI_USCI_I2C_receive(3,array); // receive the first 3 bytes of array
17
    
18
    LPM0; // put CPU to sleep during communication
19
}

TI_USCI_I2C_master.h:
1
#ifndef USCI_LIB
2
#define USCI_LIB
3
4
#define SDA_PIN BIT7
5
#define SCL_PIN BIT6
6
7
void TI_USCI_I2C_receiveinit(unsigned char slave_address, unsigned char prescale);
8
void TI_USCI_I2C_transmitinit(unsigned char slave_address, unsigned char prescale);
9
10
void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field);
11
void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field);
12
13
unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address);
14
unsigned char TI_USCI_I2C_notready();
15
16
#endif

TI_USCI_I2C_master.h.c:
1
#include "msp430g2553.h"                        // device specific header
2
#include "TI_USCI_I2C_master.h"
3
4
signed char byteCtr;
5
unsigned char *TI_receive_field;
6
unsigned char *TI_transmit_field;
7
8
void TI_USCI_I2C_receiveinit(unsigned char slave_address, unsigned char prescale)
9
{
10
  P1SEL |= SDA_PIN + SCL_PIN;                 // Assign I2C pins to USCI_B0   P3???
11
  UCB0CTL1 = UCSWRST;                         // Enable SW reset
12
  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;       // I2C Master, synchronous mode
13
  UCB0CTL1 = UCSSEL_2 + UCSWRST;              // Use SMCLK, keep SW reset
14
  UCB0BR0 = prescale;                         // set prescaler
15
  UCB0BR1 = 0;
16
  UCB0I2CSA = slave_address;                  // set slave address
17
  UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
18
  UCB0I2CIE = UCNACKIE;
19
  IE2 = UCB0RXIE;                             // Enable RX interrupt
20
}
21
 
22
void TI_USCI_I2C_transmitinit(unsigned char slave_address, unsigned char prescale)
23
{
24
  P1SEL |= SDA_PIN + SCL_PIN;                 // Assign I2C pins to USCI_B0 P3???
25
  UCB0CTL1 = UCSWRST;                         // Enable SW reset
26
  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;       // I2C Master, synchronous mode
27
  UCB0CTL1 = UCSSEL_2 + UCSWRST;              // Use SMCLK, keep SW reset
28
  UCB0BR0 = prescale;                         // set prescaler
29
  UCB0BR1 = 0;
30
  UCB0I2CSA = slave_address;                  // Set slave address
31
  UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
32
  UCB0I2CIE = UCNACKIE;
33
  IE2 = UCB0TXIE;                             // Enable TX ready interrupt
34
}
35
36
void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field)
37
{
38
  TI_receive_field = field;
39
  if ( byteCount == 1 )
40
  {
41
    byteCtr = 0 ;
42
    __disable_interrupt();
43
    UCB0CTL1 |= UCTXSTT;                      // I2C start condition
44
    while (UCB0CTL1 & UCTXSTT);               // Start condition sent?
45
    UCB0CTL1 |= UCTXSTP;                      // I2C stop condition
46
    __enable_interrupt();
47
  } 
48
  else if ( byteCount > 1 ) 
49
  {
50
    byteCtr = byteCount - 2 ;
51
    UCB0CTL1 |= UCTXSTT;                      // I2C start condition
52
  } 
53
  else
54
    while (1);                                // illegal parameter
55
}
56
57
void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field)
58
{
59
  TI_transmit_field = field;
60
  byteCtr = byteCount;
61
  UCB0CTL1 |= UCTR + UCTXSTT;                 // I2C TX, start condition
62
}
63
64
unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address)
65
{
66
  unsigned char ie2_bak, slaveadr_bak, ucb0i2cie, returnValue;
67
  ucb0i2cie = UCB0I2CIE;                      // restore old UCB0I2CIE
68
  ie2_bak = IE2;                              // store IE2 register
69
  slaveadr_bak = UCB0I2CSA;                   // store old slave address
70
  UCB0I2CIE &= ~ UCNACKIE;                    // no NACK interrupt
71
  UCB0I2CSA = slave_address;                  // set slave address
72
  IE2 &= ~(UCB0TXIE + UCB0RXIE);              // no RX or TX interrupts
73
  __disable_interrupt();
74
  UCB0CTL1 |= UCTR + UCTXSTT + UCTXSTP;       // I2C TX, start condition
75
  while (UCB0CTL1 & UCTXSTP);                 // wait for STOP condition
76
  
77
  returnValue = !(UCB0STAT & UCNACKIFG);
78
  __enable_interrupt();
79
  IE2 = ie2_bak;                              // restore IE2
80
  UCB0I2CSA = slaveadr_bak;                   // restore old slave address
81
  UCB0I2CIE = ucb0i2cie;                      // restore old UCB0CTL1
82
  return returnValue;                         // return whether or not 
83
                                              // a NACK occured
84
}
85
86
unsigned char TI_USCI_I2C_notready()
87
{
88
  return (UCB0STAT & UCBBUSY);
89
}
90
91
92
#pragma vector = USCIAB0RX_VECTOR
93
__interrupt void USCIAB0RX_ISR(void)
94
{
95
  if (UCB0STAT & UCNACKIFG)
96
  {            // send STOP if slave sends NACK
97
    UCB0CTL1 |= UCTXSTP;
98
    UCB0STAT &= ~UCNACKIFG;
99
  }
100
}
101
102
103
#pragma vector = USCIAB0TX_VECTOR
104
__interrupt void USCIAB0TX_ISR(void)
105
{
106
  if (IFG2 & UCB0RXIFG)
107
  {
108
    if ( byteCtr == 0 )
109
    {
110
      UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
111
      *TI_receive_field = UCB0RXBUF;
112
      TI_receive_field++;
113
    }
114
    else 
115
    {
116
      *TI_receive_field = UCB0RXBUF;
117
      TI_receive_field++;
118
      byteCtr--;
119
    }
120
  }
121
  else 
122
  {
123
    if (byteCtr == 0)
124
    {
125
      UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
126
      IFG2 &= ~UCB0TXIFG;                     // Clear USCI_B0 TX int flag
127
    }
128
    else 
129
    {
130
      UCB0TXBUF = *TI_transmit_field;
131
      TI_transmit_field++;
132
      byteCtr--;
133
    }
134
  }
135
}

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Marc schrieb:
> Ich habe versucht, die TI_USCI_I2C_master.h/TI_USCI_I2C_master.h.c zu
> verwenden

Woher kommen die?

Die USCI ist bei den verschiedenen MSP430-Varianten manchmal ziemlich 
unterschiedlich, insbesondere das Interrupthandling ist beim 'G2553 sehr 
anders als bei größeren MSP430-Modellen mit vermeintlich ähnlicher 
Peripherie, da die Interruptvektoren anders belegt sind.

von Johannes R. (jr17oo)


Lesenswert?

Hallo Marc,

da scheint ein Fehler in der TI_USCI_I2C_transmitinit() zu sein. Die 
I2C-Pins werden nicht ordentlich initialisiert. Neben P1SEL muss man 
auch P1SEL2 setzen:
1
  P1SEL |= SDA_PIN + SCL_PIN;
2
  P1SEL2 |= SDA_PIN + SCL_PIN;

Außerdem würde ich empfehlen die Clocks sauber zu konfigurieren. I2C 
nutzt die SMCLK (dividiert durch den angegeben Prescaler). Laut 
Datenblatt sollte dein Sensor mit 50 kHZ funktionieren. Und die 
Endlosschleife brauchst du eigentlich auch nicht. Dein erstes Beispiel 
sähe dann so aus:
1
void main(void) {
2
    WDTCTL = WDTPW + WDTHOLD;   // Stop WDT
3
4
    DCOCTL = CALDCO_1MHZ;       // DCOCLK = 1MHz
5
    BCSCTL1 = CALBC1_1MHZ;
6
    BCSCTL2 = DIVS_1;           // MCLK = DCOCLK, SMCLK = DCOCLK/2
7
8
    P1DIR |= BIT0;              // P1.0 set as output
9
    P1OUT &= ~(BIT0);           // P1.0 set low
10
11
    TI_USCI_I2C_transmitinit(0x28, 0x0A);
12
13
    if (TI_USCI_I2C_slave_present(0x28)) {
14
        P1OUT |= BIT0;          // LED on
15
    } else  {
16
        P1OUT &= ~(BIT0);       // LED off
17
    }
18
    LPM4;
19
}

von Marc (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Marc schrieb:
>> Ich habe versucht, die TI_USCI_I2C_master.h/TI_USCI_I2C_master.h.c zu
>> verwenden
>
> Woher kommen die?

Die habe ich von TI: http://www.ti.com/lit/an/slaa382a/slaa382a.pdf
Wusste nicht, dass es sowas gibt, bis ich zufällig hier im Forum darauf 
gestoßen bin.

Rufus Τ. F. schrieb:
> Die USCI ist bei den verschiedenen MSP430-Varianten manchmal ziemlich
> unterschiedlich, insbesondere das Interrupthandling ist beim 'G2553 sehr
> anders als bei größeren MSP430-Modellen mit vermeintlich ähnlicher
> Peripherie, da die Interruptvektoren anders belegt sind.

Ah danke für den Hinweis, dann muss ich da mal genauer rein schauen, 
allerdings hatte ich für die erste Version ja eine while(1) Schleife 
statt Interrupts.

Johannes R. schrieb:
> Außerdem würde ich empfehlen die Clocks sauber zu konfigurieren. I2C
> nutzt die SMCLK (dividiert durch den angegeben Prescaler). Laut
> Datenblatt sollte dein Sensor mit 50 kHZ funktionieren. Und die
> Endlosschleife brauchst du eigentlich auch nicht. Dein erstes Beispiel
> sähe dann so aus:

Oh das klingt sehr vielversprechend, ich melde mich sofort wenn ich es 
getestet habe :)

Vielen Dank!

von Marc (Gast)


Lesenswert?

Hey danke, hat geklappt. Jetzt gebe ich mich mal an die Druckmessung :)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.