mbed pin declaration problem

24 Mar 2010

I was trying to put all the pin declaration in one header file, so the source files just need to include it. However, it turns out if I include more than once of that header file, the compiler is complaining that I declare the pin more than once. Some thing like "Multiple pin declaration found in ??.cpp and ???.cpp". Then I try divided the pin declaration to specific source files, it works. But that would mean I can use only that certain pin in that certain source file, since header file method doesn't work, and I can declare it twice( compiler wouldn't let me). It is quite painful, when come to bebugging using USBTX and USBRX to print, and a lot other inconvinence. I hope you guys can make the header file method work, since I am really just declaring it once, and include it in other files...

 

Mahalo

Let me know how it goes ;)

24 Mar 2010 . Edited: 24 Mar 2010

Hi Mahalo,

Take a look at the following forum post:

This should help demonstrate it. The compiler is working fine, but C requires you to jump through a few hoops if you want to be able to access a global variable from multiple files.

btw, an really cut down example using no header files at all (not recommended, but to demonstrate the behaviour) would be:

main.cpp

#include "mbed.h"

DigitalOut myled(LED1);

extern void foo();

int main() {
    while(1) {
        myled = 1;
        wait(0.2);
        foo();
        wait(0.2);
    }
}

foo.cpp

#include "mbed.h"

extern DigitalOut myled;

void foo() {
    myled = 0;
}

The extern keyword basically means "declare without defining", so tells the compiler it exists, but will be defined elsewhere.

Please say if this answers your question or not.

Simon

24 Mar 2010

The problem is that you're probably defining pins in the headers, not just declaring.

Try like this:

pins.h: (just declarations)

#include "mbed.h"

extern DigitalIn mypin1;
extern DigitalIn mypin2;
extern DigitalIn mypin3;

pins.cpp: (definitions)

#include "pins.h"

DigitalIn mypin1(p5);
DigitalIn mypin2(p6);
DigitalIn mypin3(p7);

Now you can include pins.h in other files and you'll still have only one DigitalIn instance for each pin.

24 Mar 2010

Much nicer example; thanks Igor!

24 Aug 2011

I've got a key_reader class that sets a DigitalIn's mode in the constructor (to PullUp). Later on, I'd like to read the value of that pin, in another member function. At first, I tried:

Constructor:
myclass::myclass(PinName whichpin){
  DigitalIn this_pin(whichpin);
  this_pin.mode(PullUp);
  _whichpin = whichpin;
}

Accessor:
myclass:bool get_value(){
   DigitalIn this_pin(_whichpin); // I don't have a handle to the Digital In, but I do have it's pin name
   this_pin.mode(PullUp);         // The constructor for DigitalIn defaults to PullDown, which I don't want
   return this_pin.read();
}

Unfortunately, as you can imagine from the comments above, I sometimes get spurious low-reads on the accessor, as unless I've got some capacitance (not much - a long wire works) on the pin, the default constructor called as part of the accessor sets it to pull down, and it doesn't have time to pull back up again before the read. I can't afford a "wait" delay or anything, so I'd like to find a way to better store a handle to the DigitalIn object, so as to avoid calling the constructor a second time. My first thought is to create a private member variable "DigitalIn * _din_handle", and set it in the constructor to point at the DigitalIn, as follows:

Constructor:
myclass::myclass(PinName whichpin){
  DigitalIn this_pin(whichpin);
  this_pin.mode(PullUp);
  _din_handle = &this_pin;
  _whichpin = whichpin;
}

The problem is that the programmer in me knows that the DigitalIn should be officially created on the stack as a temporary object inside of the constructor, and as such, when I leave the constructor, that _din_handle pointer should (and will) be pointing into no-man's land.

I could consider putting all DigitalIn's into some sort of external file, but the whole point of the class is to be able to create and destroy key_readers on various pins as needed, so just making a hard coded list doesn't seem pleasant either.

Is there

  • A better way to code this?
  • A way to avoid the default constructor on DigitalIn, setting it to PullDown?
  • A safe means of creating handles or pointers to DigitalIn objects that I'm missing?

I'm naturally a C programmer, rather than C++, so if there's some obvious trick, feel free to point it out - I may be missing a feature of C++.

24 Aug 2011

Hi Greg, I use the code below and think a modified version of this should work for you. Whatever settings you make on the _RD, _WR pin in _init() should be retained. Use member functions to access the protected (pins) _RD or _WR. (Sorry about the ugly layout, no idea why i get this when pasting code...)

BusEnums.h: ----- /* BusEnums - Use the MBED Port pins for controlling the Bus

  1. ifndef _BUS_ENUMS_H
  2. define _BUS_ENUMS_H

Enums for Control Bus and Enable Bus

enum Bit_Level { LOW, HIGH };

  1. endif

MBED_ControlBus.h: -------

  1. ifndef _MBED_CONTROLBUS_H
  2. define _MBED_CONTROLBUS_H

Enums for Control Bus

  1. include "BusEnums.h"

/ Create an MBED_ControlBus object connected to the specified Pins

  • @param PinName WR the Write pin
  • @param PinName RD the Read pin
  • /

class MBED_ControlBus {

public:

MBED_ControlBus(PinName WR, PinName RD);

void WR (Bit_Level wr_level);

void RD (Bit_Level rd_level);

protected:

DigitalOut _WR; Write pin

DigitalOut _RD; Read pin

void _init();

};

  1. endif

MBED_ControlBus.cpp: -------

/* MBED_ControlBus - Use MBED Port Pins for controlling the external Bus

  1. include "mbed.h"
  2. include "MBED_ControlBus.h"

/ Create an MBED_ControlBus object connected to the specified Pins

  • @param PinName WR the Write pin
  • @param PinName RD the Read pin
  • / MBED_ControlBus::MBED_ControlBus(PinName WR, PinName RD) :

_WR(WR), WR pin

_RD(RD) { RD pin

_init();

}

/ Set or Clear the WR pin on Control Bus

  • @param Bit_Level wr_level
  • / void MBED_ControlBus::WR (Bit_Level wr_level) {

if (wr_level == LOW) { _RD = 1; RD Pin High, make sure there is no collision _WR = 0; WR Pin Low } else { _WR = 1; WR Pin High } }

/ Set or Clear the RD pin on Control Bus

  • @param Bit_Level rd_level
  • /

void MBED_ControlBus::RD (Bit_Level rd_level) {

if (rd_level == LOW) { _WR = 1; WR Pin High, make sure there is no collision _RD = 0; RD Pin Low } else { _RD = 1; RD Pin High } }

/ Init MBED_ControlBus

  • @param
  • @returns
  • /

void MBED_ControlBus::_init() { Make sure that all Control pins are disabled

_RD = 1; RD Pin High

_WR = 1; WR Pin High

}

main.cpp: -------

  1. include "MBED_ControlBus.h"

MBED_ControlBus controlbus = MBED_ControlBus(p23, p24);

int main() {

controlbus.RD(LOW);

wait(1);

controlbus.RD(HIGH); }

24 Aug 2011

You know you've been writing embedded high-reliability C for too long when you literally forget the existence of malloc, and it's younger sibling, new. A quick

DigitalIn * _din; // create a private member of the class
_din = new DigitalIn(_pinName); // set it up in the default constructor
_din->mode(PullUp); // also in the constructor
_din->read(); // called later to access it

in the right places fixed it right up. Oh what a shower reminds one of. As long as I don't call and release too much, I won't run out of RAM or risk fragmentation, and initial testing shows it's fine, so I'm leaving this in case anyone else ever needs a good swift kick in the head. (Or in case what I've done is dangerous from an MBed standpoint).