C51 COMPILER V6.14 MAGCARD 10/24/2002 11:10:34 PAGE 1 C51 COMPILER V6.14, COMPILATION OF MODULE MAGCARD OBJECT MODULE PLACED IN Magcard.OBJ COMPILER INVOKED BY: C:\CYGNAL\IDEFILES\C51\BIN\C51.EXE Magcard.c DB OE stmt level source 1 //----------------------------------------------------------------------------- 2 // Magcard.c 3 //----------------------------------------------------------------------------- 4 // Author: Baylor Electromechanical Systems 5 // 6 // Operates on an external 18.432 MHz oscillator. 7 // 8 // Target: Cygnal Educational Development Board / C8051F020 9 // Tool chain: KEIL C51 6.03 / KEIL EVAL C51 10 // 11 // This program receives the data stream from a magnetic card reader and 12 // outputs the data in ASCII format over a RS-232 protocol. The code is 13 // tailored for a TTL card reader that reads only the second track on standard 14 // financial transaction cards. 15 // 16 17 //----------------------------------------------------------------------------- 18 // Includes 19 //----------------------------------------------------------------------------- 20 21 #include // SFR declarations 22 #include 23 24 //----------------------------------------------------------------------------- 25 // 16-bit SFR Definitions for 'F02x 26 //----------------------------------------------------------------------------- 27 28 sfr16 DP = 0x82; // data pointer 29 sfr16 TMR3RL = 0x92; // Timer3 reload value 30 sfr16 TMR3 = 0x94; // Timer3 counter 31 sfr16 ADC0 = 0xbe; // ADC0 data 32 sfr16 ADC0GT = 0xc4; // ADC0 greater than window 33 sfr16 ADC0LT = 0xc6; // ADC0 less than window 34 sfr16 RCAP2 = 0xca; // Timer2 capture/reload 35 sfr16 T2 = 0xcc; // Timer2 36 sfr16 RCAP4 = 0xe4; // Timer4 capture/reload 37 sfr16 T4 = 0xf4; // Timer4 38 sfr16 DAC0 = 0xd2; // DAC0 data 39 sfr16 DAC1 = 0xd5; // DAC1 data 40 41 42 //----------------------------------------------------------------------------- 43 // Global CONSTANTS 44 //----------------------------------------------------------------------------- 45 46 #define BAUDRATE 9600 // Baud rate of UART in bps 47 #define SYSCLK 18432000 // SYSCLK frequency in Hz 48 49 sbit LED = P1^6; // LED='1' means ON 50 sbit STROBE = P0^2; 51 sbit DATA = P0^3; 52 sbit CARD = P0^4; 53 54 // Lookup table for converting keycode to ASCII 55 unsigned int keytab[4][4] ={{'1','2','3','A'}, C51 COMPILER V6.14 MAGCARD 10/24/2002 11:10:34 PAGE 2 56 {'4','5','6','B'}, 57 {'7','8','9','C'}, 58 {'*','0','#','D'}}; 59 60 61 //----------------------------------------------------------------------------- 62 // Function PROTOTYPES 63 //----------------------------------------------------------------------------- 64 65 void SYSCLK_Init (void); 66 void PORT_Init (void); 67 void INT0_ISR (void); 68 void UART0_Init (void); 69 int button_dn(void); 70 unsigned int scankey (void); 71 void delay_ms(int ms); 72 73 74 //----------------------------------------------------------------------------- 75 // Global VARIABLES 76 //----------------------------------------------------------------------------- 77 bit inbit; 78 bit ended = 0; 79 bit started = 0; 80 bit transmit_now = 0; 81 int char_index = 0; 82 int bit_index = 0; 83 int num_chars = 0; 84 int parity_errors = 0; 85 bit parity = 1; 86 87 char char_data; 88 char track2[40]; 89 90 char bdata error_temp = 0; // bit-addressable character location 91 sbit bit0 = error_temp^0; // parity bit (bit 4) of error_temp 92 93 94 95 //----------------------------------------------------------------------------- 96 // MAIN Routine 97 //----------------------------------------------------------------------------- 98 99 void main (void) 100 { 101 1 unsigned int rd1; 102 1 bit scrolling=1; 103 1 104 1 WDTCN = 0xde; // disable watchdog timer 105 1 WDTCN = 0xad; 106 1 107 1 SYSCLK_Init (); // initialize oscillator 108 1 PORT_Init (); // initialize crossbar and GPIO 109 1 UART0_Init (); // initialize UART0 110 1 EA = 1; // Enable global interrupts 111 1 112 1 113 1 while (1) 114 1 { 115 2 116 2 putchar (254); 117 2 putchar (0x01); C51 COMPILER V6.14 MAGCARD 10/24/2002 11:10:34 PAGE 3 118 2 printf(" Swipe Card...\n"); 119 2 while (transmit_now==0) // wait for transmit state to be set 120 2 { } 121 2 122 2 parity_errors=0; 123 2 for (char_index=0; char_index>1; 135 4 } 136 3 if (parity) parity_errors++; // if "parity" <> 0, then 137 3 // parity error in character 138 3 139 3 // ----- SEND CHARACTERS TO DISPLAY -----// 140 3 char_data = track2[char_index]; 141 3 char_data &= 0x0F; // clear parity bit 142 3 char_data += 0x30; // add ASCII offset 143 3 144 3 if ((char_data!=';')&&(char_data!='?')) // suppress start 145 3 // and end sentinels 146 3 putchar(char_data); // send character to display 147 3 } 148 2 149 2 150 2 while (CARD==0) // wait for card load line to go high 151 2 { } 152 2 153 2 transmit_now=0; 154 2 started=0; 155 2 ended=0; 156 2 scrolling=1; 157 2 158 2 while (scrolling) 159 2 { 160 3 if(button_dn()) // check for key press 161 3 { 162 4 delay_ms(5); // delay for debouncing 163 4 rd1 = scankey(); // read keypad 164 4 if(rd1 != 0) 165 4 { 166 5 if (rd1=='*') 167 5 { 168 6 putchar (254); 169 6 putchar (28); 170 6 } 171 5 if (rd1=='#') 172 5 { 173 6 putchar (254); 174 6 putchar (24); 175 6 } 176 5 if (rd1=='0') scrolling=0; 177 5 } 178 4 } 179 3 delay_ms(250); C51 COMPILER V6.14 MAGCARD 10/24/2002 11:10:34 PAGE 4 180 3 } 181 2 182 2 } 183 1 } 184 185 //----------------------------------------------------------------------------- 186 // Initialization Subroutines 187 //----------------------------------------------------------------------------- 188 189 //----------------------------------------------------------------------------- 190 // SYSCLK_Init 191 //----------------------------------------------------------------------------- 192 // 193 // This routine initializes the system clock to use an 18.432 MHz crystal 194 // as its clock source. 195 // 196 197 void SYSCLK_Init (void) 198 { 199 1 int i; // delay counter 200 1 OSCXCN = 0x67; // start external oscillator with 201 1 // 18.432MHz crystal 202 1 for (i=0; i < 256; i++) ; // XTLVLD blanking interval (>1ms) 203 1 while (!(OSCXCN & 0x80)) ; // Wait for crystal osc. to settle 204 1 OSCICN = 0x88; // select external oscillator as SYSCLK 205 1 // source and enable missing clock 206 1 // detector 207 1 } 208 209 //----------------------------------------------------------------------------- 210 // PORT_Init 211 //----------------------------------------------------------------------------- 212 void PORT_Init (void) 213 // Configure the Crossbar and GPIO ports 214 { 215 1 // DIGITAL CROSSBAR CONFIGURATION 216 1 XBR0 = 0x04; // XBAR0: Initial Reset Value 217 1 XBR1 = 0x04; // XBAR1: INT0 Input Enable 218 1 XBR2 = 0x40; // XBAR2: Enable weak pull-ups 219 1 220 1 221 1 P0MDOUT = 0x01; // PORT 0 CONFIGURATION 222 1 // P0.0 = UART TX0 (Push-Pull Output) 223 1 // P0.1 = UART RX0 (Open-Drain Output/Input) 224 1 // P0.2 = /INT0 - /Strobe (Open-Drain Output/Input) 225 1 // P0.3 = /Data (Open-Drain Output/Input) 226 1 // P0.4 = /Card Present (Open-Drain Output/Input) 227 1 // P0.5 = unassigned (Open-Drain Output/Input) 228 1 // P0.6 = unassigned (Open-Drain Output/Input) 229 1 // P0.7 = unassigned (Open-Drain Output/Input) 230 1 231 1 // PORT 1 CONFIGURATION 232 1 P1MDOUT = 0x40; // P1.6 (LED) is push-pull output 233 1 234 1 P2MDOUT = 0xF0; // P2 u.n. push pull, lower-nibble input 235 1 P2 = 0x0F; // upper nibble hi-imp, allowing input read 236 1 237 1 238 1 // INTERRUPT CONFIGURATION 239 1 IE = 0x01; // Enable INT0 External Interrupt 240 1 IT0 = 1; // INT0 External Interrupt on falling edges 241 1 } C51 COMPILER V6.14 MAGCARD 10/24/2002 11:10:34 PAGE 5 242 243 //----------------------------------------------------------------------------- 244 // UART0_Init 245 //----------------------------------------------------------------------------- 246 // 247 // Configure the UART0 using Timer1, for and 8-N-1. 248 // 249 250 void UART0_Init (void) 251 // Configure the UART0 using Timer1, for and 8-N-1. 252 253 { 254 1 SCON0 = 0x50; // SCON0: mode 1, 8-bit UART, enable RX 255 1 TMOD = 0x20; // TMOD: timer 1, mode 2, 8-bit reload 256 1 TH1 = -(SYSCLK/BAUDRATE/16); // set Timer1 reload value for baudrate 257 1 TR1 = 1; // start Timer1 258 1 CKCON |= 0x10; // Timer1 uses SYSCLK as time base 259 1 PCON |= 0x80; // SMOD00 = 1 260 1 TI0 = 1; // Indicate TX0 ready 261 1 } 262 263 264 //----------------------------------------------------------------------------- 265 // Interrupt Service Routines 266 //----------------------------------------------------------------------------- 267 268 //----------------------------------------------------------------------------- 269 // INT0_ISR 270 //----------------------------------------------------------------------------- 271 // 272 // INT0 External Interrupt ISR 273 // 274 275 void INT0_ISR (void) interrupt 0 276 // INT0 External Interrupt Routine 277 // When first nonzero bit on the data line is detected, this routine 278 // enables the input state by setting the "started" flag. Successive 279 // bits are added to the track2 array in 5 bit characters. After each 280 // character is added, this routine compares the character to the end 281 // sentinel [1111]. Once the end sentinel is detected, the routine 282 // disables the input state by setting the "ended" flag, and begins the 283 // transmission state by 284 { 285 1 IE0 = 0; // Clear INT0 interrupt flag 286 1 287 1 if (DATA) inbit = 0; 288 1 else inbit = 1; // invert logic on data line 289 1 290 1 if ((inbit==1)&&(!started)) // first nonzero bit is detected 291 1 { 292 2 started=1; // initialize state variables 293 2 ended=0; 294 2 char_index=0; 295 2 bit_index=0; 296 2 297 2 putchar (254); 298 2 putchar (0x02); 299 2 300 2 } 301 1 302 1 if ((started)&&(!ended)) // input state has been started 303 1 { // and has not yet been ended C51 COMPILER V6.14 MAGCARD 10/24/2002 11:10:34 PAGE 6 304 2 char_data = track2[char_index]; 305 2 char_data = char_data>>1; 306 2 if (inbit) char_data |= 0x10; // add a '1' bit to current character 307 2 else char_data &= 0x0F; // add a '0' bit to current character 308 2 track2[char_index] = char_data; 309 2 bit_index++; // increment the bit index 310 2 311 2 if (bit_index==5) 312 2 { 313 3 char_index++; // move to next chararacter in track2 314 3 bit_index=0; // reset the bit index 315 3 char_data &= 0x1F; // clear the 3 MSB 316 3 ended = (char_data==0x1F); // check for end sentinel [11111] 317 3 318 3 if (ended) // end sentinel has been detected 319 3 { 320 4 num_chars=char_index; // note the number of track2 characters 321 4 transmit_now=1; // enable the transmission state 322 4 } 323 3 324 3 } 325 2 326 2 } 327 1 328 1 } // end INT0_ISR 329 330 //----------------------------------------------------------------------------- 331 // Local Functions 332 //----------------------------------------------------------------------------- 333 334 //----------------------------------------------------------------------------- 335 // button_dn 336 //----------------------------------------------------------------------------- 337 // 338 // Function: test keypad for the presence of a key press. 339 // Return: 1 if keypress; 0 otherwise. 340 341 int button_dn() 342 { 343 1 int tmp; 344 1 tmp = (P2 & 0x0F)^0x0F; // read P2.3->P2.0 and XOR output 345 1 346 1 if(tmp) // if button is depressed, tmp != 0 347 1 return 1; 348 1 else 349 1 return 0; 350 1 } 351 352 //----------------------------------------------------------------------------- 353 // scankey 354 //----------------------------------------------------------------------------- 355 // 356 // Function: read keypad and convert keypress into equiv. ASCII code. 357 // Return: ASCII equivalent of pressed key's label. 358 359 unsigned int scankey(void) 360 { 361 1 int row = 0; 362 1 int col = 0; 363 1 int k,j; 364 1 365 1 P2 = 0x0F; // set data register C51 COMPILER V6.14 MAGCARD 10/24/2002 11:10:34 PAGE 7 366 1 P2MDOUT = 0xF0; // drive P2.3->P2.0 as output 367 1 delay_ms(10); // let drive signals settle 368 1 369 1 row = (P2 & 0x0F)^0x0F; // read P2.3->P2.0 and XOR output 370 1 371 1 delay_ms(2); 372 1 373 1 if(row == 0) 374 1 return 0; // no closure detected 375 1 376 1 P2 = 0xF0; // set data register 377 1 P2MDOUT = 0x0F; // drive P2.7->P2.4 as output 378 1 delay_ms(2); // let drive signals settle 379 1 380 1 col = (P2 & 0xF0)^0xF0; // P2.7->P2.4 and XOR output 381 1 col = col >> 4; // move hi nibble to lo nibble 382 1 383 1 if(col == 0) 384 1 return 0; // no closure detected 385 1 386 1 P2 = 0x0F; // set data register 387 1 P2MDOUT = 0xF0; // drive P2.3->P2.0 as output 388 1 delay_ms(2); // let drive signals settle 389 1 390 1 switch(row) // convert 1-of-4 to binary 391 1 { 392 2 case 1: j = 0; break; 393 2 case 2: j = 1; break; 394 2 case 4: j = 2; break; 395 2 case 8: j = 3; break; 396 2 default: return 0; 397 2 } 398 1 399 1 switch(col) // convert 1-of-4 to binary 400 1 { 401 2 case 1: k = 0; break; 402 2 case 2: k = 1; break; 403 2 case 4: k = 2; break; 404 2 case 8: k = 3; break; 405 2 default: return 0; 406 2 } 407 1 408 1 return keytab[j][k]; // return the ASCII value at that row and column 409 1 } 410 411 //----------------------------------------------------------------------------- 412 // delay_ms 413 //----------------------------------------------------------------------------- 414 // 415 // Function: approximate x ms delay 416 // Return: void 417 418 void delay_ms(int ms) 419 { 420 1 int y; 421 1 int z; 422 1 for (y=1; y<=250; y++) for (z=1; z<= ms; z++); 423 1 } MODULE INFORMATION: STATIC OVERLAYABLE CODE SIZE = 822 ---- C51 COMPILER V6.14 MAGCARD 10/24/2002 11:10:34 PAGE 8 CONSTANT SIZE = 16 ---- XDATA SIZE = ---- ---- PDATA SIZE = ---- ---- DATA SIZE = 82 10 IDATA SIZE = ---- ---- BIT SIZE = 5 1 END OF MODULE INFORMATION. C51 COMPILATION COMPLETE. 0 WARNING(S), 0 ERROR(S)