??? 06/26/09 16:03 Read: times |
#166502 - high error rate using PS2 barcode reader |
Hi,
My first post to 8052.com. I am not entirely new to 8051 but admittedly still learning too. I am working on a project using a barcode scanner (unitech MS210LG) that uses PS2 to transmit to an infineon C515C. So the C515C is the host, and BC scanner is device. And yes I know there is example code, I have looked. I have read the PS2 protocol from here and I have code mostly working. I can get scans, make them into ASCII chars and store them - but at an unacceptable error rate. I use an interrupt tied to PS2CLK that is enabled while getting a byte. This shifts bits into a temporary char. I check for a low start bit, high stop bit and odd parity. If any of those conditions fail, then I pull PS2CLK low to force a resend from the device. Once I get all 11bits I set PS2CLK=0 and process the byte in another function. I poll this function from elsewhere in the code, and if a valid char is returned then its stored it into a idata text_buffer[]. Using this method I'm getting about 1error/1500chars. The 'errors' are typically missed shifts now. Before I added data frame checking I would get occasionally oddball chars (semicolons, random lowercase letters) now I still get some repeated chars and also incorrect digits (e.g. '3' instead of '1' or something). I don't think the trouble actually lies in the PS2 scanning, but rather in the subsequent storing of the chars. I'm wondering if there could be some subtelty about the way memory is used that could corrupt the data before/during its storage into my idata text_buffer. I have gone through the exercise of putting chars directly on the lcd from inside the getbcch() function and also from text_buffer (where they should be the exact same string) and I see errors in the text_buffer string but not the string from getbcch(). I don't want to write the bc chars directly to the text_buffer in my getbcch() function because some of the scans are 'command' characters that shouldn't be in the text_buffer. I actually have to parse the first char scanned and then choose to fill the text_buffer or not. Also I can't let the 8051 go off to lunch in getbcch() waiting for scans because I also have a keypad that needs to be sampled. The barcode may scan anywhere from 1-20 chars, with 'r' delimiting. below is a snippet of the most relevant code. As above, getbcch() is polled for new ascii chars and I just use a while loop to get them once I see the first come in. /* Number of bits in a PS2 data packet (Start + 8 bits + Odd parity + Stop) */ #define PS2DATASIZE 11 // bit locations are down-count zero justified #define PS2BIT_PARITY 1 #define PS2BIT_START 10 #define PS2BIT_LSB 9 #define PS2BIT_STOP 0 /* Special scan codes */ #define LSHIFT 0x12 /* Left-shift on PS2 keyboard */ #define RSHIFT 0x59 /* Right-shift on PS2 keyboard */ #define KEYRELEASE 0xF0 /* Preceeds key code when key released */ #define EXTENDED 0xE0 /* Used for numeric keypad & arrow keys */ #define CAPSLOCK 0x58 /* Caps Lock key code */ /* Static local variables */ static volatile _data unsigned char bc_char; /* Scan code created by ISR */ static volatile _data unsigned char bc_char_temp; /* Scan code created by ISR */ static volatile _data unsigned char bc_bit_count; /* Bit counter for ISR */ static _bit BC_CHAR_RCVD; /* Set when character has been received */ static _bit BC_SHIFT; /* Set when shift key active */ static _bit BC_KEY_RELEASE; /* Set when release code 0xF0 received */ static _bit BC_DATA_TEMP; /* Temporary storage of incoming data bit */ static _bit BC_PARITY; /* cumulative XOR of incoming bits until parity bit is reached, then 1|0 for good|bad parity */ static _bit reset_ch; // set if start,parity,stop bits are incorrect unsigned char getbcch (void) // (unsigned char pos) { register unsigned char rx_char; /* Initially assume that nothing has been received from scanner yet */ rx_char = 0; // while(rx_char != 'r' && pos < TEXT_BUF_LENGTH) // { if (BC_CHAR_RCVD) { /* A PS2 byte has been received: process it */ switch (bc_char) { case KEYRELEASE: /* Flag a key release event */ BC_KEY_RELEASE = TRUE; break; case EXTENDED: /* The "extended" code has no meaning here, so ignore it */ break; case LSHIFT: case RSHIFT: /* If the previous byte was a key release, then revert */ /* back to lower case. Otherwise, flag a shift event. */ if (BC_KEY_RELEASE) { BC_SHIFT = FALSE; BC_KEY_RELEASE = FALSE; } else { BC_SHIFT = TRUE; } break; default: /* Any other code with bit 7 set is ignored ! */ if (!(bc_char & 0x80)) { /* If this follows a key release event, just clear */ /* the key release flag */ if (BC_KEY_RELEASE) BC_KEY_RELEASE = FALSE; else { /* Otherwise get the ASCII character from the lookup table. */ /* NOTE: Illegal codes return NULL from the lookup process. */ if (BC_SHIFT) rx_char = scan2ascii_shifted[bc_char]; else rx_char = scan2ascii[bc_char]; /* if(rx_char) { // put_ch(0,pos,rx_char); text_buffer[pos++] = rx_char; msec_delay(2); // put_ch(1,pos,text_buffer[pos]); // pos++; */ // } } } break; } // if (text_buffer[pos-1] == 'r') // text_buffer[pos-1]=' '; /* Reset the bit counter in preparation for the next PS2 byte */ bc_bit_count = PS2DATASIZE; BC_CHAR_RCVD = FALSE; BC_PARITY = FALSE; reset_ch = FALSE; EX1 = TRUE; /* Enable EX1 interrupts again */ PS2DAT = TRUE; PS2CLK = TRUE; /* Unlock the scanner so that it can get more */ } // } return (rx_char); } _interrupt(2) void ps2ck_interrupt (void) { /* Shift in the data bit from PS2DAT */ #pragma asm PS2DATA equ P3.4 mov c,PS2DATA mov _BC_DATA_TEMP,c #pragma endasm switch (--bc_bit_count) { case PS2BIT_START: /* ps2 start bit should be LOW * if its not reset PS2CLK to force a resend */ if (BC_DATA_TEMP) reset_ch = TRUE; break; case PS2BIT_PARITY: /* PS2 calls for odd parity, so inverse of bitwise XOR * that has been built up in BC_PARITY should be the same * as the parity bit */ if ( ~BC_PARITY != BC_DATA_TEMP ) reset_ch = TRUE; break; case PS2BIT_STOP: /* Lock the scanner so that it doesn't send anything else */ PS2CLK = 0; /* lastly check that the stop bit is high */ if (!BC_DATA_TEMP) { reset_ch = TRUE; } else { /* Save the byte received */ bc_char = bc_char_temp; /* Flag 'getbcch()' that there is a byte ready to be processed */ BC_CHAR_RCVD = TRUE; } return; default: /* Not a start or parity bit, so shift in the data bit */ /* the lsb of the data is assigned to parity, subseqeunt * bits are xor'd. later the inverse of BC_PARITY is * compared to the parity bit of the PS2 packet */ if (bc_bit_count == PS2BIT_LSB) BC_PARITY = BC_DATA_TEMP; else BC_PARITY ^= BC_DATA_TEMP; #pragma asm mov a,_bc_char_temp mov c,_BC_DATA_TEMP rrc a mov _bc_char_temp,a #pragma endasm break; } /* any data frame errors we reset the reception parameters */ if(reset_ch) { /* ensure PS2DAT is high else the bc may be thinking a host * command is coming */ PS2DAT = 1; PS2CLK = 0; // pull low for at least 100us bc_bit_count = PS2DATASIZE; bc_char_temp = 0; BC_CHAR_RCVD = FALSE; BC_SHIFT = FALSE; BC_DATA_TEMP = 0; reset_ch = FALSE; /* put line high again to force a resend */ PS2CLK = 1; // clear the false interrupt made by messing with PS2CLK IE1 = 0; } } thanks for looking. |
Topic | Author | Date |
high error rate using PS2 barcode reader | 01/01/70 00:00 | |
Retry | 01/01/70 00:00 | |
good idea, but i've got to also check my keypad | 01/01/70 00:00 | |
Interrupt & Mainline Contention | 01/01/70 00:00 | |
thank you | 01/01/70 00:00 | |
It may work....![]() | 01/01/70 00:00 |