Hi, here is my working application for your convenience. It measures and sends the result to a DMM software. R is 10 kohm, C is 47 nF. Part of code is copyright of Scott (the PicBasic Book). Cheers, Imre On Thu, 16 Jul 1998, Rigby-Jones, Michael [PAI01:4837:EXCH] wrote: > I have been trying to implement a PI temperature controller (No Differential > term, it wasn't considered necesary) using a 16C62. Temperature measurment > is (supposed) to be performed via a thermistor using the single slope > integration method outlined in Microchips AN512 application note. > Temperature control is via the PWM output driving a peltier device. The > conversion process is carried out under interupt driven from Timer1. > > Now, the application note sets up TMR0 as a counter, using the RA4/T0CKI > input and charges a capacitor whilst looking for a change in the TMR0 > register. Why? The Schmitt trigger input on this pin seems to be just as > valid when used as a normal input pin. It seems to be a lot of extra > complication if just configuring RA4 as an input would do the trick. But, > this extra complexity is there for a reason I suspect. > > I have had no end of problems with the counter not incrementing and the > software getting stuck in an endless loop, untill the watchdog kicks in. > This seems to happen very regularly, after a set number of sucessfull > conversions, usually about 3. By varying the time constant of the ADC > components, this number could be made as small as 1 or as large as 10 or so. > Generally the larger the time contant, the more reliable the conversion was, > but it was never 100% reliable. > > Well, I spent far too many erase/program cycles trying to find a way around > this, so I decided to just use RA4 as a normal input. And it nearly works. > The conversion technique uses a "set point" resistor (actually part of a > Xicor e2pot) and thermistor driven from RA0 and RA1 respectively. These > pins have the output latch set to 1 during initialisation, and the TRIS > registers are set or cleared to enable or disable charging, as per AN512. > This bit of the code worked fine while I was using TMR0, but now I'm reading > RA4 directly, RA0 refuses to go high when the TRIS register is set to 0 for > that pin. RA1 still works correctly. Could this be the infamous > read-modify-write problem? If so how do I cure it? The code is written > using Hitech C. > > Thanks for any suggestions, comments, or just general abuse you could heap > in my direction :) > > Mike Rigby-Jones > mrjones@nortel.co.uk > > Content-Type: TEXT/PLAIN; charset=US-ASCII; name="ohm2.src" Content-ID: Content-Description: DEVICE PIC16C84,WDT_OFF,PWRT_ON,PROTECT_OFF,XT_OSC ; ; ORG 0Ch ; GPR terulet kezdete ACCA DS 2 ACCB DS 2 ACCC DS 2 ACCD DS 2 ACCE DS 2 TCAL DS 2 TEMP DS 1 temp2 ds 1 ; Temporary counter for delay. dec_no ds 1 ; Decade (1,10,100...) to work on. flags ds 1 rcvd ds 1 ; The received byte buffer = 2Fh ; String storage at end of memory. ASC_0 = '0' ; ASCII numbers: 30h thru 39h. ASC_dp = '.' ; ASCII char for decimal point (period). fix = 2 ; Position for fixed decimal point. ; baud = 31 ; 2400 baud at 4MHz. baud = 63 ; 1200 baud at 4MHz. ; baud = 127 ; 600 baud at 4MHz. ; baud = 255 ; 300 baud at 4MHz. bits = 7 zs = flags.0 ; Leading-zero suppression flag. ovff = flags.1 ; overcount flag ; RCALMS EQU 10000< ;RCAL MSB VALUE IN HEX RCALLS EQU 10000> ;RCAL LSB VALUE IN HEX DSCHR EQU RA.0 RCAL EQU RA.1 RMEAS EQU RA.3 OVF EQU RB.3 RDY EQU RB.2 ERR EQU RB.0 out_pin = RB.4 ; Serial output through this pin. serial_in = RB.5 ORG 0 ; belepesi pont B OHMS ; foprogram ORG 4 ; dummy IT rutin RETFIE ;------------- ; MADD: ACCB := ACCB + ACCA MADD MOVFW ACCA+1 ADDWF ACCB+1 ;ADD LSB SKPNC ;ADD IN CARRY INCF ACCB MOVFW ACCA ADDWF ACCB ;ADD MSB RETURN ;------------- ; MPY: (ACCB,ACCC) := ACCB * ACCA MPY CALL SETUP ;RESULTS IN B(16 MSB'S) AND C(16 LSB'S) MLOOP RRF ACCD ;ROTATE D RIGHT RRF ACCD+1 SKPNC ;NEED TO ADD? CALL MADD RRF ACCB RRF ACCB+1 RRF ACCC RRF ACCC+1 DECFSZ TEMP ;LOOP UNTIL ALL BITS CHECKED B MLOOP RETURN ;------------- ; SETUP: TEMP := 16 ; ACCD := ACCB; ACCB := 0 ; ACCE := ACCC SETUP MOVLW 16 MOVWF TEMP MOVFW ACCB ;MOVE B TO D MOVWF ACCD MOVFW ACCB+1 MOVWF ACCD+1 MOVFW ACCC MOVWF ACCE MOVFW ACCC+1 MOVWF ACCE+1 CLRF ACCB CLRF ACCB+1 RETURN ;------------- ; DIV: ACCB := ACCB DIV ACCA ; ACCC := ACCB MOD ACCA DIV CALL SETUP MOVLW 32 MOVWF TEMP CLRF ACCC CLRF ACCC+1 DLOOP CLRC RLF ACCE+1 RLF ACCE RLF ACCD+1 RLF ACCD RLF ACCC+1 RLF ACCC MOVFW ACCA SUBWF ACCC,W ;CHECK IF A>C SKPZ B NOCHK MOVFW ACCA+1 SUBWF ACCC+1,W ;IF MSB EQUAL THEN CHECK LSB NOCHK SKPC ;CARRY SET IF C>A B NOGO MOVFW ACCA+1 ;C-A INTO C SUBWF ACCC+1 SKPC DECF ACCC MOVFW ACCA SUBWF ACCC SETC ;SHIFT A 1 INTO B (RESULT) NOGO RLF ACCB+1 RLF ACCB DECFSZ TEMP ;LOOP UNTIL ALL BITS CHECKED B DLOOP RETURN ;============= DSCHRG BSF RP0 BCF DSCHR ; kisuto lab kimenetkent BCF RP0 BCF DSCHR ; alacsonyba MOVLW 10 ; msecs MOVWF TEMP2 ; varakozo ciklus :LOOP0 CLRF TEMP :LOOP DECFSZ TEMP B :LOOP DECFSZ TEMP2 B :LOOP0 BSF RP0 ; vissza inputra BSF DSCHR BCF RP0 RETURN ;============= ;M_TIME: ACCA := Time of Load M_TIME CLRF TMR0 ;CLEAR RTCC CLRF ACCA+1 CLRF ACCA TLOOP INCFSZ ACCA+1 B ENDCHK INCFSZ ACCA B ENDCHK B END_M ENDCHK BTFSS TMR0.0 ; CHECK FOR RTCC TRIP B TLOOP CLRF TMR0 BCF OVFF RETLW 0 ; normal return END_M CLRF TMR0 BSF OVFF RETLW 1 ; overflow ;============= ; Main program OHMS BSF RCAL ; legyen magas, ha majd aktiv BSF RMEAS MOVLW 00101000b ;SELECT POSITIVE EDGE FOR RTCC OPTION MOVLW 11100000b ; lower 4 bits & out_pin TRIS RB MOVLW 00010011b ; clear all LEDs MOVWF RB CALL DSCHRG ;DISCHARGE CAPACITOR BSF RP0 BCF RCAL ; calibrate on BCF RP0 BSF RCAL CALL M_TIME ; MEASURE TIME BSF RP0 BSF RCAL BCF RP0 IORLW 0 ; overflow? BNZ ERROR MOVFW ACCA+1 MOVWF TCAL+1 ;STORE LSB MOVFW ACCA MOVWF TCAL ;STORE MSB AGN BSF RDY ; machine ready CALL GETCHAR ; read a character ; XORLW 'Z' ; this is the challenge ; BNZ AGN ; not recognized - try again BCF RDY ; turn LED off - communicate MEAS CALL DSCHRG ; DISCHARGE CAPACITOR BSF RP0 BCF RMEAS BCF RP0 BSF RMEAS CALL M_TIME ; MEASURE TIME BSF RP0 BSF RMEAS BCF RP0 IORLW 0 ; overflow? BZ GO BSF OVF ;signal overflow MOVLW 5 ;fill buffer with 9's MOVWF BUFFER MOVWF TEMP MOVLW BUFFER-1 MOVWF FSR MOVLW '9' :LOOP MOVWF INDF DECF FSR DECFSZ TEMP B :LOOP B DONE GO BCF OVF MOVLW RCALLS ;CALIBRATION LSB VALUE MOVWF ACCB+1 MOVLW RCALMS ;CALIBRATION MSB VALUE MOVWF ACCB CALL MPY ;MULTIPLY ACCA(MEAS) * ACCB(RCAL) MOVFW TCAL+1 MOVWF ACCA+1 MOVFW TCAL MOVWF ACCA CALL DIV ;DIVIDE ACCB(MEAS * R) BY ACCA(TCAL) CLRF BUFFER ; Clear char count (item 0 in buf). MOVLW 4 ; length of prefix MOVWF TEMP ; into loop var. MOVLW BUFFER-1 ; 1st of buffer MOVWF FSR ; pointer :LOOP MOVFW TEMP ; fetch string pointer CALL PREFIX ; fetch current char MOVWF INDF ; store it DECF FSR ; next char in buffer INCF BUFFER ; count length DECFSZ TEMP ; loop B :LOOP CALL BIN_ASC DONE CALL APPEND CALL SEROUT B AGN ERROR BCF ERR ; signal error LED B ERROR ; endless loop ;---- PREFIX ADDLW -1 ADDWF PCL RETW ' ','S','E','R' ;---- APPEND MOVLW 7 ; length of string MOVWF TEMP ; mark it MOVLW BUFFER-1 ; first pos. of buffer MOVWF FSR ; to pointer MOVFW BUFFER ; actual length SUBWF FSR ; correct :LOOP MOVFW TEMP ; fetch string pointer CALL GETSTR ; fetch current char MOVWF INDF ; store it DECF FSR ; next char in buffer INCF BUFFER ; count length DECFSZ TEMP ; loop B :LOOP RETURN GETSTR ADDLW -1 ADDWF PCL RETW 13,' ','m','h','o','k',' ' ; 0 1 2 3 4 5 ; SEROUT_# data (Serout_2 merged with bin_asc to transmit data as ; numeric text strings.) ; Transmits serial data with a fixed output pin, baud rate, and polarity. ; Data bytes to be transmitted must be arranged in memory starting at the ; address "buffer-1" and working downward (e.g., 30,29,28...). The number of ; bytes to transmit must be stored at the address labeled "buffer." A companion ; routine, BIN_ASC, converts 16-bit numbers to this form, optionally adding a ; decimal point. See the listing for Serout ...(format # data). ; Serout uses the common data format of no parity, 8 data ; bits, 1 stop bit (N81). ; This routine differs from the Serout presented in the text in that you ; must set the baud rate and input pin through the equates below. They ; cannot be changed once the program is assembled. (The larger version ; can change pins, baud rate, and data polarity on the fly.) Removing ; the code necessary for runtime changes saves about 30 instruction ; words of space. If you only need to send single bytes at a time, ; check out SEROUT_3 on this disk. ; To set the baud rate, just remove the comment symbol (;) in front of ; the desired baud rate in the list below. Make sure that all of the ; other "baud" definitions begin with (;) so that the assembler will ; ignore them. ; Note that the baud rates are all calculated at 4 MHz. At other clock ; rates, they will be proportional. For example, at 8 MHz, the fastest ; baud rate will be 4800. At 1 MHz, the fastest will be 600. ; To change the output pin, just change the line "out_pin = " to the ; desired pin. Make sure that the pin is set up as an output before ; calling serout. ; To change the signalling polarity of serout, you must make one ; change in the body of the program. There are comments next to ; the appropriate lines. Use a comment symbol (;) to deactivate the ; version you don't want, and remove comment symbols from in front of ; the desired line. The routine is currently set up for "inverted" ; polarity, meaning that it will transmit data properly to a PC ; serial port without the need for a serial line-driver IC. Just ; connect out_pin to the PC com port's data-in line, and the PIC ; circuit ground to the PC com port signal ground. ; Device data and reset vector ; Lookup table used by bin_asc routine. DECADE ADDWF PCL RETW 10000>,10000< RETW 1000>,1000< RETW 100,0 RETW 10,0 RETW 1,0 ; This routine accepts a 16-bit number in hiB, lowB and converts it into ; a counted ASCII text string located at the address "buffer." The buffer ; grows downward in memory. The first (0th) item in buffer is the number ; of characters in the string. The routine destroys the contents of ; hiB, lowB. If this value is required elsewhere, make a copy. BIN_ASC CLRF FLAGS ; Clear zs flag. CLRF DEC_NO ; Clear decade no. CLRF TEMP ; Char counter MOVLW BUFFER-1 ; elso karakter poz. MOVWF FSR ; index pointer MOVFW BUFFER ; length SUBWF FSR ; set pointer :LOOP MOVFW DEC_NO ; Get 1st hex digit of decade no. CALL DECADE ; from the lookup table. MOVWF ACCA+1 INC DEC_NO ; Get 2nd digit of decade no. MOVFW DEC_NO ; from the table. CALL DECADE MOVWF ACCA CALL D_POINT ; Insert decimal point. CALL SUB_IT ; Divide ACCB by ACCA BTFSC ZS ; If zs = 0 AND digit = 0 then B :NO_ZS MOVFW INDF ; returning answer in indirect. BZ :NO_ZED ; digit is a leading zero to be :NO_ZS ; ignored. Otherwise, it's either MOVLW ASC_0 ; an included zero (as in 7501) ADDWF INDF ; or a non-zero digit. INCF BUFFER INCF TEMP DECF FSR ; Point to next memory location. SETB ZS ; First non-zero digit sets zs bit. :NO_ZED INCF DEC_NO ; Next decade. MOVLW 8 ; If dec_no = 8, we're down to ones. XORWF DEC_NO,W SKPZ B :LOOP ; Otherwise, do next decade. INCF DEC_NO ; Update decade number for d_point. CALL D_POINT ; Decimal point here? MOVFW ACCB+1 ; Whatever's left belongs in ones. MOVWF INDF MOVLW ASC_0 ADDWF INDF ; Add offset for conversion to ASCII. INCF BUFFER ; Add 1 to character count. INCF TEMP MOVLW 5 ; max. of string SUBWF TEMP,W ; W := TEMP - 5 SKPC ; if less: return RETURN SKPNZ ; if equal: return RETURN SUBWF BUFFER ; recover char. count RETURN ; This routine performs division by iterated subtraction. It is efficient ; in this application because the dividend and divisor keep getting smaller ; as BIN_ASC runs, so the quotient is never larger than nine. A general- ; purpose division routine would be slower (and longer). SUB_IT CLRF INDF ; Clear to track no. of subtractions. :LOOP MOVFW ACCA+1 ; Subtract LSB SUBWF ACCB+1 BC :SKIP ; If no borrow, continue w/MSB. MOVLW 1 SUBWF ACCB ; Otherwise borrow from MSB. BC :SKIP ; If borrow causes a carry, then INCF ACCB ; add numbers back and return. MOVFW ACCA+1 ADDWF ACCB+1 RETURN :SKIP MOVFW ACCA ; Subtract MSB. SUBWF ACCB BC :SKIP2 ; If no borrow, subtract again. MOVFW ACCA+1 ; Otherwise, undo the subtraction ADDWF ACCB+1 SKPNC ; by adding entire 16-bit no. INCF ACCB ; back together and return. MOVFW ACCA ADDWF ACCB RETURN :SKIP2 INCF INDF ; No borrow, so do it again. B :LOOP ; This routine adds a decimal point in the location set by "fix" in the ; equates at the beginning of the program. The location of the decimal point ; is in front of the "fix"ed digit, numbered starting with 0. If you fix the ; point at 0, the first (0th) character in the string produced by BIN_ASC ; will be a decimal point. If you don't want a decimal point, either move ; it out of range (fix = 6), or delete this routine and the "call d_point" ; in the body of BIN_ASC above. D_POINT MOVLW FIX*2+1 XORWF DEC_NO,W SKPZ RETURN BSF ZS MOVLW ASC_DP MOVWF INDF INCF BUFFER DECF FSR INCF TEMP RETURN ; Subroutine used by Serout to send a bit and generate time delays. EmitBit SKPNC ; skip if Carry BCF OUT_PIN ; otherwise clear pin SKPC BSF OUT_PIN B_Wait MOVLW BAUD MOVWF TEMP2 :loop B $+1 ; Two-cycle nops for time delay. B $+1 B $+1 B $+1 B $+1 DECFSZ TEMP2 ; Number of trips through loop B :loop ; Set by baud rate in temp2. RETURN ; A data string consisting of the number of bytes, followed by the ; bytes arranged downward in memory, must be at the location "buffer." ; Upon return, the data in the buffer will be unchanged, but the 0th entry ; (representing the string length) will have been decremented to 0. Serout MOVLW BUFFER-1 ; Point to first data byte. MOVWF FSR :XMIT CLRC ; Set up start bit. CALL EmitBit ; Send start bit. MOVLW Bits ; Send data bits. MOVWF TEMP :BITS RRF INDF ; Rotate bit into carry. CALL EmitBit ; Send the data bit. DECFSZ TEMP ; All 8 bits sent? B :BITS ; No: send more bits. RRF INDF ; Rotate data back into original position. SETC ; Set up stop bit. CALL EmitBit ; Send the stop bit. SETC ; Set up stop bit. CALL EmitBit ; Send the stop bit. DECF FSR ; Point to next data byte. DECFSZ BUFFER ; All bytes sent? B :XMIT ; No: send more bytes. RETURN ; Yes: return. ; Taken from Parallax PIC Application Note: Receiving RS-232 Serial Data ; July 15, 1993 ; This program receives a byte of serial data and displays it on eight LEDs ; connected to port rb. The receiving baud rate is determined by the value of ; the constant bit_K and the clock speed of the PIC. See the table in the ; application note (above) for values of bit_K. For example, with the clock ; running at 4 MHz and a desired receiving rate of 4800 baud, make bit_K 50. ; For 1200 Baud, use bit_K = 206 bit_K = baud/21*68 ;Change this value for desired baudrate ;-------- ; GetChar: fetch a char from RxD into rcvd ; GetChar ; now program waits for mark bit (low if inverted) ; :strtbt nop ; wait for start bit (SPACE signs +) btfss serial_in ; skip if high (normal input) b :strtbt ; otherwise wait for movlw bit_K/2 ; init half-bit loop movwf TEMP2 ; dctr = W :loop nop decfsz TEMP2 b :loop btfss serial_in ; skip if high (normal input) b :strtbt ; only glitch movlw bits ; # of bits movwf TEMP clrf rcvd Rcvr call B_wait bcf c ; copy /serial_in into carry btfss serial_in ; skip if input high bsf c ; otherwise set carry rrf rcvd ; rotate bit into LSB decfsz TEMP ; bctr--; b Rcvr call B_wait ; wait for stop_bit movfw rcvd ; the Read byte return ; ;-------- END