MarineUTEP
MarineUTEP

Reputation: 43

Converting decimal to BCD

I'm working on an assignment currently that uses a microcontroller and a circuit to display a decimal in binary, through LED's. I have to use three push buttons: one to increment, one to decrement, and the last to reset. I have my wiring and configuration complete. My code on the other hand has some glitches that I cannot fix with only an intro to C class under my belt. I am using Code Composer. Problem number one: My counter on the "Tens" section(MSB) does not stop at 9 but rather begins to display binary 10-15. The first four bits are the ones(right) and the second four bits, tens(left) ex: 1010 0001 but the max value is 1001 1001. Problem number two: starting from zero if I decrement the value, the counter displays 95 rather than 99. ex: starting from 0000 0000 decrement displays 1001 0101. I tried using an if statement to make a condition for MSB to stop if greater than ten but the code doesn't run. Pretty much any modification I did to my code prevents it from working properly.

#include <msp430.h>

unsigned int dec2bcd(unsigned int num);
void delay(void);

int main(void) {
WDTCTL = WDTPW | WDTHOLD;    // Stop watchdog timer

P1DIR = 0xFF;
P2DIR = 0xF0;
unsigned int c;
unsigned int count = 0x00;

while(1){
    if((P2IN & BIT0) == BIT0){
        count++;
        c = dec2bcd(count);
    }

    else if((P2IN&BIT1) == BIT1){
        count--;
        c = dec2bcd(count);
    }

    else if((P2IN&BIT2) == BIT2){
        count = 0x00;
        c = dec2bcd(count);
    }

    delay();
    P1OUT = c;

}

}

unsigned int dec2bcd(unsigned int num)
{
    unsigned int ones = 0;
    unsigned int tens = 0;
    unsigned int temp = 0;

    ones = num%10;
    temp = num/10;
    tens = temp<<4;
    return (tens + ones);
}

void delay(void)
{
    volatile unsigned int i, j;
    for(i=10000; i>0; i--)
    {
        for(j=3; j>0; j--){
    }
}
}

Upvotes: 2

Views: 15623

Answers (6)

AJC
AJC

Reputation: 1

Structured Text Works For REAL numbers for 8 digit numbers mulitiplier removes decimal places.

// DECIMAL REAL NUMBER TO BCD FUNCTION_BLOCK DecToBcd_8D

// CHECK THE FUNCTION ENABLE IF(Enb)THEN

// READ THE INPUT VALUE AND REMOVE THE SET NUMBER OF DECIMAL PLACES
Dec_MUL:= REAL_TO_UDINT(Dec_IP * Dec_MUL_IP);

// DECODE EACH DIGIT OF THE DECIMAL NUMBER
Bcd_n1:= SHL(((Dec_MUL / 10000000) MOD 10), 28);                             
Bcd_n2:= SHL(((Dec_MUL / 1000000) MOD 10), 24);                              
Bcd_n3:= SHL(((Dec_MUL / 100000) MOD 10), 20);                               
Bcd_n4:= SHL(((Dec_MUL / 10000) MOD 10), 16);                                
Bcd_n5:= SHL(((Dec_MUL / 1000) MOD 10), 12);                                 
Bcd_n6:= SHL(((Dec_MUL / 100) MOD 10), 8);                                   
Bcd_n7:= SHL(((Dec_MUL / 10) MOD 10), 4);                                    
Bcd_n8:= (Dec_MUL MOD 10);                                                   

// SET THE BCD OUTPUT DATA
Bcd_OP:= (Bcd_n1 OR Bcd_n2 OR Bcd_n3 OR Bcd_n4 OR
            Bcd_n5 OR Bcd_n6 OR Bcd_n7 OR Bcd_n8);                           

ELSE Bcd_OP:= 0; END_IF

END_FUNCTION_BLOCK

Upvotes: 0

MarineUTEP
MarineUTEP

Reputation: 43

Here is the new code that has resolved the issues that I was having earlier. It may not be the most optimal but I managed to make it work. I added two if-statements that created the wrap around, and I modified the dec2bcd converter by implementing a modulus. The modulus in the "tens" section helped to get rid of the display issue. Thanks guys for helping me! Now I understand my syntax errors and thanks for showing me that there was a wider scope that I needed to pay attention to. Wish me luck and I hope I get the extra credit. Til next time.

#include <msp430g2553.h>

unsigned int dec2bcd(unsigned int num);
void delay(void);

int main(void) {
WDTCTL = WDTPW | WDTHOLD;    // Stop watchdog timer

P1DIR = 0xFF;
P2DIR = 0x00;
unsigned int c;
unsigned int count = 0x00;

//Here are some modified portions to create wrap around
while(1){
    if((P2IN & BIT0) == BIT0){
        count++;
        if(count == (99+1)){
            count = 0x00;
        }
        c = dec2bcd(count);
    }

    else if((P2IN&BIT1) == BIT1){
        count--;
        if(count == (0-1)){
            count = 0x63;
        }
        c = dec2bcd(count);
    }

    else if((P2IN&BIT2) == BIT2){
        count = 0x00;
        c = dec2bcd(count);
    }
    delay();
    P1OUT = c;

}

}

unsigned int dec2bcd(unsigned int num)
{
    unsigned int ones = 0;
    unsigned int tens = 0;
    unsigned int temp = 0;

    ones = num%10;
    temp = num/10;
    //I used modulus here to get rid of the improper display issue
    tens = (temp%10)<<4; 
    return (tens + ones);
}

void delay(void)
{
    volatile unsigned int i, j;
    for(i=10000; i>0; i--)
    {
        for(j=3; j>0; j--){
    }
}
}

Upvotes: 0

user3528438
user3528438

Reputation: 2817

Why you see 95?

As mentioned by @Olaf, msp430 uses 16bit integer.

When you do count = 0u -1, count acutally wraps to 65535;

unsigned int dec2bcd(unsigned int num) // num is now 65535
{
    unsigned int ones = 0;
    unsigned int tens = 0;
    unsigned int temp = 0;

    ones = num%10; // 65535%10 = 5
    temp = num/10; // 65535/10 = 6553
    tens = temp<<4;  // what's displayed is by tens is actually the lower
                     // 4 bits of tens, so tens is 6553%16=9
    return (tens + ones);// so the result is 95
}

Why tens can to beyond 10

Same problem, because your input is greater than 99.

unsigned int dec2bcd(unsigned int num) // say num is now 100
{
    unsigned int ones = 0;
    unsigned int tens = 0;
    unsigned int temp = 0;

    ones = num%10; // 100%10 = 0
    temp = num/10; // 100/10 = 10, or 0x0A
    tens = temp<<4;  
    return (tens + ones);// so the result is A0
}

What you should do?

In your code, limit the range to 0-99, you have the choice of either wrap-around (99+1=0, and 0-1=99)or saturation (99+1=99, 0-1=0). But whatevenr you need, you need to write it yourself: C language does not provide it.

Upvotes: 1

chux
chux

Reputation: 154169

Let us keep count in countBDC.

unsigned countBCD = 0;
unsigned count = 0;
while(1){
    if((P2IN & BIT0) == BIT0){
        count++;
        countBCD++;
        if ((countBCD & 0xF) >= 0xA) {
          // of course can combine these 2 lines
          countBCD -= 0xA; 
          countBCD += 0x10;  
          if ((countBCD & 0xF0) >= 0xA0) {
            countBCD -= 0xA0;
            countBCD += 0x100;
            ...
    // similar code for decrement

or use a BCD increment function

unsigned BCD_inc(unsigned x) {
  unsigned carry = 1;
  unsigned mask10 = 10;
  unsigned maskNibble = 15;
  while (carry) {
    x += carry;
    if ((x & maskNibble) >= mask10) {
      x -= mask10;
      mask10 <<= 4;
      maskNibble <<= 4;
      carry <<= 4;
    } else {
      carry = 0;
    }
  }
  return x;
}

Upvotes: 0

AliVar
AliVar

Reputation: 169

is there any constraint on using this:

if((P2IN & BIT0) == BIT0){
    count++;
    if (count == 100)
        count = 0;
    c = dec2bcd(count);
}

else if((P2IN&BIT1) == BIT1){
    if (count == 0)
        count = 100;
    count--;
    c = dec2bcd(count);
}

Upvotes: 0

Weather Vane
Weather Vane

Reputation: 34583

I don't have a strip of LEDs handy right now, but this shows how to work within a decimal range, but only convert at the point of output. The actual value is kept in the range 0..99 (note how the modulus is done when I decrement). Then you split the value into BCD nibbles, and combine them for output.

#include <stdio.h>

void display(int num, char *msg)
{
    int lsnib = num % 10;                        // decimal value of each nibble
    int msnib = num / 10;
    int ledpatt = (msnib << 4) + lsnib;          // recombine as BCD
    printf("%02X Expected %s\n", ledpatt, msg);
}

int main(void){
    int value;

    value = 42;
    display (value, "forty two");       // display 42

    value = 0;
    display (value, "zero");            // display 0

    value = 99;
    display (value, "ninety nine");     // display 99

    value = (value + 1) % 100;          // increment from 99
    display (value, "zero");            // should display 0

    value = (value -1 + 100) % 100;     // decrement from 0
    display (value, "ninety nine");     // should display 99

    return 0;
}

Program output

42 Expected forty two
00 Expected zero
99 Expected ninety nine
00 Expected zero
99 Expected ninety nine

Upvotes: 1

Related Questions