C51 COMPILER V6.14 DAC1_FGEN1 03/07/2003 11:10:06 PAGE 1 C51 COMPILER V6.14, COMPILATION OF MODULE DAC1_FGEN1 OBJECT MODULE PLACED IN DAC1_fgen1.OBJ COMPILER INVOKED BY: C:\CYGNAL\IDEFILES\C51\BIN\C51.EXE DAC1_fgen1.c DB OE stmt level source 1 //----------------------------------------------------------------------------- 2 // DAC1_fgen1.c 3 //----------------------------------------------------------------------------- 4 // 5 // AUTH: BW,FB 6 // DATE: 2 OCT 01 7 // 8 // Target: C8051F02x 9 // Tool chain: KEIL C51 10 // 11 // Description: 12 // Example source code which outputs waveforms on DAC1. DAC1's output is 13 // scheduled to update at a rate determined by the constant 14 // , managed and timed by Timer4. 15 // 16 // Implements a 256-entry full-cycle sine table of 16-bit precision. Other 17 // waveforms supported are square, triangle, and saw tooth. 18 // 19 // The output frequency is determined by a 16-bit phase adder. 20 // At each DAC update cycle, the phase adder value is added to a running 21 // phase accumulator, , the upper bits of which are used 22 // to access the sine lookup table. 23 // 24 // The program is controlled through UART using HyperTerminal running on a 25 // PC. All commands are two characters in length and have optional 26 // frequency and amplitude arguments. Note that the amplitude parameter 27 // cannot be specified unless the frequency is also specified. 28 // 29 // Command Format: 30 // 31 // XX [frequency] [amplitude] 32 // 33 // where XX denotes the command 34 // 35 // Command List: 36 // 37 // SQ - Square Wave 38 // SI - Sine Wave 39 // TR - Triangle Wave 40 // SA - Saw Tooth Wave 41 // OF - Output OFF 42 // ?? - Help 43 44 //----------------------------------------------------------------------------- 45 // Includes 46 //----------------------------------------------------------------------------- 47 48 #include // SFR declarations 49 #include 50 #include 51 #include 52 #include 53 54 //----------------------------------------------------------------------------- 55 // 16-bit SFR Definitions for 'F02x C51 COMPILER V6.14 DAC1_FGEN1 03/07/2003 11:10:06 PAGE 2 56 //----------------------------------------------------------------------------- 57 58 sfr16 DP = 0x82; // data pointer 59 sfr16 TMR3RL = 0x92; // Timer3 reload value 60 sfr16 TMR3 = 0x94; // Timer3 counter 61 sfr16 ADC0 = 0xbe; // ADC0 data 62 sfr16 ADC0GT = 0xc4; // ADC0 greater than window 63 sfr16 ADC0LT = 0xc6; // ADC0 less than window 64 sfr16 RCAP2 = 0xca; // Timer2 capture/reload 65 sfr16 T2 = 0xcc; // Timer2 66 sfr16 RCAP4 = 0xe4; // Timer4 capture/reload 67 sfr16 T4 = 0xf4; // Timer4 68 sfr16 DAC0 = 0xd2; // DAC0 data 69 sfr16 DAC1 = 0xd5; // DAC1 data 70 71 //----------------------------------------------------------------------------- 72 // Function PROTOTYPES 73 //----------------------------------------------------------------------------- 74 75 void main (void); 76 void SYSCLK_Init (void); 77 void PORT_Init (void); 78 void UART0_Init (void); 79 80 void Timer4_Init (int counts); 81 void Timer4_ISR (void); 82 long pow(int x, int y); 83 void Print_Command_List(void); 84 85 void Sine(void); 86 void Square(void); 87 void Triangle(void); 88 void Saw(void); 89 void Off(void); 90 void Help(void); 91 void Error(void); 92 93 //----------------------------------------------------------------------------- 94 // Global CONSTANTS 95 //----------------------------------------------------------------------------- 96 97 #define SYSCLK 22118400 // SYSCLK frequency in Hz 98 99 #define BAUDRATE 9600 // Baud rate of UART in bps 100 101 #define SAMPLE_RATE_DAC 80000L // DAC sampling rate in Hz 102 103 #define PHASE_PRECISION 65536 // range of phase accumulator 104 105 #define command_length 2 // command length is 2 characters 106 #define command_size 3 // command size is 3 bytes 107 108 typedef struct Command_Table_Type { // when a command is entered, it is 109 char command[command_size]; // compared to the command field of 110 void (*function_ptr)(void); // of the table. If there is a match 111 }Command_Table_Type; // then the the function located at 112 // function_ptr will be executed 113 114 typedef enum Waveform { // the different possible output 115 SQUARE, // waveforms 116 SINE, 117 TRIANGLE, C51 COMPILER V6.14 DAC1_FGEN1 03/07/2003 11:10:06 PAGE 3 118 SAW, 119 OFF 120 }Waveform; 121 122 typedef union lng { // access a long variable as two 123 long Long; // 16-bit integer values 124 int Int[2]; 125 } lng; 126 127 128 129 //----------------------------------------------------------------------------- 130 // Global Variables 131 //----------------------------------------------------------------------------- 132 133 134 unsigned long frequency = 1000; // frequency of output in Hz, 135 // defaults to 1000 Hz 136 137 unsigned int phase_add = 1000 * PHASE_PRECISION / SAMPLE_RATE_DAC; 138 139 unsigned int amplitude = 100 * 655; // 655 is a scaling factor 140 // see the Timer 4 ISR 141 Waveform output_waveform = OFF; 142 143 144 char input_str[16]= ""; 145 146 #define num_commands 6 147 Command_Table_Type code function_table[num_commands + 1] = { 148 {"SQ", Square}, 149 {"SI", Sine}, 150 {"TR", Triangle}, 151 {"SA", Saw}, 152 {"OF", Off}, 153 {"??", Help}, 154 {"", Error} 155 }; 156 157 // a full cycle, 16-bit, 2's complement sine wave lookup table 158 int code SINE_TABLE[256] = { 159 160 0x0000, 0x0324, 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2, 161 0x18f8, 0x1c0b, 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, 162 0x30fb, 0x33de, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, 163 0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, 164 0x5a82, 0x5cb4, 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6, 165 0x6a6d, 0x6c24, 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504, 166 0x7641, 0x776c, 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3, 167 0x7d8a, 0x7e1d, 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6, 168 0x7fff, 0x7ff6, 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 169 0x7d8a, 0x7ce3, 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 170 0x7641, 0x7504, 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 171 0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 172 0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 173 0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 174 0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 175 0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, 176 0x0000, 0xfcdc, 0xf9b9, 0xf696, 0xf375, 0xf055, 0xed38, 0xea1e, 177 0xe708, 0xe3f5, 0xe0e7, 0xdddd, 0xdad8, 0xd7da, 0xd4e1, 0xd1ef, 178 0xcf05, 0xcc22, 0xc946, 0xc674, 0xc3aa, 0xc0e9, 0xbe32, 0xbb86, 179 0xb8e4, 0xb64c, 0xb3c1, 0xb141, 0xaecd, 0xac65, 0xaa0b, 0xa7be, C51 COMPILER V6.14 DAC1_FGEN1 03/07/2003 11:10:06 PAGE 4 180 0xa57e, 0xa34c, 0xa129, 0x9f14, 0x9d0e, 0x9b18, 0x9931, 0x975a, 181 0x9593, 0x93dc, 0x9236, 0x90a1, 0x8f1e, 0x8dab, 0x8c4b, 0x8afc, 182 0x89bf, 0x8894, 0x877c, 0x8676, 0x8583, 0x84a3, 0x83d7, 0x831d, 183 0x8276, 0x81e3, 0x8163, 0x80f7, 0x809e, 0x8059, 0x8028, 0x800a, 184 0x8000, 0x800a, 0x8028, 0x8059, 0x809e, 0x80f7, 0x8163, 0x81e3, 185 0x8276, 0x831d, 0x83d7, 0x84a3, 0x8583, 0x8676, 0x877c, 0x8894, 186 0x89bf, 0x8afc, 0x8c4b, 0x8dab, 0x8f1e, 0x90a1, 0x9236, 0x93dc, 187 0x9593, 0x975a, 0x9931, 0x9b18, 0x9d0e, 0x9f14, 0xa129, 0xa34c, 188 0xa57e, 0xa7be, 0xaa0b, 0xac65, 0xaecd, 0xb141, 0xb3c1, 0xb64c, 189 0xb8e4, 0xbb86, 0xbe32, 0xc0e9, 0xc3aa, 0xc674, 0xc946, 0xcc22, 190 0xcf05, 0xd1ef, 0xd4e1, 0xd7da, 0xdad8, 0xdddd, 0xe0e7, 0xe3f5, 191 0xe708, 0xea1e, 0xed38, 0xf055, 0xf375, 0xf696, 0xf9b9, 0xfcdc, 192 }; 193 194 code char string0[] = "\n\n*** OUTPUT IS NOW A "; 195 code char string1[] = "\n\n----------------------------------\n\n"; 196 197 198 //----------------------------------------------------------------------------- 199 // MAIN Routine 200 //----------------------------------------------------------------------------- 201 202 void main (void) { 203 1 204 1 char i; // counting variable 205 1 char* arg_ptr1; // pointers to command line parameters 206 1 char* arg_ptr2; 207 1 208 1 long temp_frequency; // used to hold the values input from the 209 1 int temp_amplitude; // keyboard while they are error checked 210 1 211 1 int printed_amplitude = 100; // a separate copy of amplitude because 212 1 // temp_amplitude is written over 213 1 214 1 void (*f)(void); // function pointer used to call the proper 215 1 // function from the command table 216 1 217 1 WDTCN = 0xde; // Disable watchdog timer 218 1 WDTCN = 0xad; 219 1 220 1 SYSCLK_Init (); 221 1 PORT_Init (); 222 1 223 1 // initializations for wave generation 224 1 REF0CN = 0x03; // enable internal VREF generator 225 1 DAC1CN = 0x97; // enable DAC1 in left-justified mode 226 1 227 1 Timer4_Init(SYSCLK/SAMPLE_RATE_DAC); 228 1 // using Timer4 as update scheduler 229 1 // initialize T4 to update DAC1 230 1 // after (SYSCLK cycles)/sample have 231 1 // passed. 232 1 233 1 // initialization for command input 234 1 UART0_Init (); 235 1 236 1 237 1 EA = 1; // Enable global interrupts 238 1 239 1 Print_Command_List(); 240 1 241 1 while(1){ C51 COMPILER V6.14 DAC1_FGEN1 03/07/2003 11:10:06 PAGE 5 242 2 243 2 // get user input 244 2 printf ("ENTER A COMMAND:>"); 245 2 gets(input_str,sizeof(input_str)); // wait for input 246 2 input_str[0] = toupper(input_str[0]); // convert the two characters 247 2 input_str[1] = toupper(input_str[1]); // in the command to uppercase 248 2 249 2 250 2 // Parse the command 251 2 for (i = 0; i < num_commands; i++){ 252 3 253 3 // strncmp() returns 0 if the first two arguments are the same string 254 3 // set for the command that matched 255 3 if (0 == strncmp(input_str, function_table[i].command, command_length)){ 256 4 257 4 arg_ptr1 = strchr (input_str, ' '); 258 4 arg_ptr1++; // point to the frequency 259 4 260 4 arg_ptr2 = strchr(arg_ptr1, ' '); 261 4 arg_ptr2++; // point to amplitude 262 4 263 4 temp_frequency = atol(arg_ptr1); 264 4 temp_amplitude = atol(arg_ptr2); 265 4 266 4 // check to make sure entered frequency is valid 267 4 if (temp_frequency) { 268 5 269 5 frequency = temp_frequency; 270 5 271 5 } else { 272 5 273 5 printf("\n** Frequency will not change\n"); 274 5 } 275 4 276 4 // check to make sure entered amplitude is valid 277 4 if ((temp_amplitude > 0) && (temp_amplitude <=100)){ 278 5 279 5 // multiply by 655 to be divided by 65535 (16-bit shift) in the 280 5 // ISR; this is an optimization to reduce the number of 281 5 // instructions executed in the ISR 282 5 amplitude = temp_amplitude * 655; 283 5 284 5 printed_amplitude = temp_amplitude; 285 5 286 5 } else { 287 5 288 5 printf("\n** Amplitude will not change\n"); 289 5 290 5 } 291 4 292 4 293 4 printf("\nFREQUENCY: %ld Hz", frequency); 294 4 printf("\nAMPLITUDE: %d %% of VREF/2", printed_amplitude); 295 4 296 4 297 4 EA = 0; // Disable Interrupts to avoid 298 4 // contention between the ISR 299 4 // and the following code. 300 4 // set the frequency 301 4 phase_add = frequency * PHASE_PRECISION / SAMPLE_RATE_DAC; 302 4 303 4 C51 COMPILER V6.14 DAC1_FGEN1 03/07/2003 11:10:06 PAGE 6 304 4 break; 305 4 } // end if 306 3 307 3 }// end for 308 2 309 2 // call the associated function 310 2 f = (void *) function_table[i].function_ptr; 311 2 f(); 312 2 313 2 EA = 1; // re-enable interrupts 314 2 315 2 } // end while(1) 316 1 317 1 } // end main 318 319 //----------------------------------------------------------------------------- 320 // Init Routines 321 //----------------------------------------------------------------------------- 322 323 //----------------------------------------------------------------------------- 324 // SYSCLK_Init 325 //----------------------------------------------------------------------------- 326 // 327 // This routine initializes the system clock to use a 22.1184MHz crystal 328 // as its clock source. 329 // 330 void SYSCLK_Init (void) 331 { 332 1 int i; // delay counter 333 1 334 1 OSCXCN = 0x67; // start external oscillator with 335 1 // 22.1184MHz crystal 336 1 337 1 for (i=0; i < 256; i++) ; // Wait for osc. to start up 338 1 339 1 while (!(OSCXCN & 0x80)) ; // Wait for crystal osc. to settle 340 1 341 1 OSCICN = 0x88; // select external oscillator as SYSCLK 342 1 // source and enable missing clock 343 1 // detector 344 1 345 1 } 346 347 //----------------------------------------------------------------------------- 348 // PORT_Init 349 //----------------------------------------------------------------------------- 350 // 351 // Configure the Crossbar and GPIO ports 352 // 353 void PORT_Init (void) 354 { 355 1 XBR0 = 0x04; // Enable UART0 356 1 XBR1 = 0x00; 357 1 XBR2 = 0x40; // Enable crossbar and weak pull-up 358 1 P0MDOUT |= 0x01; // Set TX0 pin to push-pull 359 1 } 360 361 //----------------------------------------------------------------------------- 362 // Timer4_Init 363 //----------------------------------------------------------------------------- 364 // This routine initializes Timer4 in auto-reload mode to generate interrupts 365 // at intervals specified in . C51 COMPILER V6.14 DAC1_FGEN1 03/07/2003 11:10:06 PAGE 7 366 // 367 void Timer4_Init (int counts) 368 { 369 1 T4CON = 0; // STOP timer; set to auto-reload mode 370 1 CKCON |= 0x40; // T4M = '1'; Timer4 counts SYSCLKs 371 1 RCAP4 = -counts; // set reload value 372 1 T4 = RCAP4; 373 1 EIE2 |= 0x04; // enable Timer4 interrupts 374 1 T4CON |= 0x04; // start Timer4 375 1 } 376 377 //----------------------------------------------------------------------------- 378 // UART0_Init 379 //----------------------------------------------------------------------------- 380 // 381 // Configure the UART0 using Timer1, for and 8-N-1. 382 // 383 void UART0_Init (void) 384 { 385 1 SCON0 = 0x50; // SCON0: mode 1, 8-bit UART, enable RX 386 1 TMOD = 0x20; // TMOD: timer 1, mode 2, 8-bit reload 387 1 TH1 = -(SYSCLK/BAUDRATE/16); // set Timer1 reload value for baudrate 388 1 TR1 = 1; // start Timer1 389 1 CKCON |= 0x10; // Timer1 uses SYSCLK as time base 390 1 PCON |= 0x80; // SMOD0 = 1 391 1 TI0 = 1; // Indicate TX0 ready 392 1 } 393 394 //----------------------------------------------------------------------------- 395 // Print_Command_List 396 //----------------------------------------------------------------------------- 397 // 398 // Prints the command list to the standard output. 399 // 400 void Print_Command_List (void) 401 { 402 1 printf ("\n\ 403 1 SQ - Square Wave\n\ 404 1 SI - Sine Wave\n\ 405 1 TR - Triangle Wave\n\ 406 1 SA - Saw Tooth Wave\n\ 407 1 OF - Output OFF\n\ 408 1 ?? - Help\n\n"); 409 1 410 1 } 411 412 //----------------------------------------------------------------------------- 413 // Sine 414 //----------------------------------------------------------------------------- 415 // 416 // Sets output to a sine wave. 417 // 418 void Sine (void) 419 { 420 1 output_waveform = SINE; 421 1 // print this message: *** OUTPUT IS NOW A SINE WAVE 422 1 printf ("%sSINE WAVE%s",string0,string1); 423 1 Print_Command_List(); 424 1 425 1 } 426 427 //----------------------------------------------------------------------------- C51 COMPILER V6.14 DAC1_FGEN1 03/07/2003 11:10:06 PAGE 8 428 // Square 429 //----------------------------------------------------------------------------- 430 // 431 // Sets output to a square wave. 432 // 433 void Square (void) 434 { 435 1 output_waveform = SQUARE; 436 1 // print this message: *** OUTPUT IS NOW A SQUARE WAVE 437 1 printf ("%sSQUARE WAVE%s",string0,string1); 438 1 Print_Command_List(); 439 1 440 1 } 441 442 //----------------------------------------------------------------------------- 443 // Triangle 444 //----------------------------------------------------------------------------- 445 // 446 // Sets output to a triangle wave. 447 // 448 void Triangle (void) 449 { 450 1 output_waveform = TRIANGLE; 451 1 // print this message: *** OUTPUT IS NOW A TRIANGLE WAVE 452 1 printf ("%sTRIANGLE WAVE%s",string0,string1); 453 1 Print_Command_List(); 454 1 455 1 } 456 457 //----------------------------------------------------------------------------- 458 // Saw 459 //----------------------------------------------------------------------------- 460 // 461 // Sets output to a saw tooth wave. 462 // 463 void Saw (void) 464 { 465 1 output_waveform = SAW; 466 1 // print this message: *** OUTPUT IS NOW A SAW TOOTH WAVE 467 1 printf ("%sSAW TOOTH WAVE",string0,string1); 468 1 Print_Command_List(); 469 1 } 470 471 //----------------------------------------------------------------------------- 472 // Off 473 //----------------------------------------------------------------------------- 474 // 475 // Sets output to zero volts DC. 476 // 477 void Off (void) 478 { 479 1 printf ("\n\n*** OUTPUT OFF",string1); 480 1 output_waveform = OFF; 481 1 Print_Command_List(); 482 1 483 1 } 484 485 //----------------------------------------------------------------------------- 486 // Help 487 //----------------------------------------------------------------------------- 488 // 489 // Prints the command list. C51 COMPILER V6.14 DAC1_FGEN1 03/07/2003 11:10:06 PAGE 9 490 // 491 void Help (void) 492 { 493 1 Print_Command_List(); 494 1 } 495 496 //----------------------------------------------------------------------------- 497 // Error 498 //----------------------------------------------------------------------------- 499 // 500 // Indicates that an invalid command was entered at the command prompt. 501 // 502 void Error(void) 503 { 504 1 printf (" ***INVALID INPUT = %s\n", input_str); 505 1 506 1 } 507 508 //***************************************************************************** 509 // Interrupt Handlers 510 //***************************************************************************** 511 512 //----------------------------------------------------------------------------- 513 // Timer4_ISR -- Wave Generator 514 //----------------------------------------------------------------------------- 515 // 516 // This ISR is called on Timer4 overflows. Timer4 is set to auto-reload mode 517 // and is used to schedule the DAC output sample rate in this example. 518 // Note that the value that is written to DAC1 during this ISR call is 519 // actually transferred to DAC1 at the next Timer4 overflow. 520 // 521 void Timer4_ISR (void) interrupt 16 using 3 522 { 523 1 524 1 static unsigned phase_acc = 0; // holds phase accumulator 525 1 526 1 int temp1; // the temporary value that passes 527 1 // through 3 stages before being written 528 1 // to DAC1 529 1 530 1 int code *table_ptr; // pointer to the lookup table 531 1 532 1 lng temporary_long; // holds the result of a 16-bit multiply 533 1 534 1 T4CON &= ~0x80; // clear T4 overflow flag 535 1 536 1 table_ptr = SINE_TABLE; 537 1 538 1 phase_acc += phase_add; // increment phase accumulator 539 1 540 1 541 1 // set the value of to the next output of DAC1 at full-scale 542 1 // amplitude; the rails are +32767, -32768 543 1 switch (output_waveform){ 544 2 545 2 case SINE: 546 2 547 2 // read the table value 548 2 temp1 = *(table_ptr + (phase_acc >> 8)); 549 2 550 2 break; 551 2 C51 COMPILER V6.14 DAC1_FGEN1 03/07/2003 11:10:06 PAGE 10 552 2 case SQUARE: 553 2 554 2 // if in the first half-period, then high 555 2 if ( (phase_acc & 0x8000) == 0 ) { 556 3 557 3 temp1 = 32767; 558 3 559 3 } else { 560 3 561 3 temp1 = -32768; 562 3 } 563 2 564 2 break; 565 2 566 2 case TRIANGLE: 567 2 568 2 // in first half-period, then y = mx + b 569 2 if ( (phase_acc & 0x8000) == 0 ) { 570 3 571 3 temp1 = (phase_acc << 1) - 32768; 572 3 573 3 // else, in the second half of period 574 3 } else { 575 3 576 3 temp1 = -(phase_acc << 1) + 32767; 577 3 } 578 2 579 2 break; 580 2 581 2 case SAW: 582 2 583 2 temp1 = phase_acc - 32768; 584 2 break; 585 2 586 2 case OFF: 587 2 588 2 temp1 = -32768; 589 2 break; 590 2 591 2 default: 592 2 while(1); 593 2 } 594 1 595 1 // Adjust the Gain 596 1 temporary_long.Long = (long) ((long)temp1 * (long)amplitude); 597 1 598 1 temp1 = temporary_long.Int[0]; // same as temporary_long >> 16 599 1 600 1 601 1 // Add a DC bias to make the rails 0 to 65535 602 1 // Note: the XOR with 0x8000 translates the bipolar quantity into 603 1 // a unipolar quantity. 604 1 DAC1 = 0x8000 ^ temp1; 605 1 } MODULE INFORMATION: STATIC OVERLAYABLE CODE SIZE = 941 ---- CONSTANT SIZE = 957 ---- XDATA SIZE = ---- ---- PDATA SIZE = ---- ---- DATA SIZE = 27 24 C51 COMPILER V6.14 DAC1_FGEN1 03/07/2003 11:10:06 PAGE 11 IDATA SIZE = ---- ---- BIT SIZE = ---- ---- END OF MODULE INFORMATION. C51 COMPILATION COMPLETE. 0 WARNING(S), 0 ERROR(S)