mikrocontroller.net

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


Autor: Marc (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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):
#include <msp430g2553.h> 
#include "TI_USCI_I2C_master.h"

void main1(void)
{
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    P1DIR  |= BIT0;          // P1.0 set as output
  P1OUT  &= ~(BIT0);        // P1.0 set low
    
    TI_USCI_I2C_transmitinit(0x28,0x3f);

    while(1)
    {
        if(TI_USCI_I2C_slave_present(0x28))   // check for slave
        {
            P1OUT |= BIT0;
        }
        else
        {
            P1OUT &= ~(BIT0);
        }
    }
}

main.c (V2)
#include <msp430g2553.h> 
#include "TI_USCI_I2C_master.h"

unsigned char array[5] = { 0, 0, 0, 0, 0 };

void main(void)
{
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    
    _EINT(); // enable interrupts
    
    TI_USCI_I2C_receiveinit(0x28,0x3f); // initialize USCI and DMA module
    
    while ( TI_USCI_I2C_notready() ); // wait for bus to be free
    
    TI_USCI_I2C_receive(3,array); // receive the first 3 bytes of array
    
    LPM0; // put CPU to sleep during communication
}

TI_USCI_I2C_master.h:
#ifndef USCI_LIB
#define USCI_LIB

#define SDA_PIN BIT7
#define SCL_PIN BIT6

void TI_USCI_I2C_receiveinit(unsigned char slave_address, unsigned char prescale);
void TI_USCI_I2C_transmitinit(unsigned char slave_address, unsigned char prescale);

void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field);
void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field);

unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address);
unsigned char TI_USCI_I2C_notready();

#endif

TI_USCI_I2C_master.h.c:
#include "msp430g2553.h"                        // device specific header
#include "TI_USCI_I2C_master.h"

signed char byteCtr;
unsigned char *TI_receive_field;
unsigned char *TI_transmit_field;

void TI_USCI_I2C_receiveinit(unsigned char slave_address, unsigned char prescale)
{
  P1SEL |= SDA_PIN + SCL_PIN;                 // Assign I2C pins to USCI_B0   P3???
  UCB0CTL1 = UCSWRST;                         // Enable SW reset
  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;       // I2C Master, synchronous mode
  UCB0CTL1 = UCSSEL_2 + UCSWRST;              // Use SMCLK, keep SW reset
  UCB0BR0 = prescale;                         // set prescaler
  UCB0BR1 = 0;
  UCB0I2CSA = slave_address;                  // set slave address
  UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
  UCB0I2CIE = UCNACKIE;
  IE2 = UCB0RXIE;                             // Enable RX interrupt
}
 
void TI_USCI_I2C_transmitinit(unsigned char slave_address, unsigned char prescale)
{
  P1SEL |= SDA_PIN + SCL_PIN;                 // Assign I2C pins to USCI_B0 P3???
  UCB0CTL1 = UCSWRST;                         // Enable SW reset
  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;       // I2C Master, synchronous mode
  UCB0CTL1 = UCSSEL_2 + UCSWRST;              // Use SMCLK, keep SW reset
  UCB0BR0 = prescale;                         // set prescaler
  UCB0BR1 = 0;
  UCB0I2CSA = slave_address;                  // Set slave address
  UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
  UCB0I2CIE = UCNACKIE;
  IE2 = UCB0TXIE;                             // Enable TX ready interrupt
}

void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field)
{
  TI_receive_field = field;
  if ( byteCount == 1 )
  {
    byteCtr = 0 ;
    __disable_interrupt();
    UCB0CTL1 |= UCTXSTT;                      // I2C start condition
    while (UCB0CTL1 & UCTXSTT);               // Start condition sent?
    UCB0CTL1 |= UCTXSTP;                      // I2C stop condition
    __enable_interrupt();
  } 
  else if ( byteCount > 1 ) 
  {
    byteCtr = byteCount - 2 ;
    UCB0CTL1 |= UCTXSTT;                      // I2C start condition
  } 
  else
    while (1);                                // illegal parameter
}

void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field)
{
  TI_transmit_field = field;
  byteCtr = byteCount;
  UCB0CTL1 |= UCTR + UCTXSTT;                 // I2C TX, start condition
}

unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address)
{
  unsigned char ie2_bak, slaveadr_bak, ucb0i2cie, returnValue;
  ucb0i2cie = UCB0I2CIE;                      // restore old UCB0I2CIE
  ie2_bak = IE2;                              // store IE2 register
  slaveadr_bak = UCB0I2CSA;                   // store old slave address
  UCB0I2CIE &= ~ UCNACKIE;                    // no NACK interrupt
  UCB0I2CSA = slave_address;                  // set slave address
  IE2 &= ~(UCB0TXIE + UCB0RXIE);              // no RX or TX interrupts
  __disable_interrupt();
  UCB0CTL1 |= UCTR + UCTXSTT + UCTXSTP;       // I2C TX, start condition
  while (UCB0CTL1 & UCTXSTP);                 // wait for STOP condition
  
  returnValue = !(UCB0STAT & UCNACKIFG);
  __enable_interrupt();
  IE2 = ie2_bak;                              // restore IE2
  UCB0I2CSA = slaveadr_bak;                   // restore old slave address
  UCB0I2CIE = ucb0i2cie;                      // restore old UCB0CTL1
  return returnValue;                         // return whether or not 
                                              // a NACK occured
}

unsigned char TI_USCI_I2C_notready()
{
  return (UCB0STAT & UCBBUSY);
}


#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR(void)
{
  if (UCB0STAT & UCNACKIFG)
  {            // send STOP if slave sends NACK
    UCB0CTL1 |= UCTXSTP;
    UCB0STAT &= ~UCNACKIFG;
  }
}


#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
  if (IFG2 & UCB0RXIFG)
  {
    if ( byteCtr == 0 )
    {
      UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
      *TI_receive_field = UCB0RXBUF;
      TI_receive_field++;
    }
    else 
    {
      *TI_receive_field = UCB0RXBUF;
      TI_receive_field++;
      byteCtr--;
    }
  }
  else 
  {
    if (byteCtr == 0)
    {
      UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
      IFG2 &= ~UCB0TXIFG;                     // Clear USCI_B0 TX int flag
    }
    else 
    {
      UCB0TXBUF = *TI_transmit_field;
      TI_transmit_field++;
      byteCtr--;
    }
  }
}

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Johannes R. (jr17oo)
Datum:

Bewertung
0 lesenswert
nicht 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:
  P1SEL |= SDA_PIN + SCL_PIN;
  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:
void main(void) {
    WDTCTL = WDTPW + WDTHOLD;   // Stop WDT

    DCOCTL = CALDCO_1MHZ;       // DCOCLK = 1MHz
    BCSCTL1 = CALBC1_1MHZ;
    BCSCTL2 = DIVS_1;           // MCLK = DCOCLK, SMCLK = DCOCLK/2

    P1DIR |= BIT0;              // P1.0 set as output
    P1OUT &= ~(BIT0);           // P1.0 set low

    TI_USCI_I2C_transmitinit(0x28, 0x0A);

    if (TI_USCI_I2C_slave_present(0x28)) {
        P1OUT |= BIT0;          // LED on
    } else  {
        P1OUT &= ~(BIT0);       // LED off
    }
    LPM4;
}

Autor: Marc (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Marc (Gast)
Datum:

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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.