C51 COMPILER V6.14 TEMP_LAB 11/05/2002 12:26:24 PAGE 1 C51 COMPILER V6.14, COMPILATION OF MODULE TEMP_LAB OBJECT MODULE PLACED IN Temp_Lab.OBJ COMPILER INVOKED BY: C:\CYGNAL\IDEFILES\C51\BIN\C51.EXE Temp_Lab.c DB OE stmt level source 1 //----------------------------------------------------------------------------- 2 // Temp_Lab.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 // Controls the chip temperature by implementing DAC0 to control an external 12 // fan. The fan varies speed according to a specified target temperature 13 // from the keypad. Output is display on the LCD 14 // 15 16 //----------------------------------------------------------------------------- 17 // Includes 18 //----------------------------------------------------------------------------- 19 20 #include // SFR declarations 21 #include 22 #include 23 24 //----------------------------------------------------------------------------- 25 // 16-bit SFR Definitions for 'F02x 26 //----------------------------------------------------------------------------- 27 28 sfr16 TMR3RL = 0x92; // Timer3 reload value 29 sfr16 TMR3 = 0x94; // Timer3 counter 30 sfr16 ADC0 = 0xbe; // ADC0 data 31 sfr16 DAC0 = 0xd2; // DAC0 data 32 33 34 //----------------------------------------------------------------------------- 35 // Global CONSTANTS 36 //----------------------------------------------------------------------------- 37 38 #define BAUDRATE 9600 // Baud rate of UART in bps 39 #define SYSCLK 18432000 // SYSCLK frequency in Hz 40 #define SAMPLE_RATE 5000 // Sample frequency in Hz 41 #define INT_DEC 256 // integrate and decimate ratio 42 #define command_length 2 // command length is 2 characters 43 // Lookup table for converting keycode to ASCII (for this lab, some keypad 44 // entries are disabled) 45 unsigned int keytab[4][4] ={{'1','2','3',0}, 46 {'4','5','6',0}, 47 {'7','8','9',0}, 48 {0,'0',0,0}}; 49 50 51 52 //----------------------------------------------------------------------------- 53 // Function PROTOTYPES 54 //----------------------------------------------------------------------------- 55 C51 COMPILER V6.14 TEMP_LAB 11/05/2002 12:26:24 PAGE 2 56 void SYSCLK_Init (void); 57 void PORT_Init (void); 58 void UART0_Init (void); 59 void ADC0_Init (void); 60 void Timer3_Init (int counts); 61 void ADC0_ISR (void); 62 int button_dn(void); 63 unsigned int scankey (void); 64 void delay_ms(int ms); 65 66 //----------------------------------------------------------------------------- 67 // Global VARIABLES 68 //----------------------------------------------------------------------------- 69 70 long result; // ADC0 decimated value 71 char input_str[3]= ""; 72 73 //----------------------------------------------------------------------------- 74 // MAIN Routine 75 //----------------------------------------------------------------------------- 76 77 void main (void) { 78 1 long temperature; // temperature in hundredths of a 79 1 // degree C 80 1 int temp_int, temp_frac; // integer and fractional portions of 81 1 // temperature 82 1 int target_temp; 83 1 int x; 84 1 unsigned int rd1; 85 1 86 1 87 1 WDTCN = 0xde; // disable watchdog timer 88 1 WDTCN = 0xad; 89 1 SYSCLK_Init (); // initialize oscillator 90 1 PORT_Init (); // initialize crossbar and GPIO 91 1 UART0_Init (); // initialize UART0 92 1 Timer3_Init (SYSCLK/SAMPLE_RATE); // initialize Timer3 to overflow at 93 1 // sample rate 94 1 ADC0_Init (); // init ADC 95 1 AD0EN = 1; // enable ADC 96 1 DAC0CN = 0x8C; // enable DAC0 97 1 putchar (254); // LCD command 98 1 putchar (0x01); // clear LCD 99 1 EA = 1; // enable interrupts 100 1 101 1 x=0; // string counter 102 1 printf (" Please type\ntarget temp:"); 103 1 while (x<2) // 2 digit temp 104 1 { 105 2 if(button_dn()) // check for key press 106 2 { 107 3 delay_ms(5); // delay for debouncing 108 3 rd1 = scankey(); // read keypad 109 3 if(rd1 != 0) 110 3 { 111 4 putchar(rd1); // send value to UART 112 4 input_str[x]=rd1; // add character to input_str 113 4 x++; // increment counter 114 4 } 115 3 while(button_dn()); // check for key release 116 3 } 117 2 delay_ms(5); C51 COMPILER V6.14 TEMP_LAB 11/05/2002 12:26:24 PAGE 3 118 2 } 119 1 delay_ms (1500); // delay a tad for 'asthetic' reasons 120 1 target_temp = atoi (input_str); // translate target temp 121 1 putchar (254); // LCD command 122 1 putchar (0x01); // clear LCD 123 1 124 1 while (1) 125 1 { 126 2 EA = 0; // disable interrupts 127 2 temperature = result; 128 2 EA = 1; // re-enable interrupts 129 2 130 2 // calculate temperature in hundredths of a degree 131 2 temperature = temperature - 42380; 132 2 temperature = (temperature * 100L) / 156; 133 2 temp_int = temperature / 100; 134 2 temp_frac = temperature - (temp_int * 100); 135 2 136 2 // target temp + 1 degree 137 2 if (temp_int >= target_temp + 1) 138 2 DAC0 = 0x8000 ^ 32767; 139 2 else 140 2 // target temp + .50 degrees 141 2 if ((temp_int == target_temp) && (temp_frac > 50)) 142 2 DAC0 = 0x8000 ^ 24000; 143 2 else 144 2 // target temp + .25 degrees 145 2 if ((temp_int == target_temp) && (temp_frac > 20)) 146 2 { 147 3 DAC0 = 0x8000 ^ 30000; // 'jump start it' 148 3 DAC0 = 0x8000 ^ 19000; 149 3 } 150 2 else 151 2 //target temp - .20 degrees 152 2 if ((temp_int == target_temp -1 ) && (temp_frac < 80)) 153 2 DAC0 = 0; 154 2 155 2 printf ("Temp = %+02d.%02d", temp_int, temp_frac); // Display temp 156 2 putchar (254); // LCD command 157 2 putchar (0x02); // return home 158 2 159 2 } 160 1 } 161 162 //----------------------------------------------------------------------------- 163 // Initialization Subroutines 164 //----------------------------------------------------------------------------- 165 166 //----------------------------------------------------------------------------- 167 // SYSCLK_Init 168 //----------------------------------------------------------------------------- 169 // 170 // This routine initializes the system clock to use an 18.432MHz crystal 171 // as its clock source. 172 // 173 void SYSCLK_Init (void) 174 { 175 1 int i; // delay counter 176 1 177 1 OSCXCN = 0x67; // start external oscillator with 178 1 // 18.432MHz crystal 179 1 C51 COMPILER V6.14 TEMP_LAB 11/05/2002 12:26:24 PAGE 4 180 1 for (i=0; i < 256; i++) ; // XTLVLD blanking interval (>1ms) 181 1 182 1 while (!(OSCXCN & 0x80)) ; // Wait for crystal osc. to settle 183 1 184 1 OSCICN = 0x88; // select external oscillator as SYSCLK 185 1 // source and enable missing clock 186 1 // detector 187 1 } 188 189 //----------------------------------------------------------------------------- 190 // PORT_Init 191 //----------------------------------------------------------------------------- 192 // 193 // Configure the Crossbar and GPIO ports 194 // 195 void PORT_Init (void) 196 { 197 1 XBR0 = 0x04; // Enable UART0 198 1 XBR1 = 0x00; 199 1 XBR2 = 0x40; // Enable crossbar and weak pull-ups 200 1 P0MDOUT |= 0x01; // enable TX0 as a push-pull output 201 1 P1MDOUT |= 0x40; // enable P1.6 (LED) as push-pull output 202 1 203 1 P2MDOUT = 0xF0; // P2 u.n. push pull, lower-nibble input 204 1 P2 = 0x0F; // upper nibble hi-imp, allowing input read 205 1 206 1 } 207 208 //----------------------------------------------------------------------------- 209 // UART0_Init 210 //----------------------------------------------------------------------------- 211 // 212 // Configure the UART0 using Timer1, for and 8-N-1. 213 // 214 void UART0_Init (void) 215 { 216 1 SCON0 = 0x50; // SCON0: mode 1, 8-bit UART, enable RX 217 1 TMOD = 0x20; // TMOD: timer 1, mode 2, 8-bit reload 218 1 TH1 = -(SYSCLK/BAUDRATE/16); // set Timer1 reload value for baudrate 219 1 TR1 = 1; // start Timer1 220 1 CKCON |= 0x10; // Timer1 uses SYSCLK as time base 221 1 PCON |= 0x80; // SMOD00 = 1 222 1 TI0 = 1; // Indicate TX0 ready 223 1 } 224 225 //----------------------------------------------------------------------------- 226 // ADC0_Init 227 //----------------------------------------------------------------------------- 228 // 229 // Configure ADC0 to use Timer3 overflows as conversion source, to 230 // generate an interrupt on conversion complete, and to use left-justified 231 // output mode. Enables ADC end of conversion interrupt. Leaves ADC disabled. 232 // 233 void ADC0_Init (void) 234 { 235 1 ADC0CN = 0x05; // ADC0 disabled; normal tracking 236 1 // mode; ADC0 conversions are initiated 237 1 // on overflow of Timer3; ADC0 data is 238 1 // left-justified 239 1 REF0CN = 0x07; // enable temp sensor, on-chip VREF, 240 1 // and VREF output buffer 241 1 AMX0SL = 0x0f; // Select TEMP sens as ADC mux output C51 COMPILER V6.14 TEMP_LAB 11/05/2002 12:26:24 PAGE 5 242 1 ADC0CF = (SYSCLK/2500000) << 3; // ADC conversion clock = 2.5MHz 243 1 ADC0CF |= 0x01; // PGA gain = 2 244 1 245 1 EIE2 |= 0x02; // enable ADC interrupts 246 1 } 247 248 //---------------------------------------------------------------------------- 249 // Timer3_Init 250 //---------------------------------------------------------------------------- 251 // 252 // Configure Timer3 to auto-reload at interval specified by (no 253 // interrupt generated) using SYSCLK as its time base. 254 // 255 void Timer3_Init (int counts) 256 { 257 1 TMR3CN = 0x02; // Stop Timer3; Clear TF3; 258 1 // use SYSCLK as timebase 259 1 TMR3RL = -counts; // Init reload values 260 1 TMR3 = 0xffff; // set to reload immediately 261 1 EIE2 &= ~0x01; // disable Timer3 interrupts 262 1 TMR3CN |= 0x04; // start Timer3 263 1 } 264 265 //----------------------------------------------------------------------------- 266 // Interrupt Service Routines 267 //----------------------------------------------------------------------------- 268 269 //----------------------------------------------------------------------------- 270 // ADC0_ISR 271 //----------------------------------------------------------------------------- 272 // 273 // ADC0 end-of-conversion ISR 274 // Here we take the ADC0 sample, add it to a running total , and 275 // decrement our local decimation counter . When reaches 276 // zero, we post the decimated result in the global variable . 277 // 278 void ADC0_ISR (void) interrupt 15 279 { 280 1 static unsigned int_dec=INT_DEC; // integrate/decimate counter 281 1 // we post a new result when 282 1 // int_dec = 0 283 1 static long accumulator=0L; // here's where we integrate the 284 1 // ADC samples 285 1 286 1 AD0INT = 0; // clear ADC conversion complete 287 1 // indicator 288 1 289 1 accumulator += ADC0; // read ADC value and add to running 290 1 // total 291 1 int_dec--; // update decimation counter 292 1 293 1 if (int_dec == 0) { // if zero, then post result 294 2 int_dec = INT_DEC; // reset counter 295 2 result = accumulator >> 8; 296 2 accumulator = 0L; // reset accumulator 297 2 } 298 1 } 299 300 //----------------------------------------------------------------------------- 301 // Local Functions 302 //----------------------------------------------------------------------------- 303 C51 COMPILER V6.14 TEMP_LAB 11/05/2002 12:26:24 PAGE 6 304 //----------------------------------------------------------------------------- 305 // button_dn 306 //----------------------------------------------------------------------------- 307 // 308 // Function: test keypad for the presence of a key press. 309 // Return: 1 if keypress; 0 otherwise. 310 311 int button_dn() 312 { 313 1 int tmp; 314 1 tmp = (P2 & 0x0F)^0x0F; // read P2.3->P2.0 and XOR output 315 1 316 1 if(tmp) // if button is depressed, tmp != 0 317 1 return 1; 318 1 else 319 1 return 0; 320 1 } 321 322 //----------------------------------------------------------------------------- 323 // scankey 324 //----------------------------------------------------------------------------- 325 // 326 // Function: read keypad and convert keypress into equiv. ASCII code. 327 // Return: ASCII equivalent of pressed key's label. 328 329 unsigned int scankey(void) 330 { 331 1 int row = 0; 332 1 int col = 0; 333 1 int k,j; 334 1 335 1 P2 = 0x0F; // set data register 336 1 P2MDOUT = 0xF0; // drive P2.3->P2.0 as output 337 1 delay_ms(10); // let drive signals settle 338 1 339 1 row = (P2 & 0x0F)^0x0F; // read P2.3->P2.0 and XOR output 340 1 341 1 delay_ms(2); 342 1 343 1 if(row == 0) 344 1 return 0; // no closure detected 345 1 346 1 P2 = 0xF0; // set data register 347 1 P2MDOUT = 0x0F; // drive P2.7->P2.4 as output 348 1 delay_ms(2); // let drive signals settle 349 1 350 1 col = (P2 & 0xF0)^0xF0; // P2.7->P2.4 and XOR output 351 1 col = col >> 4; // move hi nibble to lo nibble 352 1 353 1 if(col == 0) 354 1 return 0; // no closure detected 355 1 356 1 P2 = 0x0F; // set data register 357 1 P2MDOUT = 0xF0; // drive P2.3->P2.0 as output 358 1 delay_ms(2); // let drive signals settle 359 1 360 1 switch(row) // convert 1-of-4 to binary 361 1 { 362 2 case 1: j = 0; break; 363 2 case 2: j = 1; break; 364 2 case 4: j = 2; break; 365 2 case 8: j = 3; break; C51 COMPILER V6.14 TEMP_LAB 11/05/2002 12:26:24 PAGE 7 366 2 default: return 0; 367 2 } 368 1 369 1 switch(col) // convert 1-of-4 to binary 370 1 { 371 2 case 1: k = 0; break; 372 2 case 2: k = 1; break; 373 2 case 4: k = 2; break; 374 2 case 8: k = 3; break; 375 2 default: return 0; 376 2 } 377 1 378 1 return keytab[j][k]; // return the ASCII value 379 1 } 380 381 //----------------------------------------------------------------------------- 382 // delay_ms 383 //----------------------------------------------------------------------------- 384 // 385 // an approximate x ms delay 386 387 void delay_ms(int ms) 388 { 389 1 int y; 390 1 int z; 391 1 for (y=1; y<=250; y++) for (z=1; z<= ms; z++); 392 1 } MODULE INFORMATION: STATIC OVERLAYABLE CODE SIZE = 958 ---- CONSTANT SIZE = 44 ---- XDATA SIZE = ---- ---- PDATA SIZE = ---- ---- DATA SIZE = 45 22 IDATA SIZE = ---- ---- BIT SIZE = ---- ---- END OF MODULE INFORMATION. C51 COMPILATION COMPLETE. 0 WARNING(S), 0 ERROR(S)