Arduino Forum

Using Arduino => LEDs and Multiplexing => Topic started by: Techone on Mar 30, 2012, 04:29 pm

Title: Making a calculator using an Arduino
Post by: Techone on Mar 30, 2012, 04:29 pm
Hi guys;

As the title said, I am trying to do a programing exersise to make a basic calculator using a telephone keypad and 8 7 segments display. 

Here what I am planning to do :

Enter a number, add it, and sum it. Easy to say, but no so easy to be done.

I will be learning to do a program do do just that.  I know, it all depend of  the type of hardware. 

I did the display and the keypad circuit. I did a test program for the display and the keypad to see if it is working.

The display : Use MAX7219 to display the 8 7 segments display. The display is a CC type. Test code will be in the next post.
The keypad : A telephone keypad, with a commun connection, <-- A Row will indicated a LOW at the location of that row being press, same thing goes for the colum. I made an interrupt pulse - HIGH for any key press. If I need that pusle. A test code will be in the next post.

Next, it is to combine them and code it.

Any help, some codes, pseudo-code is very welcome. I will try to do mine version, and figure this out. Any ideas of coding this project will be nice.


Title: Re: Making a calculator using an Arduino
Post by: Techone on Mar 30, 2012, 04:36 pm
Here a picture of the display and the test code. For the new guys or to the one who are not familiar with the MAX7219. This info came from the datasheet. http://www.datasheetcatalog.org/datasheet/maxim/MAX7219-MAX7221.pdf (http://www.datasheetcatalog.org/datasheet/maxim/MAX7219-MAX7221.pdf)

Code: [Select]


const byte datapin = 12;
const byte latchpin = 11;
const byte clockpin = 10;

void setup()
{
pinMode(datapin, OUTPUT);
pinMode(latchpin, OUTPUT);
pinMode(clockpin, OUTPUT);
// set : Normal Mode
digitalWrite(latchpin, LOW);
shiftOut(datapin, clockpin, MSBFIRST, 0x0C );
shiftOut(datapin, clockpin, MSBFIRST, 0x01 );
digitalWrite(latchpin, HIGH);
delay(5);
// set : Normal Operation
digitalWrite(latchpin, LOW);
shiftOut(datapin, clockpin, MSBFIRST, 0x0F );
shiftOut(datapin, clockpin, MSBFIRST, 0x00 );
digitalWrite(latchpin, HIGH);
delay(5);
// set : Intensity
digitalWrite(latchpin, LOW);
shiftOut(datapin, clockpin, MSBFIRST, 0x0A );
shiftOut(datapin, clockpin, MSBFIRST, 0x0B );
digitalWrite(latchpin, HIGH);
delay(5);
// set : Numbers of digits
digitalWrite(latchpin, LOW);
shiftOut(datapin, clockpin, MSBFIRST, 0x0B );
shiftOut(datapin, clockpin, MSBFIRST, 0x07 );
digitalWrite(latchpin, HIGH);
delay(5);
// set : Decode Mode Register
digitalWrite(latchpin, LOW);
shiftOut(datapin, clockpin, MSBFIRST, 0x09 );
shiftOut(datapin, clockpin, MSBFIRST, 0xFF );
digitalWrite(latchpin, HIGH);
}

void loop()
{
byte j;

for (int i=1;i<9;i++)
{
   digitalWrite(latchpin, LOW);
   shiftOut(datapin, clockpin, MSBFIRST, i );
   shiftOut(datapin, clockpin, MSBFIRST, i );
   digitalWrite(latchpin, HIGH);
   delay(5);
}
delay(2000);
j = 8;
for (int i=1;i<9;i++)
{
   digitalWrite(latchpin, LOW);
   shiftOut(datapin, clockpin, MSBFIRST, i );
   shiftOut(datapin, clockpin, MSBFIRST, j );
   digitalWrite(latchpin, HIGH);
   delay(5);
   j--;
}
delay(2000);

Title: Re: Making a calculator using an Arduino
Post by: Techone on Mar 30, 2012, 04:39 pm
Here a picture of the keypad and the test code.

Code: [Select]


//**************************************************************//
//  Name    : shiftIn Example 1.1                              //
//  Author  : Carlyn Maw                                        //
//  Date    : 25 Jan, 2007                                      //
//  Version : 1.0                                               //
//  Notes   : Code for using a CD4021B Shift Register    //
//          :                                                   //
//****************************************************************
// Modify code by Techone from the original
// This code is just an example of using a telephone keypad
// with the use of 4021 and using shiftIn() function.
// Use only shiftIn () function
/*
    --------------
     1      2    3  <-- Row 1 
     4      5    6  <-- Row 2
     7      8    9  <-- Row 3
     *      0    #  <-- Row 4
     -------------
    /\     /\   /\
     |     |     |
    Col 1 Col 2 Col 3
   
   Telephone keypad pinouts
   
   gnd, col 2, col 1, row 4, col 3, row 3, row 2, row 1
   4021 connection :
   
   gnd   : pin 1
   col 1 : pin 15
   col 2 : pin 14
   col 3 : pin 13
   row 1 : pin 4
   row 2 : pin 5
   row 3 : pin 6
   row 4 : pin 7
     
   All keypad pins are with a 1 K pull-up resistor.
   
   All keypad outputs goes to a 74LS04 to be inverted.
   At outputs of the 74LS04 going into the 4021, place a
   pull-up resistor of 4.7 K. It is for TTL --> CMOS
   
   And connected all row output to a 74LS20 for
   a interrupt signal output or any keypress output signal.
   Work like : 0 - no ley
               1 - a key is being press
     
   Tigh Serial In - pin 11 to gnd.
   
   Therefore the outputs bits are : R4-R3-R2-R1-C3-C2-C1
       
   Button = 1 = 0b00001001 = 0x09 = 9
   Button = 2 = 0b00001010 = 0x0A = 10
   Button = 3 = 0b00001100 = 0x0C = 12
   Button = 4 = 0b00010001 = 0x11 = 17
   Button = 5 = 0b00010010 = 0x12 = 18
   Button = 6 = 0b00010100 = 0x14 = 20
   Button = 7 = 0b00100001 = 0x21 = 33
   Button = 8 = 0b00100010 = 0x22 = 34
   Button = 9 = 0b00100100 = 0x24 = 36
   Button = * = 0b01000001 = 0x41 = 65
   Button = 0 = 0b01000010 = 0x42 = 66
   Button = # = 0b01000100 = 0x44 = 68
   Button = None press = 0b00000000 = 0x00 = 0
*/

//define where your pins are
int latchPin = 11;
int dataPin = 12;
int clockPin = 10;

//Define variables to hold the data
//for shift register.

byte switchVar;

void setup() {
  //start serial
  Serial.begin(9600);

  //define pin modes
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, INPUT);
 
}

void loop() {

  //Pulse the latch pin:
  //set it to 1 to collect parallel data
  digitalWrite(latchPin,HIGH);
  //set it to 1 to collect parallel data, wait
  delayMicroseconds(20);
  //set it to 0 to transmit data serially 
  digitalWrite(latchPin,LOW);

  //while the shift register is in serial mode
  //collect each shift register into a byte
  //the register attached to the chip comes in first
  switchVar = shiftIn(dataPin, clockPin,LSBFIRST);

  //Print out the results.
   
  Serial.print(switchVar, BIN);
  Serial.print("  ");
  Serial.print(switchVar, HEX);
  Serial.print("  ");
  Serial.println(switchVar, DEC);
 
//white space
Serial.println("-------------------");
//delay so all these print satements can keep up.
delay(1000);

}
Title: Re: Making a calculator using an Arduino
Post by: CrossRoads on Mar 30, 2012, 05:02 pm
I would suggest the <keypad.h> library for reading the key presses, works very well.
No external hardware needed, just 8 IO pins.
Title: Re: Making a calculator using an Arduino
Post by: Nishant_Sood on Mar 30, 2012, 06:48 pm
Hi TechOne, SO far so good things are working i think.
Where in you are seeking code help or input?
I think you yourself are working pretty fine!   :)
Title: Re: Making a calculator using an Arduino
Post by: graynomad on Mar 31, 2012, 01:18 am
@Techone

Did you find a cheap source for those displays or just pull it from an old calculator?

Looks like a fun project BTW.

______
Rob
Title: Re: Making a calculator using an Arduino
Post by: Techone on Mar 31, 2012, 03:56 am
@Graynomad

Quote
Did you find a cheap source for those displays or just pull it from an old calculator?


Old calculator ?  No   They are a 3 digit 7 segments display. I got them for $0.50 ca at Active Surplus. So I got myself a few of those.

It is a fun project. It just help me out to learn in programing, use a keypad and use a MAX7219.

@ CrossRoads

I agree with you. I did look into the keypad.h. I download the library. The small problem with this solution is : Use to many pins. So I was planing to use the 4021. I was planning to build a circuit for a 4 X 5 keypad matrix using the 4021. Beside a byte have 256 combinations. I also look into the use of the chip MAX1234, a touch pad / keypad encoder compatible with SPI <-- will work with shiftIn() too.  Datasheet site : http://datasheets.maxim-ic.com/en/ds/MAX1233-MAX1234.pdf (http://datasheets.maxim-ic.com/en/ds/MAX1233-MAX1234.pdf) I check Mouser.com if they have it, they do, but no DIP version. The chip is QFN. ... I got a little hope with this site. http://www.ezprototypes.com/index.php (http://www.ezprototypes.com/index.php) Click the Chips Adapters and Sockets.

@NI$HANT

Quote
Where in you are seeking code help or input?


Both. I am open mind about new code, new help or new ideas. This project is just some kind of "homework".

Updated :

I put the two circuit together. I did a code. It just simply "scroll" a number you press the keypad. When I press nothing, no movement, scrolling. I press a key, a number coresponding the key I press show up. The next key I press show up and place the last key next to it.<-- Shifting the number to the left.

So far, my code I have now, work just fine, but it is the keypad I have an issue with ( I think ) , during the serial monitor, the bits do not all show up. I press a key and a row bit show but no col bit, sometime it show, sometime it does not. Maybe the hex Inverter chip  - 74LS04 / 74LS14 maybe not right for the job. I do have in my parts bins a 4049, 74HC04 and 74HC14. I wil see if that will work. With the 4049, I have to re-wired the breadboard setup. I will try to wired directely the keypad to the 4021 chip, code the variable - keydata - invert the data so I can use the code almost as is. If that does not work to well , I will use a LM339 comparator and inverter chip. <-- I know, it is overkill.

Here the code I have so far.

Code: [Select]

// Keypad Serial pins
const byte latchkeypin = 10;
const byte datakeypin = 12;
const byte clockkeypin = 11;

// Display Serial pins
const byte datadisplaypin = 9;
const byte clockdisplaypin = 8;
const byte latchdisplaypin = 7;

// Anykey pin
const byte anykeypin = 2;

// MAX7419 init data
word initdata[5] = { 0x0C01, 0x0F00, 0x0A0B, 0x0B07, 0x09FF };

// Fill the Display array with a blank code
word display_data[8] = { 0x010F, 0x020F, 0x030F, 0x040F, 0x050F, 0x060F, 0x070F, 0x080F }; 

volatile boolean keystate;

byte keydata;
byte keynumber;
byte data_box;


void setup()
{
  //start serial
  Serial.begin(9600);

  //define the pins modes
  pinMode(latchkeypin, OUTPUT);
  pinMode(clockkeypin, OUTPUT);
  pinMode(datakeypin, INPUT);
  pinMode(datadisplaypin, OUTPUT);
  pinMode(clockdisplaypin, OUTPUT);
  pinMode(latchdisplaypin, OUTPUT);
  pinMode(anykeypin, INPUT);
  attachInterrupt(0,anykeypress,RISING);
 
  /* Init the MAX7419 : Normal Mode
                        Normal Operation
                        Setting the Intensity
                        Numbers of Digits being display
                        Set to Decode Mode
  */

  for (int i=0;i<5;i++)
  { 
     digitalWrite(latchdisplaypin, LOW);
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, highByte(initdata[i]));
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, lowByte(initdata[i]) );
     digitalWrite(latchdisplaypin, HIGH);
     delay(5);
  }
  // Blank the display
  display_the_numbers();
  keystate = 0;
  data_box = 1;


void loop()
{
  data_box = 1;
  while ( keystate == 0)
  {
     // wait for a key press
  }
  read_keypad();
  convert_the_keypad_data();
  if ( keynumber < 0x0A )
  {
     for (int i=7;i>0;i--)
     {
       display_data[i]=display_data[i-1];
       display_data[i] = word ( (i+1) , lowByte( display_data[i] ) );
     }
     
     display_data[0] = word ( 1, keynumber );
     data_box++;
  }
  display_the_numbers();
  keystate = 0; 
 
  //Print out the results.
   
    Serial.print(keydata, BIN);
    Serial.print("  ");
    Serial.print(keydata, HEX);
    Serial.print("  ");
    Serial.print(keynumber, HEX);
    Serial.print("  ");
    Serial.println(keydata, DEC);
 
//white space
//Serial.println("-------------------");
//delay so all these print satements can keep up.
    delay(1000);

//display_the_numbers();

}

void read_keypad()
{
  //Pulse the latch pin:
  //set it to 1 to collect parallel data
  digitalWrite(latchkeypin,HIGH);
  //set it to 1 to collect parallel data, wait
  delayMicroseconds(20);
  //set it to 0 to transmit data serially 
  digitalWrite(latchkeypin,LOW);

  //while the shift register is in serial mode
  //collect each shift register into a byte
  //the register attached to the chip comes in first
  keydata = shiftIn(datakeypin, clockkeypin,LSBFIRST); 
}

void convert_the_keypad_data()
{
  byte what_row;
 
  what_row = ( keydata >> 3) & 0x0F;
  switch ( what_row)
  {
    case 1:
           keynumber = ( ( keydata >> 1 ) & 0x03 ) + 1;
           break;
    case 2:
           keynumber = (( keydata >> 1 ) & 0x03 ) + 4;
           break;
    case 4:
           keynumber = (( keydata >> 1 ) & 0x03 ) + 7;
           break;
    case 8:
           special_key();
           break;   
  } 
 


void display_the_numbers()
{
   for (int i=0;i<8;i++)
   {
     digitalWrite(latchdisplaypin, LOW);
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, highByte(display_data[i]) );
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, lowByte(display_data[i]) );
     digitalWrite(latchdisplaypin, HIGH);
     delay(5);
   } 
}

void special_key()
{
   byte special_case;
   
   special_case = ( ( keydata >> 1) & 0x03 ) + 1;
   switch ( special_case )
   {
     case 1:
            keynumber = 0x0F;
            break;
     case 2:
            keynumber = 0x00;
            break;
     case 3:
            keynumber = 0x0C;
            break;
   }       
}

void anykeypress()
{
  keystate = 1;




Title: Re: Making a calculator using an Arduino
Post by: Nishant_Sood on Mar 31, 2012, 05:17 am
Quote
during the serial monitor, the bits do not all show up. I press a key and a row bit show but no col bit, sometime it show, sometime it does not.


Serial data is so undependable ,i recently had a lot lot problem grabbing the serial data in char arrays and putting them into strings then finally i tried using <Packets> and serial flush with serial debug statements then everything became very predictable and i was able to grab the data precisely from Serial buffer.
WHEN YOU say SOMETIME it SHOW SOMETIME it does not then it definitely points out to this same problem.
Title: Re: Making a calculator using an Arduino
Post by: Techone on Mar 31, 2012, 06:37 am
@NI$HANT
Quote
WHEN YOU say SOMETIME it SHOW SOMETIME it does not then it definitely points out to this same problem.


I was using the Serial.print() to see what data I have. I was monitoring the keyboard data.  I got monitor the bits - BIN , an hex value - HEX and the number I press - DEC.  The data in binary show me all the pins from the keypad. I was expecting this :

0b0000000 for no key press. When I press 1, the binary result is : 0b00001001 The rows bits are : 0 RRRR CCC R is a row bit. The col bits are : 0 RRRR CCC  C is the col bits.  So I expect a bit at the row and col when I press a key.  I only received this : 0b00001000 <-- that binary result. The interrupt pulse is activated. Because all the rows pins are connect to an 4 input NAND gate - 74LS20. So if I received no bits at : 00000 CCC <-- any of the C location, but a bit is activated in the 0 RRRR CCC  row location.

So I concluded that the keypad is a bit "bad" or not so conductive. I did try to change 74LS04 ---> 74LS14. Got worse, not better. Maybe TTL gate are more "picky" when I come to voltage input level. Come to think of it, when a key is press, the keyboard do not really make a proper "short" = 0 = LOW for the TTL gate, the voltage is not low enought to become a zero for the TTL gate is consern. I will try CMOS gate. They are less "picky" , but they are "picky" about static electricity. One tiny "zap" and it is "Bye-Bye chippo ... ".  If that solution is not working, the LM339 route. I will set to 2.5 V for reference.  Now that I call "overkill". I will need 2 chip of the LM339. I have those in my parts bins. And I know, a lost of breadboarding.   
Title: Re: Making a calculator using an Arduino
Post by: Nishant_Sood on Mar 31, 2012, 07:13 am
Quote
the Serial.print() to see what data I have


I think that is ok but sometimes we use flushing and Packets atleast at the end of the elements we are sending so as to make them land complete in the programme but nevermind as you are saying that the keypad isn't that much conductive.

Quote
And I know, a lost of breadboarding.


A a lots of BreadBoarding atleast its easier than the Solder breadboarding.
Title: Re: Making a calculator using an Arduino
Post by: Techone on Apr 01, 2012, 06:51 am
Updated :

I got the keyboard working better by using 74HC14. But a few "double entry" and a few "not reading right". In that case, I will use the LM339 to take care of the keypad "bad contact". Just a lots of breadboarding.

I just finish coding the calculator program. So far, The "Add" section is not working right. I may need some help. The rest is working fine. The "Clear" section is working fine. I will double check the "keynumber" section. Look it is working fine, but I will double check it.

I may re-code the "add" section. Instead of extracting the thousands, hundrens, tens, etc, and use a long variable, I will try the method use when we where in Grade 3. How to add a number.

Any help from you guys will be nice.

Here the Add section:

Code: [Select]

// Check for the "Add / Equal" button
   if ( ( keynumber == 0x0B ) && ( over_flow == 0) )
   {      
     the_number= 0;
     for (int i=0;i<8;i++)
     {
       temp_number = long(digit_number[i]) * power_of_ten[i];
       the_number = the_number + temp_number;      
     }  
     add_number = add_number + the_number;
     if (add_number <= 99999999)
     {
       for (int i=7;i>=0;i--)
       {
         digit_number[i] = byte(add_number / power_of_ten[i]);
         add_number = add_number - (long(digit_number[i]) * power_of_ten[i]);
         display_data[i] = word ( ( i + 1) , digit_number[i] );        
       }
       for (int i=7;i>0;i++)
       {
         if ( digit_number[i] == 0 )
         {
            display_data[i] = word ( ( i + 1 ), 0x0F );
         }
         else
         {
           break;
         }  
       }
       
       display_the_numbers();
       add_flag = 1;
       keystate = 0;
     }
     else
     {
       // Over Flow
       over_flow = 1;
       digit_number[0] = 0;
       display_data[0] = 0x010B;
       for ( int i=1;i<8;i++)
       {
          digit_number[i] = 0;
          display_data[i] = word( (i+1), 0x0F );              
       }      
       keystate = 0;      
       display_the_numbers();          
     }        

Title: Re: Making a calculator using an Arduino
Post by: Techone on Apr 01, 2012, 06:52 am
Here the complete code:

Code: [Select]


/*
   size : 3118 bytes
   
   Calculator Version 1.0
   
   Just add a number enter by the keypad and display it.
   With 2 function : Add / Equal ===> * button
                     Clear ==>  # button
   It will use a MAX7219 for display the data ( for the shiftOut() ).
   and a 4021 for the keypad input data with the use of
   an NOT gate 74HC14. ( for the shiftin() )
   See the keypad example in the tread for details.
 
   The interrupt use a 72LS20 from the row pins, any LOW signal will
   produce a HIGH pulse to be use has an interrupt signal.

   By Serge J Desjardins
   aka techone / tech37
   Toronto, Ontario, Canada

   Compile and Tested.
   
   Bug :
   The add section need to be re-code.
*/

// Keypad Serial pins
const byte latchkeypin = 10;
const byte datakeypin = 12;
const byte clockkeypin = 11;

// Display Serial pins
const byte datadisplaypin = 9;
const byte clockdisplaypin = 8;
const byte latchdisplaypin = 7;

// Anykey and interrupt pin
const byte anykeypin = 2;

// MAX7419 init data
word initdata[5] = { 0x0C01, 0x0F00, 0x0A0B, 0x0B07, 0x09FF };

// Fill the Display array with a blank code
word display_data[8] = { 0x0100, 0x020F, 0x030F, 0x040F, 0x050F, 0x060F, 0x070F, 0x080F }; 

// The digit array
byte digit_number[8] = {0,0,0,0,0,0,0,0};

// For the digits extraction calculation
long power_of_ten[8] = {1,10,100,1000,10000,100000,1000000,10000000};

// Key press keypad flag
volatile boolean keystate;

// Overflow flag
boolean over_flow;
// add button flag
boolean add_flag;
// Clear button flag
boolean clear_flag;

// The keypad data
byte keydata;
byte keynumber;

// the ADD calculation
long the_number;
long temp_number;
long add_number;


void setup()
{
  //start serial
  //Serial.begin(9600);

  //define the pins modes
  pinMode(latchkeypin, OUTPUT);
  pinMode(clockkeypin, OUTPUT);
  pinMode(datakeypin, INPUT);
  pinMode(datadisplaypin, OUTPUT);
  pinMode(clockdisplaypin, OUTPUT);
  pinMode(latchdisplaypin, OUTPUT);
  pinMode(anykeypin, INPUT);
  // setup the interrupt pin
  attachInterrupt(0,anykeypress,RISING);
 
  /* Init the MAX7419 : Normal Mode
                        Normal Operation
                        Setting the Intensity
                        Numbers of Digits being display
                        Set to Decode Mode
  */

  for (int i=0;i<5;i++)
  { 
     digitalWrite(latchdisplaypin, LOW);
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, highByte(initdata[i]));
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, lowByte(initdata[i]) );
     digitalWrite(latchdisplaypin, HIGH);
     delay(5);
  }
  // Blank the display
  display_the_numbers();
  // init the flags and the calculation variable
  keystate = 0;
  add_number = 0;
  add_flag = 0;
  over_flow = 0;
  clear_flag = 1; 


void loop()

  while ( keystate == 0)
  {
     // wait for a key press
  }
  read_keypad();
  convert_the_keypad_data();
  // reset add flag and set the display
  if ( (( add_flag == 1) || ( clear_flag = 1 )) && ( over_flow == 0 ) )
  {
    for (int i=0;i<8;i++)
    {
      digit_number[i] = 0;
      display_data[i] = word ( ( i+1 ), 0x0F );
    }
    add_flag = 0;
    clear_flag = 0; 
  }
  // Enter the numbers routine 
  if ( ( keynumber < 0x0A ) && ( over_flow == 0 ) )
  {     
     // Enter the key number and move the arrays data.     
     for (int i=7;i>0;i--)
     {
       digit_number[i] = digit_number[i-1];
       display_data[i]=display_data[i-1];
       display_data[i] = word ( (i+1) , lowByte( display_data[i] ) );
     }
     digit_number[0] = keynumber;     
     display_data[0] = word ( 1, keynumber );     
     display_the_numbers();
     keystate = 0;   
  }
  else
  {
    // Check for the "Add / Equal" button
    if ( ( keynumber == 0x0B ) && ( over_flow == 0) )
    {     
      the_number= 0;
      for (int i=0;i<8;i++)
      {
        temp_number = long(digit_number[i]) * power_of_ten[i];
        the_number = the_number + temp_number;       
      } 
      add_number = add_number + the_number;
      if (add_number <= 99999999)
      {
        for (int i=7;i>=0;i--)
        {
          digit_number[i] = byte(add_number / power_of_ten[i]);
          add_number = add_number - (long(digit_number[i]) * power_of_ten[i]);
          display_data[i] = word ( ( i + 1) , digit_number[i] );       
        }
        for (int i=7;i>0;i++)
        {
          if ( digit_number[i] == 0 )
          {
             display_data[i] = word ( ( i + 1 ), 0x0F );
          }
          else
          {
            break;
          }   
        }
       
        display_the_numbers();
        add_flag = 1;
        keystate = 0;
      }
      else
      {
        // Over Flow
        over_flow = 1;
        digit_number[0] = 0;
        display_data[0] = 0x010B;
        for ( int i=1;i<8;i++)
        {
           digit_number[i] = 0;
           display_data[i] = word( (i+1), 0x0F );               
        }     
        keystate = 0;     
        display_the_numbers();           
      }         
    }
   
    // Check for the "Clear" button
    if ( keynumber == 0x0E )
    {
      digit_number[0] = 0;
      display_data[0] = 0x0100;
      for ( int i=1;i<8;i++)
      {
        digit_number[i] = 0;
        display_data[i] = word( (i+1), 0x0F );               
      }
      add_number = 0;
      keystate = 0;
      over_flow = 0;
      add_flag = 0;
      clear_flag = 1;
      display_the_numbers();     
    }   
  }   
  //For troubleshooting the program using Serial Monitor
/* 
    Serial.print(keydata, BIN);
    Serial.print("  ");
    Serial.print(keydata, HEX);
    Serial.print("  ");
    Serial.print(keynumber, HEX);
    Serial.print("  ");
    Serial.println(keydata, DEC);
    delay(1000);
*/
}

// Read keypad data via a 74HC14 - Inverter from the 4021
void read_keypad()
{
  digitalWrite(latchkeypin,HIGH);
  delayMicroseconds(20);
  digitalWrite(latchkeypin,LOW);
  keydata = shiftIn(datakeypin, clockkeypin,LSBFIRST); 
}

// Convert the keypad data into BCD
// And a code for *, 0, # button
void convert_the_keypad_data()
{
  byte what_row;
 
  what_row = ( keydata >> 3) & 0x0F;
  switch ( what_row)
  {
    case 1:
           keynumber = ( ( keydata >> 1 ) & 0x03 ) + 1;
           break;
    case 2:
           keynumber = (( keydata >> 1 ) & 0x03 ) + 4;
           break;
    case 4:
           keynumber = (( keydata >> 1 ) & 0x03 ) + 7;
           break;
    case 8:
           special_key();
           break;   
  } 
 


// the display the data routine to the MAX7219
void display_the_numbers()
{
   for (int i=0;i<8;i++)
   {
     digitalWrite(latchdisplaypin, LOW);
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, highByte(display_data[i]) );
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, lowByte(display_data[i]) );
     digitalWrite(latchdisplaypin, HIGH);
     delay(5);
   } 
}

// A special code for 0, *, # button
void special_key()
{
   byte special_case;
   
   special_case = ( ( keydata >> 1) & 0x03 ) + 1;
   switch ( special_case )
   {
     case 1:
            keynumber = 0x0E;
            break;
     case 2:
            keynumber = 0x00;
            break;
     case 3:
            keynumber = 0x0B;
            break;
   }       
}

// Interrupt Routibe
void anykeypress()
{
  keystate = 1;

Title: Re: Making a calculator using an Arduino
Post by: Nishant_Sood on Apr 01, 2012, 07:08 am
Quote
byte digit_number[8] = {0,0,0,0,0,0,0,0};

// For the digits extraction calculation
long power_of_ten[8] = {1,10,100,1000,10000,100000,1000000,10000000};


should the arrays not be [7] here?i think the last one is free.
Title: Re: Making a calculator using an Arduino
Post by: Techone on Apr 01, 2012, 07:24 am
array -> 7 ?  No... 8   "Boxes"  ;)  from Box 0 to Box 7 = 8 boxes

The arrays need data into them. I init my arrays, even it is Zero's. The code need it. I always init my variables.

My full calculator code is compiling. A bug in the Add section, an execution bug. I need to check it out, and maybe re-code that section.

The problem with me when I code, I have "writter's block". My mind is just "blank" and I have no clue how can I do this, and it is the lack of ideas of how can I program this out. That what I call "Writter's block". 
Title: Re: Making a calculator using an Arduino
Post by: Nishant_Sood on Apr 01, 2012, 07:41 am
Quote
I have "writter's block". My mind is just "blank" and I have no clue how can I do this


Why don't you just form specific functions for specific tasks like for e.g. >> Add() function for adding and pass on the processed variables(after formulating them for unit place etc.) into the respective function after just checking the * for Add or equal button  .
Title: Re: Making a calculator using an Arduino
Post by: graynomad on Apr 01, 2012, 09:01 am
I think one reason you have a bug is that there is just too much going on in the one function. As Nis$hant inferred you should compartmentalise things.

Also I don't think you need all the array shuffling and IMO read_keypad() should return a human-readable value, ie 0-9 and + etc.

For example here's is a simpler way (I think)

Code: [Select]
long num1;
long num2;
long result;
long *curr_num = num1;
byte key;

loop () {
key = read_keypad(); // this should return an int == to the numeric key entered or obvious values for '=' etc

switch (key) {

case '+':
    if (curr_num == num1) { // if first number just start accululating into second number
curr_num = num2;
} else {
addNumbers(); // if the second number add them
}
break;

case '=':
addNumbers();
break;

default:
accumulateNumber();
display_number(curr_num);

}
}

void addNumbers () {
result = num1 + num2;
display_number(result);
curr_num = num1;
num1 = 0;
num2 = 0;
}

void accumulateNumber () {
*curr_num *= 10;
*curr_num += key;
}

void display_number(long * num){
for (int x = 0; x < 8, x++) {
shiftNum (num % 10); // send digit out
num /= 10;
}
}



This is little more than psuedo code and there's no error checking etc but I think it's easy to follow and if there's a bug it should be easy to isolate.

______
Rob


Title: Re: Making a calculator using an Arduino
Post by: Nishant_Sood on Apr 01, 2012, 09:30 am
Yes Sir ROB i used to do similar coding while i programmed addition/subtraction/division/multiplication calculator back 2 years from now in VB.
The approach is pretty simple and easy to grasp while Mr. Serje  may not have any fault in his programme but due to increased cluttering he might not be able to stay on the correct logical path.
Title: Re: Making a calculator using an Arduino
Post by: Techone on Apr 02, 2012, 01:39 am
@Graynomad

Thanks for your idea. I may change my code if I have issues. Oh yes... I still do... will change the code later.

@NI$HANT

I agree with you. I may have to change my code for a modular method of coding. I have to many if()'s. I will have to do that later.

Updated :

I did re-code the add section, no modular method yet. Still have an issues with the keypad. I have : Double entry and  wrong entry. All intermittents problems. I may have to re-design the keypad circuit. Right now, it is not reliable.

As for the code, after the Add section change, still some bugs... But I like the new methode of adding.  Just like :

      Carry : 1111
                  1234 <-- Array call : digit_number[]
               +  9876 <-- Array call : add_number[]
                -------
Last Digit ->11110   The last digit is the OverFlow.  So I add two array + the carry.  That is the logic behind the Add routine.

The section that work : entry routine, the clear routine, keypad routine, convert routine and the display routine.
I will use the Serial Monitor to see what is going on. 

The updated code is the next post.

Thank for the idea. I will apreaciated that you guys check my code.     
                   
Title: Re: Making a calculator using an Arduino
Post by: Techone on Apr 02, 2012, 01:41 am
Here my updated code :

Code: [Select]


/*
   size : 2648 bytes
   
   Calculator Version 1.5
   
   Just add a number enter by the keypad and display it.
   With 2 function : Add / Equal ===> * button
                     Clear ==>  # button
   It will use a MAX7219 for display the data ( for the shiftOut() ).
   and a 4021 for the keypad input data with the use of
   an NOT gate 74HC14. ( for the shiftin() )
   See the keypad example in the tread for details.
 
   The interrupt use a 72LS20 from the row pins, any LOW signal will
   produce a HIGH pulse to be use has an interrupt signal.

   By Serge J Desjardins
   aka techone / tech37
   Toronto, Ontario, Canada

   Compile and Tested.   
*/

// Keypad Serial pins
const byte latchkeypin = 10;
const byte datakeypin = 12;
const byte clockkeypin = 11;

// Display Serial pins
const byte datadisplaypin = 9;
const byte clockdisplaypin = 8;
const byte latchdisplaypin = 7;

// Anykey and interrupt pin
const byte anykeypin = 2;

// MAX7419 init data
word initdata[5] = { 0x0C01, 0x0F00, 0x0A0B, 0x0B07, 0x09FF };

// Fill the Display array with a blank code
word display_data[8] = { 0x0100, 0x020F, 0x030F, 0x040F, 0x050F, 0x060F, 0x070F, 0x080F }; 

// The digit array
byte digit_number[8] = {0,0,0,0,0,0,0,0};

// The second array - The total number
byte add_number[9] = {0,0,0,0,0,0,0,0,0};

// Key press keypad flag
volatile boolean keystate;

// Overflow flag
boolean over_flow;
// add button flag
boolean add_flag;
// Clear button flag
boolean clear_flag;

// The keypad data
byte keydata;
byte keynumber;

void setup()
{
  //start serial
  //Serial.begin(9600);

  //define the pins modes
  pinMode(latchkeypin, OUTPUT);
  pinMode(clockkeypin, OUTPUT);
  pinMode(datakeypin, INPUT);
  pinMode(datadisplaypin, OUTPUT);
  pinMode(clockdisplaypin, OUTPUT);
  pinMode(latchdisplaypin, OUTPUT);
  pinMode(anykeypin, INPUT);
  // setup the interrupt pin
  attachInterrupt(0,anykeypress,RISING);
 
  /* Init the MAX7419 : Normal Mode
                        Normal Operation
                        Setting the Intensity
                        Numbers of Digits being display
                        Set to Decode Mode
  */

  for (int i=0;i<5;i++)
  { 
     digitalWrite(latchdisplaypin, LOW);
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, highByte(initdata[i]));
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, lowByte(initdata[i]) );
     digitalWrite(latchdisplaypin, HIGH);
     delay(5);
  }
  // Blank the display
  display_the_numbers();
  // init the flags and the calculation variable
  keystate = 0; 
  add_flag = 1;
  over_flow = 0;
  clear_flag = 1; 


void loop()

  while ( keystate == 0)
  {
     // wait for a key press
  }
  read_keypad();
  convert_the_keypad_data();
  // Enter the numbers routine 
  if ( ( keynumber < 0x0A ) && ( over_flow == 0 ) )
  { 
     if ( ( add_flag == 1) && ( clear_flag = 1 ) )
     {
       for (int i=0;i<8;i++)
       {
         digit_number[i] = 0;     
         display_data[i] = word ( ( i+1 ), 0x0F );
       }     
     }   
     // Enter the key number and move the arrays data.     
     for (int i=7;i>0;i--)
     {
       digit_number[i] = digit_number[i-1];
       display_data[i]=display_data[i-1];
       display_data[i] = word ( (i+1) , lowByte( display_data[i] ) );
     }
     digit_number[0] = keynumber;     
     display_data[0] = word ( 1, keynumber );     
     display_the_numbers();
     add_flag = 0;
     clear_flag = 0;
     keystate = 0;   
  }
  else
  {
    // Check for the "Add / Equal" button
    if ( ( keynumber == 0x0B ) && ( over_flow == 0) )
    {     
      for (int i=0;i<8;i++)
      {
         add_number[i] = add_number[i+1] + add_number[i] + digit_number[i];
         if (add_number[i] > 0x09 )
         {
           add_number[i+1] = 1;
           display_data[i] = word ( ( i + 1 ), ( add_number[i] - 10 ));
         }
         else
         {
            display_data[i] = word ( ( i + 1 ) , add_number[i]);
         }       
      } 
     
      // check for over flow
      if ( add_number[8] > 0)
      {     
        over_flow = 1;
        digit_number[0] = 0;       
        display_data[0] = 0x010B;
        for ( int i=1;i<8;i++)
        {
           digit_number[i] = 0;
           display_data[i] = word( (i+1), 0x0F );               
        }     
        keystate = 0;
        over_flow = 1;
        add_flag = 1;     
        display_the_numbers();           
      }
      else
      {
        keystate = 0;
        over_flow = 0;
        add_flag = 1;
        display_the_numbers();
      }     
    }
   
    // Check for the "Clear" button
    if ( keynumber == 0x0E )
    {
      digit_number[0] = 0;
      add_number[0] = 0;
      display_data[0] = 0x0100;
      for ( int i=1;i<8;i++)
      {
        digit_number[i] = 0;
        add_number[i] = 0;
        display_data[i] = word( (i+1), 0x0F );               
      }
      add_number[8] = 0;
      keystate = 0;
      over_flow = 0;
      add_flag = 1;
      clear_flag = 1;
      display_the_numbers();     
    }   
  }   
  //For troubleshooting the program using Serial Monitor
/* 
    Serial.print(keydata, BIN);
    Serial.print("  ");
    Serial.print(keydata, HEX);
    Serial.print("  ");
    Serial.print(keynumber, HEX);
    Serial.print("  ");
    Serial.println(keydata, DEC);
    delay(1000);
*/
}

// Read keypad data via a 74HC14 - Inverter from the 4021
void read_keypad()
{
  digitalWrite(latchkeypin,HIGH);
  delayMicroseconds(20);
  digitalWrite(latchkeypin,LOW);
  keydata = shiftIn(datakeypin, clockkeypin,LSBFIRST); 
}

// Convert the keypad data into BCD
// And a code for *, 0, # button
void convert_the_keypad_data()
{
  byte what_row;
 
  what_row = ( keydata >> 3) & 0x0F;
  switch ( what_row)
  {
    case 1:
           keynumber = ( ( keydata >> 1 ) & 0x03 ) + 1;
           break;
    case 2:
           keynumber = (( keydata >> 1 ) & 0x03 ) + 4;
           break;
    case 4:
           keynumber = (( keydata >> 1 ) & 0x03 ) + 7;
           break;
    case 8:
           special_key();
           break;   
  } 
 


// the display the data routine to the MAX7219
void display_the_numbers()
{
   for (int i=0;i<8;i++)
   {
     digitalWrite(latchdisplaypin, LOW);
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, highByte(display_data[i]) );
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, lowByte(display_data[i]) );
     digitalWrite(latchdisplaypin, HIGH);
     delay(5);
   } 
}

// A special code for 0, *, # button
void special_key()
{
   byte special_case;
   
   special_case = ( ( keydata >> 1) & 0x03 ) + 1;
   switch ( special_case )
   {
     case 1:
            keynumber = 0x0E;
            break;
     case 2:
            keynumber = 0x00;
            break;
     case 3:
            keynumber = 0x0B;
            break;
   }       
}

// Interrupt Routibe
void anykeypress()
{
  keystate = 1;

Title: Re: Making a calculator using an Arduino
Post by: Techone on Apr 02, 2012, 03:24 am
Updated :

I did place the sections into a routine way. I re-modify my code. Almost the same code, except a bit more "modular"

Issue : The Add section still give me some problems. Sometime, it work, and then it is not, I even see the Over Flow ==> E the Numbers are lock and the add button is lock <== That is expected, that mean it did go through the Add Section. The clear work just great.  Still have double entry, and I got the feeling my keypad circuit need to be change.  The cause is : When I press a key, the voltage level is not approaching a LOW level for the input of the 74HC14. It is in the "If Zone" <-- "Can Not Make Up It Mind Level". So I will re-design the keypad circuit with LM339, and add a 555 circuit in a monostable mode to take care of the interrupt signal <-- possible cause of the "double" entry. The interrupt signal came from a 74LS20. The 555 is the "deboucing" circuit. And also, I may add a latch chip between the 74LS14 ( that is the buffer after the LM339 output )  and the 4021. Maybe the 555 output ? , or another digital out pin to take care of that ?   555 is a more reliable. 

As for my code, I will keep it and test it with the new keypad circuit. Well I may change a bit the Add section... I press Add, and it display : 0000012 . That is just cosmetic bug, I will fix that in the Add section. Just replace the 0 before the 1 with 0x0F <-- code for Display Blank to be send at the MAX7219.

I know, it is sound overkill, I need reliability, that is why I overkill in my circuits and code. I am trying to remove Murphay's Law of the equation.    Input + Murphay's Law = Garbage Output   

Next post is the updated code.
Title: Re: Making a calculator using an Arduino
Post by: Techone on Apr 02, 2012, 03:27 am
Here the updated code. I will appreaciated that you guys look at it and tell me what you think.

Code: [Select]

/*
   size : 2734 bytes
   
   Calculator Version 1.5
   
   Just add a number enter by the keypad and display it.
   With 2 function : Add / Equal ===> * button
                     Clear ==>  # button
   It will use a MAX7219 for display the data ( for the shiftOut() ).
   and a 4021 for the keypad input data with the use of
   an NOT gate 74HC14. ( for the shiftin() )
   See the keypad example in the tread for details.
 
   The interrupt use a 72LS20 from the row pins, any LOW signal will
   produce a HIGH pulse to be use has an interrupt signal.

   By Serge J Desjardins
   aka techone / tech37
   Toronto, Ontario, Canada

   Compile and Tested. Still Issues. Maybe it it the Keypad circuit. Not so clean   
*/

// Keypad Serial pins
const byte latchkeypin = 10;
const byte datakeypin = 12;
const byte clockkeypin = 11;

// Display Serial pins
const byte datadisplaypin = 9;
const byte clockdisplaypin = 8;
const byte latchdisplaypin = 7;

// Anykey and interrupt pin
const byte anykeypin = 2;

// MAX7419 init data
word initdata[5] = { 0x0C01, 0x0F00, 0x0A0B, 0x0B07, 0x09FF };

// Fill the Display array with a blank code
word display_data[8] = { 0x0100, 0x020F, 0x030F, 0x040F, 0x050F, 0x060F, 0x070F, 0x080F }; 

// The digit array
byte digit_number[8] = {0,0,0,0,0,0,0,0};

// The second array - The total number
byte add_number[9] = {0,0,0,0,0,0,0,0,0};

// Key press keypad flag
volatile boolean keystate;

// Overflow flag
boolean over_flow;
// add button flag
boolean add_flag;
// Clear button flag
boolean clear_flag;

// The keypad data
byte keydata;
byte keynumber;

// The choice
byte choise;

void setup()
{
  //start serial
  //Serial.begin(9600);

  //define the pins modes
  pinMode(latchkeypin, OUTPUT);
  pinMode(clockkeypin, OUTPUT);
  pinMode(datakeypin, INPUT);
  pinMode(datadisplaypin, OUTPUT);
  pinMode(clockdisplaypin, OUTPUT);
  pinMode(latchdisplaypin, OUTPUT);
  pinMode(anykeypin, INPUT);
  // setup the interrupt pin
  attachInterrupt(0,anykeypress,RISING);
 
  /* Init the MAX7419 : Normal Mode
                        Normal Operation
                        Setting the Intensity
                        Numbers of Digits being display
                        Set to Decode Mode
  */

  for (int i=0;i<5;i++)
  { 
     digitalWrite(latchdisplaypin, LOW);
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, highByte(initdata[i]));
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, lowByte(initdata[i]) );
     digitalWrite(latchdisplaypin, HIGH);
     delay(5);
  }
  // Blank the display
  display_the_numbers();
  // init the flags and the calculation variable
  keystate = 0; 
  add_flag = 1;
  over_flow = 0;
  clear_flag = 1; 


void loop()

  while ( keystate == 0)
  {
     // wait for a key press
  }
  read_keypad();
  convert_the_keypad_data();
  // The choise 1 = numbers , 2 = add , 3 = clear
  switch (choise)
  {
     case 1 :
             entry_of_numbers();
             break;
     case 2 :
             add_section();
             break;
     case 3 :
             clear_section();
             break;     
  } 
}

// Choise 1
void entry_of_numbers()

  // Enter the numbers routine 
  if ( over_flow == 0 )
  { 
     if ( ( add_flag == 1) && ( clear_flag = 1 ) )
     {
       for (int i=0;i<8;i++)
       {
         digit_number[i] = 0;     
         display_data[i] = word ( ( i+1 ), 0x0F );
       }     
     }   
     // Enter the key number and move the arrays data.     
     for (int i=7;i>0;i--)
     {
       digit_number[i] = digit_number[i-1];
       display_data[i]=display_data[i-1];
       display_data[i] = word ( (i+1) , lowByte( display_data[i] ) );
     }
     digit_number[0] = keynumber;     
     display_data[0] = word ( 1, keynumber );     
     display_the_numbers();
     add_flag = 0;
     clear_flag = 0;
     keystate = 0;   
  }
}
// Choise 2 - the add section
void add_section()
{
    // Check for the "Add / Equal" button
    if ( over_flow == 0 )
    {     
      for (int i=0;i<8;i++)
      {
         add_number[i] = add_number[i+1] + add_number[i] + digit_number[i];
         if ((add_number[i] > 0x09) && (add_number[i] < 0x14) )
         {
           add_number[i+1] = 1;
           display_data[i] = word ( ( i + 1 ), ( add_number[i] - 10 ));
         }
         else
         {
            display_data[i] = word ( ( i + 1 ) , add_number[i]);
         }       
      } 
     
      // check for over flow
      if ( add_number[8] != 0)
      {     
        over_flow = 1;
        digit_number[0] = 0;       
        display_data[0] = 0x010B;
        for ( int i=1;i<8;i++)
        {
           digit_number[i] = 0;
           display_data[i] = word( (i+1), 0x0F );               
        }     
        keystate = 0;
        over_flow = 1;
        add_flag = 1;     
        display_the_numbers();           
      }
      else
      {
        keystate = 0;
        over_flow = 0;
        add_flag = 1;
        display_the_numbers();
      }     
    }
}

// Choise 3 - The clear section
void clear_section()
{
    // Check for the "Clear" button
      digit_number[0] = 0;
      add_number[0] = 0;
      display_data[0] = 0x0100;
      for ( int i=1;i<8;i++)
      {
        digit_number[i] = 0;
        add_number[i] = 0;
        display_data[i] = word( (i+1), 0x0F );               
      }
      add_number[8] = 0;
      keystate = 0;
      over_flow = 0;
      add_flag = 1;
      clear_flag = 1;
      display_the_numbers();     
     
}   
  //For troubleshooting the program using Serial Monitor
/* 
    Serial.print(keydata, BIN);
    Serial.print("  ");
    Serial.print(keydata, HEX);
    Serial.print("  ");
    Serial.print(keynumber, HEX);
    Serial.print("  ");
    Serial.println(keydata, DEC);
    delay(1000);
*/

// Read keypad data via a 74HC14 - Inverter from the 4021
void read_keypad()
{
  digitalWrite(latchkeypin,HIGH);
  delayMicroseconds(20);
  digitalWrite(latchkeypin,LOW);
  keydata = shiftIn(datakeypin, clockkeypin,LSBFIRST); 
}

// Convert the keypad data into BCD
// And a code for *, 0, # button
void convert_the_keypad_data()
{
  byte what_row;
 
  what_row = ( keydata >> 3) & 0x0F;
  switch ( what_row)
  {
    case 1:
           keynumber = ( ( keydata >> 1 ) & 0x03 ) + 1;
           choise = 1;
           break;
    case 2:
           keynumber = (( keydata >> 1 ) & 0x03 ) + 4;
           choise = 1;
           break;
    case 4:
           keynumber = (( keydata >> 1 ) & 0x03 ) + 7;
           choise = 1;
           break;
    case 8:
           special_key();
           break;   
  } 
 


// the display the data routine to the MAX7219
void display_the_numbers()
{
   for (int i=0;i<8;i++)
   {
     digitalWrite(latchdisplaypin, LOW);
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, highByte(display_data[i]) );
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, lowByte(display_data[i]) );
     digitalWrite(latchdisplaypin, HIGH);
     delay(5);
   } 
}

// A special code for 0, *, # button
void special_key()
{
   byte special_case;
   
   special_case = ( ( keydata >> 1) & 0x03 ) + 1;
   switch ( special_case )
   {
     case 1:
            keynumber = 0x0E;
            choise = 3;
            break;
     case 2:
            keynumber = 0x00;
            choise = 1;
            break;
     case 3:
            keynumber = 0x0B;
            choise = 2;
            break;
   }       
}

// Interrupt Routibe
void anykeypress()
{
  keystate = 1;



Title: Re: Making a calculator using an Arduino
Post by: Nishant_Sood on Apr 02, 2012, 07:38 am
Hi Mr.Serje , had a look on the code,

What about the KeyPad , is it working fine with amp now? i recall you had a problem with that! , May be its having debouncing effect?
Title: Re: Making a calculator using an Arduino
Post by: graynomad on Apr 02, 2012, 09:33 am
One thing  notice is that there's no debouncing with the keypad reading. That may cause unreliable input.

______
Rob
Title: Re: Making a calculator using an Arduino
Post by: Techone on Apr 02, 2012, 04:16 pm
I agree with both of you. I may add a debounce, but I wonder how and where to place the tiny delay ? The key data came from the 4021, after a shiftIn() read. And the interrupt signal came from a 4 input NAND gate - 74LS20.  So any bouncing by a key, also created a double pulse at the interrupt pin, activate the interrupt request. A 555 in monostable mode will take care of that. I will re-design the keypad circuit and is not done yet. I may add a latch in between the inverters and the 4021.  And beside the bouncing problem, the close contact is not a close contact after all, more than intermittent, due to a non - proper LOW level at the input gates. The LM339 comparator will take care of that. I will set the comparator V ref at 2.5 V <-- mid point. Still two state.   

I will keep you guys posted.

I happen to have a PS/2 keypad - see picture. I will re-code using the PS/2 library and re-do a circuit to use the PS/2 keypad and using the same 7 segments display. I will do that later. I will keep you posted on that one too. Still keep the same tread anyway.

Title: Re: Making a calculator using an Arduino
Post by: Nishant_Sood on Apr 02, 2012, 06:53 pm
Hi Mr.Serje i hope things are fine and the code is hopefully getting done ,following i add my suggestions:

Quote
also created a double pulse at the interrupt pin, activate the interrupt request.


I think what here can be done is that as the interrupt is being fired by the NAND gate You can set a counter in here to note the number of times the interrupt routine is being fired and put in a debugging statements on the Serial (I debugged my code in the same way when I was working with interrupts that however came from a mechanical part that is a Reed Switch) this way the real culprit can be traced back, if and only if the debouncing may be happening.

also. Mr.Serje you told once that amplifying(if i recall it right from my memory) the keypad buttons may make then susceptible to ultra sensitivity and thus the same can result in debounce.



Title: Re: Making a calculator using an Arduino
Post by: cyclegadget on Apr 02, 2012, 07:58 pm

I have a keypad/LCD screen that I put both debounce code into it for the usual reasons. I also put a millis count so that I could not double enter the same button.

Pseudo code:

Code: [Select]
Check for button press twice for debounce
          if good button press, use it,
  if a new button press check millis
if (millis - last button press) ==  long enough time
  record new button press


The downside is you can push a button too quickly and have it ignored depending how you set the "long enough time variable.
Title: Re: Making a calculator using an Arduino
Post by: Techone on Apr 03, 2012, 01:06 am
@cyclegadget

Thank for you tips. Using the millis - time  to check if a double press is being done... OK I think I get you. To impliment in my code, that I will figure this out. It look like it is a good idea. I will impliment something like that.

Let see :Loop 1 :  read key    Loop 1 ---> I mean : void loop()
                         measured time

            Loop 2 :  readkey
                         measured time
                         check the time difference
                         if to small - don't take the key
                         if big enough - take the key

Something like that.  But with a 555 in monostable - output of the 555 going to the interrupt pin will solve the debouncing problem.
And I will do a digitalWrite( latchkeypin, HIGH ) in the interrupt routine to latch the keypad data.

@NI$HANT

To monitor the interrupt routine using Serial Monitor is a good idea.

Quote
also. Mr.Serje you told once that amplifying(if i recall it right from my memory) the keypad buttons may make then susceptible to ultra sensitivity and thus the same can result in debounce


I agree. That the 555 in monostable come in. I just set the output of the 555 about .. let say 10 mS to 20 mS. The input can multi pulse for 1 ms to 8 mS until it is stable, and the 555 chip won't even care about it. It is after the 555 finish it's pulse that the 555 chip care. ( the mono stable circuit, that is )

Title: Re: Making a calculator using an Arduino
Post by: Techone on Apr 03, 2012, 01:25 am
Updated :

The new keypad circuit is still no done.  Today, when I was finish my afternoon run, going home, and in the kitchen, I was thinking about my code, and it occur to me that I made a executable bug in the ADD routine. I was installing the carry into the next array box, that may explain some garbage data in my display. No add right , screw up numbers, etc. Instead to place the carry into the add_number[] array, I just simply use a "temp" variable. Use the / and % to isolate the unit number. 

Example :  temp = add_number / 10;   <-- the carry calculation
               temp = 12 / 10 --> 1  or 8 / 10 --> 0 
Extract Unit : add_number = add_number % 10;
                   add_number = 12 % 10 --- > 2  or 8 % 10 ---> 8 <-- the unit to be display.

Add also, I fix the "cosmetic" bug. Was display : 00001234  Now :        1234

I change the interrupt routine : I just add : digitalWrite(latchkeypin, HIGH);  And remove that line from the read_keypad routine.

Next post is the new and final code. <-- I think   

Here the old code :

Code: [Select]

if ( over_flow == 0)
    {     
      for (int i=0;i<8;i++)
      {
         add_number[i] = add_number[i+1] + add_number[i] + digit_number[i];
         if (add_number[i] > 0x09 )
         {
           add_number[i+1] = 1;
           display_data[i] = word ( ( i + 1 ), ( add_number[i] - 10 ));
         }
         else
         {
            display_data[i] = word ( ( i + 1 ) , add_number[i]);
         }       
      } 
     
      // check for over flow
      if ( add_number[8] > 0)
      {     
        over_flow = 1;
        digit_number[0] = 0;       
        display_data[0] = 0x010B;
        for ( int i=1;i<8;i++)
        {
           digit_number[i] = 0;
           display_data[i] = word( (i+1), 0x0F );               
        }     
        keystate = 0;
        over_flow = 1;
        add_flag = 1;     
        display_the_numbers();           
      }
      else
      {
        keystate = 0;
        over_flow = 0;
        add_flag = 1;
        display_the_numbers();
      }     
    }

 
   
The new Add section

Code: [Select]

// Choise 2 - the add section
void add_section()
{
    byte temp;
 
    if ( over_flow == 0 )
    {
      // The Add logic   
      temp = 0; // the carry variable
      for (int i=0;i<8;i++)
      {
         add_number[i] = temp + add_number[i] + digit_number[i];
         temp = add_number[i] / 10;
         add_number[i] = add_number[i] % 10;
         display_data[i] = word ( ( i + 1 ) , add_number[i] );
      } 
     
      // check for over flow
      if ( temp != 0)
      {     
        over_flow = 1;
        digit_number[0] = 0;       
        display_data[0] = 0x010B;
        for ( int i=1;i<8;i++)
        {
           digit_number[i] = 0;
           display_data[i] = word( (i+1), 0x0F );               
        }     
        keystate = 0;
        over_flow = 1;
        add_flag = 1;     
        display_the_numbers();           
      }
      else
      {
        /*
        For a cleaner display by removing
        the zero's on the left side of the number
        */
        for (int i=7;i>0;i--)
        {
          if (add_number[i] == 0)
          {
            display_data[i] = word ( ( i + 1 ) , 0x0F );
          }
          else
          {
            break;
          }         
        }         
        keystate = 0;
        over_flow = 0;
        add_flag = 1;
        display_the_numbers();
      }     
    }
}



Title: Re: Making a calculator using an Arduino
Post by: Techone on Apr 03, 2012, 01:27 am
Here is the updated and maybe the final code. It is working nice, except the issue with the keypad - double entry and miss key.

Code: [Select]

/*
   size : 2794 bytes
   
   Calculator Version 2.0
   
   Just add a number enter by the keypad and display it.
   With 2 function : Add / Equal ===> * button
                     Clear ==>  # button
   It will use a MAX7219 for display the data ( for the shiftOut() ).
   and a 4021 for the keypad input data with the use of
   an NOT gate 74HC14. ( for the shiftin() )
   See the keypad example in the tread for details.
 
   The interrupt use a 72LS20 from the row pins, any LOW signal will
   produce a HIGH pulse to be use has an interrupt signal.

   By Serge J Desjardins
   aka techone / tech37
   Toronto, Ontario, Canada

   Compile and Tested.   
*/

// Keypad Serial pins
const byte latchkeypin = 10;
const byte datakeypin = 12;
const byte clockkeypin = 11;

// Display Serial pins
const byte datadisplaypin = 9;
const byte clockdisplaypin = 8;
const byte latchdisplaypin = 7;

// Anykey and interrupt pin
const byte anykeypin = 2;

// MAX7419 init data
word initdata[5] = { 0x0C01, 0x0F00, 0x0A0B, 0x0B07, 0x09FF };

// Fill the Display array with a blank code
word display_data[8] = { 0x0100, 0x020F, 0x030F, 0x040F, 0x050F, 0x060F, 0x070F, 0x080F }; 

// The digit array
byte digit_number[8] = {0,0,0,0,0,0,0,0};

// The second array - The total number
byte add_number[8] = {0,0,0,0,0,0,0,0};

// Key press keypad flag
volatile boolean keystate;

// Overflow flag
boolean over_flow;
// add button flag
boolean add_flag;
// Clear button flag
boolean clear_flag;

// The keypad data
byte keydata;
byte keynumber;

// The choice
byte choise;

void setup()
{
  //define the pins modes
  pinMode(latchkeypin, OUTPUT);
  pinMode(clockkeypin, OUTPUT);
  pinMode(datakeypin, INPUT);
  pinMode(datadisplaypin, OUTPUT);
  pinMode(clockdisplaypin, OUTPUT);
  pinMode(latchdisplaypin, OUTPUT);
  pinMode(anykeypin, INPUT);
  // setup the interrupt pin
  attachInterrupt(0,anykeypress,RISING);
 
  /* Init the MAX7419 : Normal Mode
                        Normal Operation
                        Setting the Intensity
                        Numbers of Digits being display
                        Set to Decode Mode
  */

  for (int i=0;i<5;i++)
  { 
     digitalWrite(latchdisplaypin, LOW);
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, highByte(initdata[i]));
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, lowByte(initdata[i]) );
     digitalWrite(latchdisplaypin, HIGH);
     delay(5);
  }
  // Blank the display
  display_the_numbers();
 
  // Set the latch key LOW
  digitalWrite(latchkeypin, LOW);
  // init the flags and the calculation variable
  keystate = 0; 
  add_flag = 1;
  over_flow = 0;
  clear_flag = 1;   


void loop()

  while ( keystate == 0)
  {
     // wait for a key press
  }
  read_keypad();
  convert_the_keypad_data();
  // The choise 1 = numbers , 2 = add , 3 = clear
  switch (choise)
  {
     case 1 :
             entry_of_numbers();
             break;
     case 2 :
             add_section();
             break;
     case 3 :
             clear_section();
             break;     
  } 
}

// Choise 1
void entry_of_numbers()

  // Enter the numbers routine 
  if ( over_flow == 0 )
  { 
     if ( ( add_flag == 1) && ( clear_flag = 1 ) )
     {
       for (int i=0;i<8;i++)
       {
         digit_number[i] = 0;     
         display_data[i] = word ( ( i+1 ), 0x0F );
       }     
     }   
     // Enter the key number and move the arrays data.     
     for (int i=7;i>0;i--)
     {
       digit_number[i] = digit_number[i-1];
       display_data[i]=display_data[i-1];
       display_data[i] = word ( (i+1) , lowByte( display_data[i] ) );
     }
     digit_number[0] = keynumber;     
     display_data[0] = word ( 1, keynumber );     
     display_the_numbers();
     add_flag = 0;
     clear_flag = 0;
     keystate = 0;   
  }
}
// Choise 2 - the add section
void add_section()
{
    byte temp;
 
    if ( over_flow == 0 )
    {
      // The Add logic   
      temp = 0; // the carry variable
      for (int i=0;i<8;i++)
      {
         add_number[i] = temp + add_number[i] + digit_number[i];
         temp = add_number[i] / 10;
         add_number[i] = add_number[i] % 10;
         display_data[i] = word ( ( i + 1 ) , add_number[i] );
      } 
     
      // check for over flow
      if ( temp != 0)
      {     
        over_flow = 1;
        digit_number[0] = 0;       
        display_data[0] = 0x010B;
        for ( int i=1;i<8;i++)
        {
           digit_number[i] = 0;
           display_data[i] = word( (i+1), 0x0F );               
        }     
        keystate = 0;
        over_flow = 1;
        add_flag = 1;     
        display_the_numbers();           
      }
      else
      {
        /*
        For a cleaner display by removing
        the zero's on the left side of the number
        */
        for (int i=7;i>0;i--)
        {
          if (add_number[i] == 0)
          {
            display_data[i] = word ( ( i + 1 ) , 0x0F );
          }
          else
          {
            break;
          }         
        }         
        keystate = 0;
        over_flow = 0;
        add_flag = 1;
        display_the_numbers();
      }     
    }
}

// Choise 3 - The clear section
void clear_section()
{
    // Check for the "Clear" button
      digit_number[0] = 0;
      add_number[0] = 0;
      display_data[0] = 0x0100;
      for ( int i=1;i<8;i++)
      {
        digit_number[i] = 0;
        add_number[i] = 0;
        display_data[i] = word( (i+1), 0x0F );               
      }     
      keystate = 0;
      over_flow = 0;
      add_flag = 1;
      clear_flag = 1;
      display_the_numbers();     
     
}   

// Read keypad data via a 74HC14 - Inverter from the 4021
void read_keypad()
{

  delayMicroseconds(10);
  digitalWrite(latchkeypin,LOW);
  keydata = shiftIn(datakeypin, clockkeypin,LSBFIRST); 
}

// Convert the keypad data into BCD
// And a code for *, 0, # button
void convert_the_keypad_data()
{
  byte what_row;
 
  what_row = ( keydata >> 3) & 0x0F;
  switch ( what_row)
  {
    case 1:
           keynumber = ( ( keydata >> 1 ) & 0x03 ) + 1;
           choise = 1;
           break;
    case 2:
           keynumber = (( keydata >> 1 ) & 0x03 ) + 4;
           choise = 1;
           break;
    case 4:
           keynumber = (( keydata >> 1 ) & 0x03 ) + 7;
           choise = 1;
           break;
    case 8:
           special_key();
           break;   
  } 
 


// the display the data routine to the MAX7219
void display_the_numbers()
{
   for (int i=0;i<8;i++)
   {
     digitalWrite(latchdisplaypin, LOW);
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, highByte(display_data[i]) );
     shiftOut(datadisplaypin, clockdisplaypin, MSBFIRST, lowByte(display_data[i]) );
     digitalWrite(latchdisplaypin, HIGH);
     delay(5);
   } 
}

// A special code for 0, *, # button
void special_key()
{
   byte special_case;
   
   special_case = ( ( keydata >> 1) & 0x03 ) + 1;
   switch ( special_case )
   {
     case 1:
            keynumber = 0x0E;
            choise = 3;
            break;
     case 2:
            keynumber = 0x00;
            choise = 1;
            break;
     case 3:
            keynumber = 0x0B;
            choise = 2;
            break;
   }       
}

// Interrupt Routibe
void anykeypress()
{
  digitalWrite(latchkeypin, HIGH);
  keystate = 1;
Title: Re: Making a calculator using an Arduino
Post by: Nishant_Sood on Apr 03, 2012, 07:33 am
Quote
double entry and miss key


okay so it seems Mr.Serje that everything now is fine , i think we guys are done and the code is good the problem arising if any is because of that keypad that is getting beyond our control.
Title: Re: Making a calculator using an Arduino
Post by: Techone on Apr 03, 2012, 04:12 pm
Thanks NI$HANT for your support.

Quote
because of that keypad that is getting beyond our control.


I will tame that keypad, don't you worry about it  :smiley-mr-green:

I will keep you guys update about my progress. The PS/2 keypad will be use for the same idea. But a more complete project by adding the function : Add, Minus, Multiplication and Division. 
Title: Re: Making a calculator using an Arduino
Post by: Nishant_Sood on Apr 03, 2012, 04:23 pm
Mention not! Mr Serje, I'm always here for you, now lets see how things work with ps 2 keyboard.
Title: Re: Making a calculator using an Arduino
Post by: josh-s on Dec 13, 2014, 05:29 am
I want to do something very similar to this, but I want preset buttons (15, 16, 17, 18, 19, 20, 25) and have those numbers be added when each of the 7 buttons would correlate with the addition of each of the numbers listed. Any advice as to how i would go about this coding?