#include /* 12bit 8 channel A- D convertor This is a rewrite of an old assembler project from 1998. It uses an AD7858L converter and a 9600 Baud serial connection to a PC that is implemented in software */ /***************** MAJOR BUG *********************************/ /***** The HiTech c compiler wrongly assumes a 16c84 *********/ /***** has 0x44 bytes of RAM. it doesn't. it has 0x24 ********/ /***** You need to go to the Project->Global_Options *********/ /***** and set the RAM range to 0c-2f, otherwise some ********/ /****** variables will mysteriously lose their values ********/ /****** or appear to be corrupted or reset to zero **********/ /*************************************************************/ __CONFIG(XT & WDTDIS & UNPROTECT); /* Frequency using RC oscillator. * 150pf + 10k ~ 660kHz */ #define _XTAL_FREQ 1000000 // define some data structures for soe bit-mapped variables and // in/out values. typedef union { unsigned char ALL; struct { unsigned l:4; unsigned h:4; }; } bcd_t; typedef union { unsigned int ALL; struct { unsigned char l; unsigned char h; }; } adc_t; // processor pins used for the SPI. if you choose other // pin assignments, be sure to update the TRIS assignments // accordingly #define SDI RB3 #define SDO RB2 #define SYNC RB0 #define SCLK RB1 #define TxD RB6 #define RxD RB7 // declare prottypes of functions used in the code void putch(unsigned char); void putint(unsigned int); void put_hexc(unsigned char); void put_int4(unsigned int); unsigned char spi(unsigned char); void put_bin(unsigned char); void bbin(unsigned int); void adc_cal(); unsigned int adc_chan(unsigned char); void dly(unsigned char); // global variable declaration - when built, there are 2 bytes of RAM free volatile unsigned char timer1; // 10mSec timer volatile unsigned char timer2; // second 10mSec timer volatile bcd_t ticks; volatile bcd_t seconds; volatile bcd_t sec100; volatile bcd_t sec10k; const char *message = "12Bit A-D 28-Aug-2009. AIN2 faulty\n"; void main(void) { unsigned int res; unsigned char *p = message; OPTION = 0b00010011; /* pullups enabled - 0x80 */ /* prescaler to WDT (not used) */ INTCON = 0b00111000; // TMR0 interrupt // INT (RB0 1->0) // RB5 change TRISA = 0; // All Port A are output pins TRISB = 0b10001000; // RB7 = RxD, // RB3 = SD in RB6 = 1; // serial port idle state /* initilaise all the variables here */ SYNC = 1; // quiescent state for SYNC is high SCLK = 1; SDO = 0; ticks.ALL = 0; seconds.ALL = 0; sec100.ALL = 0; sec10k.ALL = 0; GIE = 1; // let 'em in // output an introductory message when powered up while(*p) { putch(*p++); } putch(13); putch(10); while(seconds.l < 1) ; // wait 1 sec for things to // settle down adc_cal(); // get ADC to self-calibrate while(seconds.l < 2) ; // wait for cal to finish /* main loop here. Check if any buttons have been pressed (and released) - set up actions if they have been Take action if the ISD raises an interrupt - interrogate it to clear See if the RAC bit is toggling, this indicates record / play - change the LED patterns accordingly */ loop: timer1 = 10; // once round the loop every 250 mSec putch('0'+sec10k.h); putch('0'+sec10k.l); putch('0'+sec100.h); putch('0'+sec100.l); putch('0'+seconds.h); putch('0'+seconds.l); putch('.'); putch('0'+ticks.h); putch('0'+ticks.l); putch(' '); res = adc_chan(0); put_int4(res); putch(' '); res = adc_chan(1); put_int4(res); putch(' '); res = adc_chan(2); put_int4(res); putch(' '); res = adc_chan(3); put_int4(res); putch(' '); // res = adc_chan(4); // put_int4(res); // putch(' '); res = adc_chan(5); put_int4(res); putch(' '); res = adc_chan(6); put_int4(res); putch(' '); res = adc_chan(7); put_int4(res); putch(13); // carriage return putch(10); // linefeed to end line of data while(timer1) ; // wait for second to expire goto loop; // end of actions, back to start } /*******************************************************/ /* Interrupt routine called ever 10mSec */ /* Used mainly to provide time delays and to flash the */ /* LEDs which provide status information */ /*******************************************************/ void interrupt isr(void) { if(T0IF) { timer1--; // msec timer used in dealy loops timer2--; ticks.l++; /* nop's to pad out interrupt time to exactly 10 mSec. */ #asm nop #endasm TMR0 = 102; // reload timer for next interrupt T0IF = 0; // clear interrupt if(ticks.l > 9) { ticks.l = 0; ticks.h++; if(ticks.h > 9) { ticks.h = 0; seconds.l++; if(seconds.l > 9) { seconds.l = 0; seconds.h++; if(seconds.h > 9) { seconds.h = 0; sec100.l++; if(sec100.l > 9) { sec100.l = 0; sec100.h++; if(sec100.h > 9) { sec100.h = 0; sec10k.l++; if(sec10k.l > 9) { sec10k.l = 0; sec10k.h++; } } } } } } } } // interrupt when pin RB0 goes high if(INTF) { // interrupt on RB0 INTF = 0; // reset interupt } // interrupt on pin change (either 0->1 or 1->0) if(RBIF) { // RAC has changed state asm("movf _PORTB, w"); // clear the interrupt RBIF = 0; } } // write the contents of the byte argument as binary void put_bin(unsigned char a) { putch('0'+((a >>7) & 1)); putch('0'+((a >>6) & 1)); putch('0'+((a >>5) & 1)); putch('0'+((a >>4) & 1)); putch('0'+((a >>3) & 1)); putch('0'+((a >>2) & 1)); putch('0'+((a >>1) & 1)); putch('0'+((a ) & 1)); } void bbin(unsigned int b) { put_bin((b >> 8) & 0xff); put_bin(b & 0xff); } // send a self-calibration command to the ADC void adc_cal() { SCLK = 0; // idle at zero SYNC = 0; spi(0b11100001); spi(0b10010000); SYNC = 1; } // get a reading from channel unsigned int adc_chan(unsigned char chn) { adc_t r; r.h = 0b11100001 | (chn << 2); // top 2 bits == control reg. // single-ended // 3 bits for channel // final 01 == no SLEEP mode SCLK = 1; // idle at logic 1 SYNC = 0; spi(r.h); spi(0b00000000); // don't start conversion yet SYNC = 1; asm("nop"); /* now we have loaded the correct channel into the ADC and allowed time for the data aquisition (500nS) to take place, do the conversion */ SCLK = 1; SYNC = 0; spi(r.h); // same channel and config spi(0b00010000); // start conversion //spi(0b11000000); // read status register, instead SYNC = 1; asm("nop"); asm("nop"); // 10uSec aquisition time for ":" part /* finally, tickle the ADC for a third time to get the result */ /* the conversion time is < 5uSec */ SCLK = 1; SYNC = 0; r.h = spi(0); // doesn't matter what r.l = spi(0); // values we send down here SYNC = 1; return(r.ALL); // return 12 bit result }