/**************************************************************************** ADC3.C ADC using PIC 16F873. It's input range is 0-5V. It is controlled by three bytes sent via RS232. * The first byte is '$'. * The second byte is the unit address and ADC channel select, configured as: XX A4 A3 A2 A1 A0 C1 C0(lsb) * The third byte is the digital value to be sent out Port C, configured as: D7 D6 D5 D4 D3 D2 D1 D0(lsb) If the second and third bytes are not each received within one second, the software resets to look for the '$' again. Upon receiving the three bytes, the digital value is sent out Port C, a conversion is done and the digital equivalent returned at 9600 baud as one to four characters (0-1023) followed by a trailing CR/LF. If leading zeros are desired so that four characters are always received, tie NO ZEROS high or let it float. The LED flashes when the chip is selected. The serial Tx output floats when high, and is 0V when low. This allows paralleling several of these units on the same Rx and Tx line on the TTL side of the MAX235 RS232 converter. (The Tx line needs a pullup resistor.) --------- +5--20-|Vdd | +5---1-|Mclr B6|-27----LED Gnd---8-|Vss | Gnd--19-|Vss | 4MHz--10-|Xtal | -------- ---9-|Xtal | Gnd-20-|EN | | | Gnd-21-|SD | | | Gnd-11-|Vss | | 16F873 | +5-12-|Vcc | | | | | ADC CH O ->--2-|A0 A4|-6---<----9600 baud----9-|OUT IN|-10-<-Rx ADC CH 1 ->--3-|A1 A5|-7--->--*-9600 baud----7-|IN OUT|-4-->-Tx ADC CH 2 ->--5-|A3 | | | | | | from other units | MAX235 | DIGOUT 7 -<-18-|C7 | -------- DIGOUT 6 -<-17-|C6 | ----- DIGOUT 5 -<-16-|C5 B4|-25--<--| | DIGOUT 4 -<-15-|C4 B3|-24--<--| ADR | DIGOUT 3 -<-14-|C3 B2|-23--<--| DIP |--Gnd DIGOUT 2 -<-13-|C2 B1|-22--<--| SW. | DIGOUT 1 -<-12-|C1 B0|-21--<--| | DIGOUT 0 -<-11-|C0 | | | | | ----- | | -NO ZEROS ->-26-|B5 | --------- External crystal oscillator = 4MHz Cycle time = 1uS Jon Fick 03/29/99 ***************************************************************************/ #include < 16F873.h > #list /* Set configuration bits in the PIC processor */ #fuses XT, NOPROTECT, NOPUT, NOWDT, NOBROWNOUT, NOLVP, NOCPD, NOWRT #use delay (clock=4000000) /* sets appropriate compiler constants */ #use standard_io ( a ) #use standard_io ( b ) #use fast_io ( C ) #use rs232 ( baud=9600, XMIT=PIN_A5, RCV=PIN_A4, FLOAT_HIGH ) #define PORT_B 6 #define PORT_C 7 #define NO_ZEROS PIN_B5 #define LED PIN_B6 #define TIMEOUT_VALUE 15 #byte DIGOUT = PORT_C #byte BIT_SWITCH = PORT_B void BlinkLed ( void ); static char cTimeoutCounter, cError; void main( void ) { char cAdcVal, cDigVal, cChannel, cAddress; set_tris_c ( 0b00000000 ); /* make all outputs */ setup_counters ( RTCC_INTERNAL, RTCC_DIV_256 ); setup_adc_ports ( RA0_RA1_RA3_ANALOG ); setup_adc ( ADC_CLOCK_INTERNAL ); port_b_pullups ( TRUE ); enable_interrupts ( INT_RTCC ); /* enable timer interrupt */ enable_interrupts ( GLOBAL ); /* enable global interrupts */ cError = NO; BlinkLed(); /* blink on initialization */ while ( TRUE ) /* do forever */ { while ( getc() != '$' ); /* wait until '$' leader comes along */ /* PREPARE FOR SECOND BYTE */ cTimeoutCounter = 0; /* restart timeout counter */ cError = NO; /* default */ while ( kbhit() == FALSE ) /* wait for start bit */ { if ( cError == YES ) /* if timed out */ { break; } } if ( cError == NO ) /* if not timed out yet */ { cAdcVal = getc(); /* get second byte from serial */ /* PREPARE FOR THIRD BYTE */ cTimeoutCounter = 0; /* restart timeout counter */ cError = NO; /* default */ while ( kbhit() == FALSE ) /* wait for start bit */ { if ( cError == YES ) /* if timed out */ { break; } } if ( cError == NO ) /* if not timed out yet */ { cDigVal = getc(); /* get third byte from serial */ /* ALL THREE BYTES RECEIVED SUCCESSFULLY */ cChannel = cAdcVal & 0x03; /* get channel select bits 0 & 1 */ cAddress = ( cAdcVal >> 2 ) & 0x1F; /* get address bits 2-6 */ if ( cAddress == ( ~BIT_SWITCH & 0x1F ) ) /* if address matches bit switches */ { /* SET THE DIGITAL OUTS, CHANNEL, AND RETURN ADC MEASUREMENT */ DIGOUT = cDigVal; /* send to Port C */ switch ( cChannel ) /* set ADC channel */ { case 0x00: case 0x03: { set_adc_channel ( 0 ); break; } case 0x01: { set_adc_channel ( 1 ); break; } case 0x02: { set_adc_channel ( 3 ); break; } } delay_us ( 25 ); /* wait the "delay aquisition time" after setting channel (refer to data sheet) */ if ( input ( NO_ZEROS ) == HIGH ) { printf ( "%04lu", read_adc() ); /* read the ADC and transmit value with leading zeros */ } else { printf ( "%lu", read_adc() ); /* read the ADC and transmit value */ } printf ( "\r\n" ); /* CR/LF */ BlinkLed(); /* signal done */ } } } } } void BlinkLed ( void ) { output_high ( LED ); delay_ms ( 10 ); output_low ( LED ); } /*****************************************************************************************************/ #INT_RTCC void TIMER_INTERRUPT ( void ) { /* This interrupt occurs every 65mS. */ if ( cTimeoutCounter > TIMEOUT_VALUE ) /* has it counted to timeout yet? */ { cError = YES; /* timed out, signal the event */ } else { cTimeoutCounter++; /* if not, increment the counter */ } }