Dear Bigmac

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Dear Bigmac

8,618 Views
ganimides
Contributor I
Dear Bigmac, sorry if I`m bothering with my stuff but I`m doing my best to be abel to learn about C coding and I see you are a very good teacher ...   :smileyhappy:
 
SO I have a  problem trying to translate this asembly code into C coding.
 
 
I attached for you the piece of code so that you can tke a look so how would you do this in C?.
 
 
 
SUper thank you!!!!.
 
 
Ganimides.
 
 
 
 .
Labels (1)
0 Kudos
12 Replies

1,780 Views
Ware
Contributor III
 
There are probably a few ways to do this, but here is my solution:
 
Code:
#define OUT1 0#define REPLY 1unsigned char HexDW[6];  // globalsunsigned char BitCntr;// returns OUT1 or REPLYchar function(void){    unsigned char i, j, mask;    mask = 0x10;  // bit 4    for(i=0; i>=25; i++)    {        if(i==BitCntr)        {            HexDW[j] |= mask;  // set the correct bit            break;  // done        }        mask = mask >> 1;  // shift mask        if(mask == 0)         {            j++;  // next element in HexDW[] array            if(j==5) mask = 0x10;  // first and last element starts with bit 4            else mask = 0x08;  // start with bit 3        }    }    BitCntr++;    if(BitCntr>0x1A) return OUT1;    T2SC &= ~0x40;  // clear bit 6 of T2SC    return REPLY;}

 
It would help if the code had comments...  but that should work as a generic solution.
USAGE:
 
Code:
 result = function(); if(result==OUT1) do_out1_function(); else do_reply_function();

 
Regards,
 - Ware
 

 
0 Kudos

1,780 Views
ganimides
Contributor I
Thank you very very much friend Ware!!.
 
Look I`m a beginner into C coding and as exercise I tried last week to translate some interesting program I like into C coding.The only routine needed was the one I mentioned you here.
 
Can I ask you a favor?...look,I have written this piece of C coding trying to translate it from a piece of asembly one.Could you just correct it to learn some more and to be able to see where I commited the errors?.
 
Here  I attached for you the two codes so that you can see it.
 
 
Thanks a lot buddy!.
 
GAnimides.
 
 
 
 
0 Kudos

1,780 Views
bigmac
Specialist III
Hello Ganimides,
 
The assembly code shown in the file Wiegand26.asm seems to actually refer to the 31-bit Wiegand protocol, rather than the 26-bit protocol that you appear to require.  Additionally, by attempting to separate the raw data, as received, into only the lower nybble of a number of byte registers has resulted in code that is much more complex than it needs to be.  This is probably not a good example to attempt to convert to C code.
 
A simpler approach, and assuming a 26-bit protocol with 24 data bits, would be to shift the data bits into a three byte register.  The separation into six nybbles, to represent either hexadecimal or BCD data, and the conversion to ASCII characters, can then be done once the data accumulation is complete, and outside of any ISR.  This is quite a simple process.  I am assuming that the first and last (parity) bits of the sequence would simply be ignored.
 
There appears to be no particular advantage to consuming a pair of timer channels to detect the data pulses.  I would probably consider using the keyboard interrupt facility.  You will still need to monitor timer overflow to detect timeout of the Wiegand sequence.
 
Here are some untested assembly code snippets to demonstrate the simplification.  I have not shown initialisation for the DATA0 and DATA1 input pins, the KB module, or the timer.
 
The following page 0 RAM registers are used within the code -
 
         ORG    RAM
OVFCNT    DS     1      ; TIM overflow counter
BITCNT    DS     1      ; Bit counter
DATREG    DS     3      ; Register for Wiegand data
 
The following code would be required within the main loop -
 
         LDA    BITCNT
         CMP    #25           ; Test for new data available
         BNE    ML1           ; Branch if not
         LDA    DATREG
         JSR    DISPHEX       ; Display byte as hexadecimal
         LDA    DATREG+1
         JSR    DISPHEX       ; Display byte as hexadecimal
         LDA    DATREG+2
         JSR    DISPHEX       ; Display byte as hexadecimal
 
         ; Clear registers for next reading
         CLR    DATREG
         CLR    DATREG+1
         CLR    DATREG+2
         CLR    BITCNT
 
         BSET   ACKK,KBSCR     ; Clear KB flag
         BCLR   IMASKK,KBSCR   ; Enable KB interrupts
ML1:
 
Here are the supporting sub-routines used.  The SENDCHR routine sends a single ASCII character to a suitable display device, e.g. LCD display, or perhaps SCI.
 
***************************************************************
* DISPLAY BYTE AS HEXADECIMAL VALUE
* On entry, ACC = byte value
***************************************************************
 
DISPHEX: PSHA                  ; Save value for later
         JSR    UHEX2ASC       ; Convert upper nybble
         JSR    SENDCHR        ; Display character
         PULA
         JSR    LHEX2ASC       ; Convert lower nybble
         JSR    SENDCHR        ; Display character
         RTS
 
***************************************************************
* CONVERT NYBBLE VALUE TO ASCII
* On entry, ACC = byte value for conversion
***************************************************************
 
LHEX2ASC: ; Convert lower nybble
         AND #$0F
         BRA    H2A1           ; Branch always
 
UHEX2ASC: ; Convert upper nybble
         LSRA
         LSRA
         LSRA
         LSRA
H2A1:    CMP    #9
         BLS    *+4            ; Skip next if numeric value
         ADD    #7
         ADD    #'0'           ; Convert to ASCII value
         RTS
 
And now for the ISR code -
 
***************************************************************
* KEYBOARD ISR
***************************************************************
 
KB_ISR:  CLR    OVFCNT         ; Clear TIM overflow count
         LDA    BITCNT
         BEQ    KBI1           ; Branch if first parity bit
         BRCLR  DATA0,PTA,*+3  ; Set/clear CF - current bit state
         ROL    DATREG+2
         ROL    DATREG+1
         ROL    DATREG
KBI1:    INC    BITCNT
         LDA    BITCNT
         CMP    #25            ; Test for last data bit
         BLO    KBI2           ; Exit if not
         BSET   IMASKK,KBSCR   ; Mask further KB interrupts
KBI2:    BSET   ACKK,KBSCR     ; Clear KB flag
         RTI
 
***************************************************************
* TIMER OVERFLOW ISR
***************************************************************
 
TIM_ISR: TST    BITCNT
         BEQ    TIR2           ; Exit if already initialised
         TST    OVFCNT
         BNE    TIR1           ; Branch if prior overflow
         INC    OVFCNT         ; Increment value
         BRA    TIR2           ; Exit always
TIR1:    LDA    BITCNT
         CMP    #25            ; Test for data complete
         BHS    TIR2           ; Exit if so
 
         ; Premature timeout for end of data
         CLR    DATREG
         CLR    DATREG+1
         CLR    DATREG+2
         CLR    BITCNT
 
TIR2:    BCLR   TOF,TSC        ; Clear TIM overflow flag
         RTI
 
Regards,
Mac
 

Message Edited by bigmac on 2006-09-2901:40 PM

0 Kudos

1,781 Views
ganimides
Contributor I
Dear Bigmac,athank you for your reliable explanation as always.You are one of those amazing people in this forum who helps me every time I need.
 
have a really nice weekend in company of the people who loves you.
 
Bye!.
 
 
Ganimides
 
 
0 Kudos

1,781 Views
Ware
Contributor III
 
This would not fit in private message:
 
Code:
const char RFID[] = {'0','0','0','0','0','4','4','7','8','F'};void hexstr2decstr(char *hexstr, char *decstr);char RFIDdec[10];    // ...void main(void) {    // ...    hexstr2decstr(RFID, RFIDdec); //hex ASCII string to dec ASCII string    // ...}void hexstr2decstr(char *hexstr, char *decstr){unsigned char i;unsigned long decimal;    // first convert hex ASCII string to a number    decimal = 0;    for(i=0; i<10; i++)    {        decimal = decimal << 4;                             // shift previous digits right 4bits        if(hexstr[i]>'f') ;                                 // ERROR ('e' thru '~')        else if(hexstr[i]>='a') decimal += hexstr[i] - 87;  // convert lower-case ASCII to #        else if(hexstr[i]>'F') ;                            // ERROR ('E' thru '`')        else if(hexstr[i]>='A') decimal += hexstr[i] - 55;  // convert UPPER-CASE ASCII to #        else if(hexstr[i]>'9') ;                            // ERROR (':' thru '@')        else decimal += hexstr[i] - 0x30;                   // convert numeric ASCII to #    }        //now convert decimal number to a ASCII string    for(i=9; i!=0; i--)    {        if(decimal==0) decstr[i]=0x20;      // space character        else         {            decstr[i]= (decimal%10)+0x30;   // convert current digit to ASCII            decimal = decimal / 10;         // next digit        }    }}

 
Regards,
 - Ware
0 Kudos

1,781 Views
ganimides
Contributor I
Dear Ware,thank you very ,very ,very,very much for your reliable contribution!.Sorry but I couldn`t reply to thank you before.
 
I`ll test it and  I`m sure it`s gonna work out.
 
 
Kindly regards.
 
 
Ganimides
0 Kudos

1,781 Views
bigmac
Specialist III
Hello Ganimides,

Ganimides wrote in a sequence of PMs -
 
HEX to DECIMAL routine.
 
I just wanted to code in C lenguage some kind of routine to convert HEX to DECIMAL routine. How should I write this example in C?
 
5CB2h = 2*1 + 11*16 + 12*256 + 5*4096 = 23730
 
I have a LCD routine that converts to ASCII by a functions called
Datos4bits((value%10) +0x30);
 
How Do I put the Hex to decimal routine into my LCD routine?.
 
------------
I get the data delivered from a proximity card reader in HEXA.I made an array of 10 elements each one of 8 bits. These 11 elements are according to the ID card and these are 5 bytes. When I start up my routine reads the data string and is ddisplayed in HEX format.
 
For example my personal card delivers 2548D4 in hexa when I read on my LCD but in decimal it`s 2443476 that it is my real card numer identifying me.
 
I just need some routine that converts this HEXA into decimal so that my LCD shows 2443476.
 
------------
My array is about 10 elements each one of 1 byte as follows:
RFID [0]=02
RFID [1]=05
RFID [2]=04
RFID [3]=08
RFID [4]=0D
RFID [5]=04
 
I need to convert it to decimal and show it to my LCD in decimal format. THe equivalent would be 2443476 (this is my real personal card) but nowaday I`m showing 2548D4 on my LCD display.

Your raw data within the array RFID occupies the first six bytes of the array, with only the lower nybble of each byte being significant.  These nybble values are strictly 4-bit binary values that you have chosen to express as hexadecimal digits, a convenient "shorthand".
 
I would suggest that the display task occur in the following stages -
  1. Combine the nybble data within RFID, to give a 24-bit binary value.  In C, this would be expressed as an unsigned long or dword value (32 bits length).
  2. Convert the binary value to a "packed BCD" format of up to 8 digits, contained in four bytes (dword value).
  3. Unpack each BCD value, convert to ASCII, and display the value to LCD.  Alternatively, each ASCII value could be entered in a string array, and the whole string then sent to the LCD.
The attached code attempts to demonstrate this process.  I have actually chosen to accumulate the ASCII characters within a string array variable.  This process has similarities to that you have previously used to display the contents of a RTC device.
 
The function I have used to convert to packed BCD format should be more compact and faster than other alternatives that use integer divide operations.
 
Regards,
Mac
 

Message Edited by bigmac on 2006-11-2203:05 PM

0 Kudos

1,781 Views
Alban
Senior Contributor II
It's very good it doesn't fit in PM:
Everyone can benefit from it, this way :smileyhappy:
 
 
 
0 Kudos

1,781 Views
Ware
Contributor III
First...  "unsigned long" is only 4 bytes...  so I would go with a 5 element array (myself).
 
In C you cannot address bytes within a "long" like you do here:
Code:
                     printf_LCD_4bits (1,1,"",hexDW);                     printf_LCD_4bits (1,2,"",hexDW+1);                     printf_LCD_4bits (1,3,"",hexDW+2);                     printf_LCD_4bits (1,4,"",hexDW+3);                     printf_LCD_4bits (1,5,"",hexDW+4);
 
 

 Instead (asumming big-endian):
 
Code:
                     printf_LCD_4bits (1,1,"",hexDW&0xFF);                     printf_LCD_4bits (1,2,"",(hexDW>>8)&0xFF);                     printf_LCD_4bits (1,3,"",(hexDW>>16)0xFF);                     printf_LCD_4bits (1,4,"",(hexDW>>24)0xFF);//cant do 5th byte   printf_LCD_4bits (1,5,"",hexDW+4);

 
As you can see this is complex (the array method is more simple and can include a 5th byte easily).
Code:
                     printf_LCD_4bits (1,1,"",hexDW[0]);                     printf_LCD_4bits (1,2,"",hexDW[1]);                     printf_LCD_4bits (1,3,"",hexDW[2]);                     printf_LCD_4bits (1,4,"",hexDW[3]);                     printf_LCD_4bits (1,5,"",hexDW[4]);

 
These corrections need to be made everywhere else "hexDW" is referenced (such as the ISR).
 
Regards,
 - Ware
 
 
0 Kudos

1,781 Views
ganimides
Contributor I
Dear Ware,my printf_LCD_4bits () function converts automatically the value passed directly to ASCII  because I use it to send the chars to my LCD display.
 
In this routine ,what would you change ?.
 
Code:
void printf_LCD_4bits(unsigned char fila, unsigned char columna, char *texto, char value){ unsigned char adrs;                                                                      adrs = columna - 1;  if(fila == 2)   adrs = adrs | 0x40; Ctrl4bits(adrs | 0x80); while(*texto)   Datos4bits(*texto++); // Datos4bits(':');//Datos4bits( ((value%10000)/1000)+0x30);//Datos4bits( ((value%1000)/100)+0x30);//Datos4bits( ((value%100)/10)+0x30);Datos4bits( (value%10)+0x30);}

 
Message Edited by ganimides on 2006-09-2610:49 AM

Message Edited by Alban on 2006-09-26 04:53 PM

0 Kudos

1,781 Views
Ware
Contributor III
 
From your first message, it looks as if bit 4 of hexDW can be set (so the value could be as high as 16)...  but if you only care about values 0 to 9, that should work (assuming Datos4bits() works) .
 
If not, try:
Code:
if(value>9) Datos4bits(0x31);Datos4bits( (value%10)+0x30);
Regards,
  - WARE
0 Kudos

1,781 Views
ganimides
Contributor I
zanks a lot ware for your reliable explanations.
 
Have a nice week!.
 
Ganimides
0 Kudos