Show Posts
Pages: 1 [2] 3 4 ... 10
16  Forum 2005-2010 (read only) / Bugs & Suggestions / Re: found bug in Serial.available() on: January 09, 2007, 01:44:18 pm
Hey Mellis,

Thanks!

By the way, just wondering if you have seen the latest version of the library patch I did in the playground?  I was able to get rid of the link_order file that neither of us liked... didn't hear back from you after that change, so I just figured you have been pretty busy.  I'm excited about the possibility for my first time of seeing my small contribution show up in an open-source project, so please forgive me for pestering!  smiley  Also just want to make sure there are no roadblocks to prevent it from being included.  Looks like I might have someone help me figure out the problem with makefile build:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1168127321
17  Forum 2005-2010 (read only) / Bugs & Suggestions / found bug in Serial.available() on: January 08, 2007, 09:26:48 pm
I was looking at some of the code in the Arduino runtime library today, and I saw something that looked a bit fishy to me.  In the following code, it occurred to me that there could be a bug when rx_buffer_head wraps around from 127 back to 0:

Code:
int serialAvailable()
{
    return (rx_buffer_head - rx_buffer_tail) % RX_BUFFER_SIZE;
}

In that case, it occurred to me that you could have rx_buffer_head==0, and rx_buffer_tail==127.  Then serialAvailable() would return (0 - 127) % 128 == -127.  Or at least, that's the mod operator works on most computers I am used to.  

So I decided to test this out with a program before making a fool of myself!  smiley  I wrote the following code and ran it.

Code:
extern volatile int rx_buffer_head, rx_buffer_tail;

void setup()
{
    Serial.begin (9600);
}

void loop()
{
    cli();      // disable interrupts, to make absolutely sure we get consistent numbers
    int avail = Serial.available();
    int head  = rx_buffer_head;
    int tail  = rx_buffer_tail;
    sei();      // enable interrupts again

    if (avail) {
        Serial.print (" h=");
        Serial.print (head);
        Serial.print (" t=");
        Serial.print (tail);
        Serial.print (" a=");
        Serial.print (avail);
        Serial.println();

        Serial.read();  // read and discard one byte
    }
}

While running this code, I kept sending the Arduino board one character at a time over the serial port.  Here is the output, with a lot of unnecessary lines removed:

Code:

 h=1 t=0 a=1            
 h=2 t=1 a=1            
 h=3 t=2 a=1            
 h=4 t=3 a=1            
 h=5 t=4 a=1            
 h=6 t=5 a=1            
 h=7 t=6 a=1            
 h=8 t=7 a=1            
 h=9 t=8 a=1            
 h=10 t=9 a=1            
 h=11 t=10 a=1              
 h=12 t=11 a=1              
// ... over 100 lines deleted for brevity's sake ...
 h=122 t=121 a=1
 h=123 t=122 a=1
 h=124 t=123 a=1
 h=125 t=124 a=1
 h=126 t=125 a=1
 h=127 t=126 a=1
 h=0 t=127 a=129      // <=== *** RED ALERT ***  should have said a=1
 h=1 t=0 a=1
 h=2 t=1 a=1
 h=3 t=2 a=1
 h=4 t=3 a=1
 h=5 t=4 a=1
 h=6 t=5 a=1
 h=7 t=6 a=1
 h=8 t=7 a=1

As predicted, you get the wrong value returned by serialAvailable() whenever rx_buffer_head < rx_buffer_tail.  The reason it wasn't negative is because I am calling Serial.available(), which calls serialAvailable(), then typecasts the negative value to an unsigned byte.

To fix this problem, the function serialAvailable needs to be modified as follows:

Code:
int serialAvailable()
{
    return (RX_BUFFER_SIZE + rx_buffer_head - rx_buffer_tail) % RX_BUFFER_SIZE;
}

After applying this fix and running again, now I see correct behavior:

Code:
// ... blah blah blah
 h=124 t=123 a=1
 h=125 t=124 a=1
 h=126 t=125 a=1
 h=127 t=126 a=1
 h=0 t=127 a=1      // <===  Yes!  It works!
 h=1 t=0 a=1
 h=2 t=1 a=1
 h=3 t=2 a=1

I just thought I would mention this so that
  • It could be fixed for Arduino 0008.
  • People could edit their own copy of Arduino 0007 and fix it themselves, or
  • They could be very careful calling Serial.available(), knowing it can return incorrect values.
18  Forum 2005-2010 (read only) / Syntax & Programs / Re: Making Stopwatch with Pushbutton & millis() on: December 08, 2006, 04:01:14 pm
Hmmm... I'm staring at this code, and I don't see why it would print continuously.
I do see some things you might want to change.  The lines

     StartTime = int(millis());
      EndTime = int(millis());

should be:

     StartTime = millis();
      EndTime = millis();

because otherwise you are chopping off the high 2 bytes of the return value of millis().
To be completely correct, you should change the declarations of these variables to the following, because millis() returns unsigned long:

   unsigned long StartTime = 0;
   unsigned long EndTime = 0;

But none of this explains why you would be seeing continuous output, even when you are not pressing the button.  Maybe you should try adding more debug prints to see where exactly the problem is.  There are some simplifications to the logic you could make also.  Here would be my idea of how to change the loop() function to see what is going on.  Note that I'm using an if/else instead of two ifs with gotos.  But more importantly, I have added extra prints of strings "PUSH:" and "RELEASE:" so you can tell which part of the code is running when you don't expect it to.

void loop()
{
    Btn1Val = digitalRead(Btn1Pin);

    if (Btn1Val == LOW) {//IF BUTTON = PUSH
        if (Temp == 0) {
            Temp = 1;
            StartTime = millis();
            Serial.print("PUSH: ");
            Serial.println(StartTime);
            //digitalWrite(ledPin, HIGH);

        }
    } else {
        //IF BUTTON=RELEASED
        if (Temp == 1) {
            Temp = 0;
            EndTime = millis();  
            Serial.print("RELEASE: ");
            Serial.println(EndTime - StartTime);
            //digitalWrite(ledPin, LOW);
        }
    }
}


Hope this helps!

- Don
19  Forum 2005-2010 (read only) / Syntax & Programs / Re: C++ problem with pure virtual method on: January 01, 2007, 12:32:29 pm
As a follow-up, I found a workaround:  I modified class DebouncedButton and replaced the following lines:

Code:
   virtual bool isButtonPressed() = 0;     // derived class defines what it means for noisy button to be pressed
    virtual void onPress() = 0;             // action to take when debouncer says button is pressed
    virtual void onRelease() = 0;           // action to take when debouncer says button is realeased

with these lines:

Code:
   virtual bool isButtonPressed()     // derived class defines what it means for noisy button to be pressed
    {
        return false;
    }

    virtual void onPress()             // action to take when debouncer says button is pressed
    {
    }

    virtual void onRelease()           // action to take when debouncer says button is realeased
    {
    }

The compiler no longer complains, and as a bonus, when I upload and run the sketch, it actually works!  So I can tell that my derived class methods are being called, not the base class, as is supposed to be the case.  Weird...
20  Forum 2005-2010 (read only) / Syntax & Programs / C++ problem with pure virtual method on: January 01, 2007, 12:21:15 pm
I am a fairly experienced C++ programmer, but this has me stumped.  I am trying to make a generic class for button debouncing, and then derive from that a class specific to an analog touch sensor I made.  But when my base class DebouncedButton tries to call a pure virtual method isButtonPressed(), the compiler barks at me like an angry German Shepherd:
 
o: In function `DebouncedButton::update()':
undefined reference to `__cxa_pure_virtual'
 
The line of code it does not like is marked with "//!!!!!" below.  Am I doing something wrong, or does this compiler not support pure virtual methods?
 
Code:
/*
    touch_sensor.pde  -  Don Cross  -  http://cosinekitty.com
    
    Experiment with interfacing darlington-pair touch sensor to analog input on atmega8.
*/

//-------------------------------------------------------------------------------------------------

class DebouncedButton {
public:
    DebouncedButton (unsigned _debounceTimeInMilliseconds):
        stableButtonState (false),  // assume button starts out released
        debounceTimeInMilliseconds (_debounceTimeInMilliseconds)
    {
    }

    void update()
    {
        // Check current sensor reading...
        bool sample = isButtonPressed();      //!!!!!
        unsigned long now = millis();

        // Is the current state different from the last stable state?
        if (sample == stableButtonState) {
            // might still be bouncing around, so restart debounce timer
            lastBounceTime = now;
        } else {
            unsigned long elapsed = now - lastBounceTime;
            if (elapsed > debounceTimeInMilliseconds) {
                // the state has changed, and appears stable, so toggle the state now...
                stableButtonState = sample;
                if (stableButtonState) {
                    onPress();
                } else {
                    onRelease();
                }
            }
        }
    }

    virtual bool isButtonPressed() = 0;     // derived class defines what it means for noisy button to be pressed
    virtual void onPress() = 0;             // action to take when debouncer says button is pressed
    virtual void onRelease() = 0;           // action to take when debouncer says button is realeased

private:
    bool            stableButtonState;      // false=button released, true=button pressed
    unsigned long   lastBounceTime;
    unsigned        debounceTimeInMilliseconds;
};


//-------------------------------------------------------------------------------------------------


const int TOUCH_THRESHOLD = 500;
class AnalogTouchSensor: public DebouncedButton {
public:
    AnalogTouchSensor (byte _analogInputPin, byte _digitalOutputPin):
        DebouncedButton (10),        // pass debounce time in milliseconds to DebouncedButton class
        analogInputPin (_analogInputPin),
        digitalOutputPin (_digitalOutputPin),
        digitalOutputState (false)
    {
        pinMode (digitalOutputPin, OUTPUT);
    }

    virtual bool isButtonPressed()
    {
        return analogRead(analogInputPin) < TOUCH_THRESHOLD;
    }

    virtual void onPress()
    {
        digitalOutputState = !digitalOutputState;
        digitalWrite (digitalOutputPin, digitalOutputState);
    }

    virtual void onRelease()
    {
        // do nothing
    }

private:
    byte    analogInputPin;
    byte    digitalOutputPin;
    byte    digitalOutputState;
};


//-------------------------------------------------------------------------------------------------


AnalogTouchSensor sensor(5, 13);     // monitor analog pin 5, toggle LED on pin 13


void setup()
{
}

void loop()
{
    sensor.update();
}

//-------------------------------------------------------------------------------------------------

/*
    $Log: touch_sensor.pde,v $
    Revision 1.1  2007/01/01 02:30:14  dcross
    Almost works, but needs debounce.

*/
21  Forum 2005-2010 (read only) / Syntax & Programs / Re: using math.h library (sin/cos/acos...) on: December 10, 2006, 05:56:25 pm
Hello missmoun,

When I read that you are doing this for a wearable device, and that you are processing GPS data to find the distance between two points on the Earth, does that mean that the two points are likely to be very close together?  For example, if you are trying to figure out the distance around the Earth from Japan to England, you definitely need some complicated formulas.  On the other hand, if you just want the distance between two points that are very close together (like a few miles on a sphere the size of the Earth), you can greatly simplify things.  

For points very close together, the straight-line distance will be a very good approximation for the curvilinear distance across the ground.  We simplify by assuming that we can break down the distance into an east-west distance (delta_x) and north-south distance (delta_y).  

delta_x = cos((latitude1 + latitude2) / 2) * (longitude1 - longitude2) * earth_radius;
delta_y = (latitude1 - latitude2) * earth_radius;   // note that latitudes MUST be in radians!
approx_distance = sqrt (delta_x*delta_x + delta_y*delta_y);

This formula requires only one trig function: cosine.  If you are using this in a particular geographical area, you could do a really easy hack: just hard-code the value cos(your_latitude) into your program!  The formula for delta_x becomes:

delta_x = your_cosine_latitude * (longitude1 - longitude2) * earth_radius;

Then the only tricky math you have to do is sqrt, which is very easy to implement using divide-and-average.
22  Forum 2005-2010 (read only) / Syntax & Programs / Re: charlieplexing 72 LED's. Need help with code on: August 12, 2008, 10:42:10 am
Looks like a case-sensitivity issue in C++.  Try changing:

Code:
void light_cp_led(unsigned char N)

to

Code:
void light_cp_led(unsigned char n)
23  Forum 2005-2010 (read only) / Syntax & Programs / Re: Deferring SoftwareSerial object creation on: August 14, 2008, 06:50:21 am
Hi Mikal,

I tried your experiment and you are correct: the constructor is called for a global class instance.

I now know why my constructor did not work as expected.  It was because it does some digital output, but it does it before setup() was called, so the pins I was writing to have not yet been defined as output pins!  Silly me.   smiley

Thanks for clearing up the confusion...

Don
24  Forum 2005-2010 (read only) / Syntax & Programs / Re: Deferring SoftwareSerial object creation on: August 13, 2008, 09:27:30 am
Hi Galileo,

Yes, I too am a software engineer by day, working on much larger OOP-based systems.  However, in the microcontroller world, there is a lot to be said for predictability.  You have very little memory, very little debugging support, and there is not much recourse for failures like out-of-memory conditions.  I have found myself taking a somewhat balanced approach: I use C++ classes, but I avoid dynamic memory allocation.  I also have found that C++ constructors do not seem to get called for global instances of the class.  This just bit me as a matter of fact!  I had to replace the constructor with a goofy Initialize() method that gets called by the setup() function.

So I take advantage of OOP concepts like making things private inside a class, providing controlled public interfaces, but still use global variables for instances so I know exactly how much memory I am using.  If I need a dynamic buffer, I declare my own global array and use indexes into the array to implement a stack or a queue.  You can even create your own freelist to allocate for yourself, but you risk running out of resources at a critical time.  Of course, you can hide all of this inside a class, but I would still recommend making the instance of that class be a global variable.

In the case of the serial port, unless you write your own software serial driver (which has been done, though the timing constraints make it hard to do anything else useful at the same time), you don't have much choice about what pins are used for the serial port.  At least, this is the case on the ATMEGA8.  Maybe things are more flexible on the higher-end processors?

As another example of how my coding style has changed in the Arduino environment, I notice I no longer automatically use multi-byte data types like 'int', if it is at all possible to use 'char' instead.  I have found this saves a lot of program memory in addition to the obvious reduction in data memory.  This alone has made the difference in fitting a complex algorithm in the 7K I had available.

- Don
25  Forum 2005-2010 (read only) / Syntax & Programs / Re: Deferring SoftwareSerial object creation on: August 12, 2008, 11:01:23 am
Just curious... why do you need to "defer" creating the serial connection?  Maybe if we understood what the problem was, there would be another way to do what you want.

- Don
26  Forum 2005-2010 (read only) / Syntax & Programs / Re: Array on: August 12, 2008, 10:58:53 am
If you post your existing source code here, it may help people answer your question.

- Don
27  Forum 2005-2010 (read only) / Syntax & Programs / Re: Persistence Of Vision  (POV) software on: December 03, 2006, 01:36:22 pm
You could save a lot of space by changing the arrays from "int" (2 bytes) to "char" (1 byte):

static char _[] = {0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0};
// ... etc ...

You would not have to modify any of the rest of the code.

If you are more ambitious, you could replace each array with a single "int", because each value in the array is just a bit (either 0 or 1).  For example:

#define LETTER(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o)  \
    ((a)<<14|(b)<<13|(c)<<12|(d)<<11|(e)<<10|    \
    ((f)<<9|(g)<<8|(h)<<7|(i)<<6|(j)<<5|     \
    ((k)<<4|(l)<<3|(m)<<2|(n)<<1|(o))

Note the backslashes at the end of the first 3 lines, which allow the macro definition to span lines.

static int _ = LETTER(0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0);
static int A = LETTER(0,1,1,1,1, 1,0,1,0,0, 0,1,1,1,1);
// ... etc ...

Then, to access a particular bit within a letter, instead of accessing array
  • , you would retrieve a bit using the following macro:

#define GETBIT(variable,position)   (((variable) >> (15-position)) & 1)

For example, GETBIT(A,0) would access the leftmost bit in the variable A.

While this is a bit of work, it would shrink your data size by a factor of 16.  But of course this matters only if you intend to make the rest of the code more complex.
28  Forum 2005-2010 (read only) / Syntax & Programs / Re: need to reduce sketch size on: February 16, 2007, 09:42:57 am
If you are using Arduino 0007, I would recommend trying out the following library patch:

http://www.arduino.cc/playground/Code/LibPatch0007

You may be surprised at how much smaller your sketch will get!
29  Forum 2005-2010 (read only) / Syntax & Programs / Re: GICR |= (1<<INT0) on: February 11, 2007, 12:25:17 pm
Hello ccdust,

My guess is that you need to add this to the top of your source code:

Code:
#include <avr/pgmspace.h>
30  Forum 2005-2010 (read only) / Syntax & Programs / Re: GICR |= (1<<INT0) on: December 30, 2006, 03:18:23 pm
OK, I have started a new page in the Playground that expands upon this topic:

http://www.arduino.cc/playground/Code/BitMath

I am not finished yet; I want to write up a section at the end showing how to encode/decode multiple pieces of binary data inside bytes to save memory, but I have been writing for hours now and I need a break.

I would love it if everyone would take a look and let me know...

What is confusing?
What is helpful, or explained something you did not already know?
Are there other examples of weird bit-manipulations you have seen that you do not understand?
Are there any typos or mistakes?
Is this article formatted correctly on your browser? (I used Firefox v 2.0.0.1)

Thanks,

- Don
Pages: 1 [2] 3 4 ... 10