# trossin

Moderator

243

1. ## Calculating Distance Using Tmr0

Depending how you printed out the variable (hex, decimal or octal) it is the number of clocks that the timer saw. You did not say how you configured the timer but if your timer counts at a rate of 1 count / usec then the number is the number of microseconds. So, all you need is the counter rate to figure out how much time has elapsed then you can do some simple math to convert to inches. Another way to go is assume that the sensor is behaving in a linear fashion and take your number (I'll assume decimal), 602 and measure with a ruler the distance that you got that value at. For example 25 inches. Then all you need is to calculate the scaling constant. For my example it would be 25 inches = 602 * C. so C=25 inches/602 or C=0.04153. Take a few more measurements and make sure the constant is really a constant. If it is not, you could create a table of say 10 or 20 constants and then do linear interpolation between them to get a nice calibrated distance. If you are too young to rembember log tables here is the secret using an example: Table: Value Distance 0 0 105 5 250 10 330 15 540 20 To interpolate the table, find the two values that your sensor value is between. For example, say you read 275, you would select the entries for 250 (Value.low) and 330 (Value.high). Now the equation is: Ratio=(Reading-Value.low)/(Value.high-Value.low); Distance = (Ratio * (Distance.high-Distance.low)) + Distance.low; So for this example: Ratio = (275-250)/(330-250) = 0.3125 // 31.25% of the way between 250 and 330 Distance = (0.3125 * (15 - 10)) + 10 = 11.5625 inches // 31.25% between 10 and 15 I hope this helps

3. ## Another Rs232 Problem

The secret of how to do this: what{ indent } is to use followed by your code and then ending with the same thing except end with /code in brackets. As far as your problem is concerned, how big is your transmit buffer and how long of a string are you sending. 9600 baud is pretty slow, about 100 characters/second. Also, Why are you calculating parity. I thought the UART did this for you while you are sleeping? The data sheet will have the secrets. I'm not sure what device you are using but I wrote ASM code for the 16F628 to do the buffered RS-232 receive for a little LCD terminal project. (http://www.geocities.com/ted_rossin/Electronics/Pic/Pic.html#LCD%20Terminal or http://www.geocities.com/ted_rossin/Electronics/Pic/Pic.html if the previous link is messed). If your buffer is 10 characters and you shove a string longer than 10 characters at it, you will most likely overrun your buffer and have your string chopped off. The delay you add plus all the code you execute may be enough to slow the buffer fill rate down low enough to get longer strings out. At least, you should try using a buffer of 10 bytes and see if it is rock solid sending strings of 9 characters with a wait of 100ms between each string sent. You should not need the 1ms wait for each character.
4. ## A/d Conversion Help

The loop looks good except that you will blow through the 256 EEPROM locations pretty fast and wrap around. I would suggest hooking up 8 LEDs to display the A/D result or add an RS-232 interface and spew the results to a terminal screen. The code I use to setup the A/D is: adcon1 = 0x0e; // (left justified) 1 A/D channel adcon0 = 0x81; // FOSC/32, channel=0, ADON=1 Then, I make calls to SampleADC: unsigned char SampleADC(void) { set_bit(adcon0,GO); // Start conversion while(test_bit(adcon0,GO)); return(adresh); // Fetch high 8 bits of result } Maybe using the individual bits you are not setting all the config bits. I know this code works for a 16F873A device but I just noticed that you are using an 18F type device. Sorry. All I can say for sure is buy some LEDs or an RS-232 (maybe with a RS-232 to USB converter dongle) inteface to help debug problems.
5. ## Interfacing To Power Lines

My Bad. I meant to say zener diode. Here is some lovely ASCII art. I did it with trial and error. Not real easy to do for some reason. o---/\/\/\/\/---+--------| AN0 1K | /----/ /\ 5.1 V /---\ | | ----- --- - Shove 9 VAC in on the left and AN0 will see a clipped sine wave that goes from about -0.6 V to about 5 V. If you are running your PIC at 3V get a lower voltage zener diode.
6. ## Interfacing To Power Lines

I suggest you skip the digital technique and use the A/D converter. You can either set up a timer to read the A/D result then start the next conversion or just do a spin loop of starting, waiting, reading and waiting till you see the voltage go from above a threshold (1V) to below another threshold (0.02V) and only detect the falling zero crossing. You may have to tune the low threshold as there may be some noise or offset in the system that prevents you from seeing zero. You could still use the zerner diode and resistor setup I described. Doing a little simple DSP (average samples in time) should get you very good results. I think the A/D converter can give you an answer in 10us. 8 bits is more than enough accuracy so just grab the upper 8.
7. ## Interfacing To Power Lines

Since you want this zero crossing detector to trigger an interrupt, I'm guessing you are trying to get a very accurate 50Hz or 60Hz timebase for a clock and not trying to do high frequency networking on the power line. If so you should take Picxie's advice and use an isolation transformer. Most folks use an AC wall wart to get 9 VAC then make a local power supply with diodes and a simple linear regulator or a switcher. You then can tap off the input to the bridge rectifier and get a low voltage and safely isolated signal that you make a simple resistor zener protection circuit and then shove the output into a schmidt trigger input. Instead of looking for zero, look for one and you will only get 50 or 60 rising edges/second. Nice and clean. People have been doing this for more than 20 years. It is pretty solid and will survive power surges and most nearby lightning strikes! I used to make my students calculate the value of the resistor using a 5.1 V zener that would allow the circuit to work over the widest range of input voltages without burning up the diode.
8. ## Newbi Questions

I made a little library of functions under BoostC that may help out as well. Go to: http://www.geocities.com/ted_rossin/Electronics/Pic/Pic.html Scroll down to Library of C Routines and grab CBLib.zip. In there you will find Serial.c and Serial.h. Just add them to your project and make use of the following functions: void RS232Init(unsigned char BaudRate); void RS232putch(unsigned char ByteVal); char RS232getch(void); unsigned char RS232peekch(void); The RS232Init function was written for 16F873 parts so it will not work for the 16F628A part directly. The 16F628 uses RB1 for RX and RB2 for Tx instead of RC7 for RX and RC6 for Tx that the 16F87x parts use. So you would have to change two lines in RS232Init from set_bit(trisc,7); to set_bit(trisb,1); and change clear_bit(trisc,6); to clear_bit(trisb,2); The rest of the crap should be the same. I defined a bunch of Baud rates in Serial.h that you can pass to RS232Init. For example: RS232Init(RS232_20MHZ_BAUD_115000); will set up the baud rate generator for 115K baud when clocking the PIC with a 20 MHz crystal. The function RS232putch(Value); will wait for the transmit buffer to be empty and then send the value you pass. The function RS232getch() will wait for a character to be recieved and then return the value as a char. The function RS232peekch() will return 1 if a character is available and 0 if one is not. One day I'll add an optional type input to RS232Init so you don't have to hack the version.
9. ## Delay Functions

I checked out the manual and found that the BASIC compiler uses the same prgama statements as the C compiler. So the answer is to add this line to your program. #pragma CLOCK_FREQ 20000000 This tells the delay functions what your clock frequency is. The frequency setting that you changed with a pull down menu is for the simulator to be able to display time correctly if you use a timer plug in. I hope this helps
10. ## Post Sample Hobby Type Projects

http://www.geocities.com/ted_rossin/Electronics/Pic/Pic.html

Try swaping your resistors and see if the value moves. 503/1023 is 0.4917 or less than a 1% error. Most resistors are 5% tolerance. You usually pay more for 1%. Have you measued the voltage with a meter?

13. ## Baud Rate Doubt ?

I run reliably at 115.2K baud using a 20 MHz crystal but I connect up to my own applications that use the Win32 API calls under C++ code and use a nice cable with a MAX202 interface/charge-pump chip. Here are the values I use for various baud rates. #define RS232_20MHZ_BAUD_115000 10 #define RS232_20MHZ_BAUD_57600 20 #define RS232_20MHZ_BAUD_28800 42 #define RS232_20MHZ_BAUD_19200 64 #define RS232_20MHZ_BAUD_9600 12 This comes out to 113.6 Kbaud or just a 1.4% error plus the crystal freq error which is way below 1%. Using 1 start bit, 8 data bits and 1 stop bit requires that 9 bits be sampled correctly by the receiver (either host or PIC). The hardware tries to sample in the middle of each bit (with Nx oversampling) with the goal being that when the stop bit rolls by that it is still sampling inside that bit. There are 10 bits that get sent out for a "frame". Time starts a half bit after the falling edge of the start bit and time ends a half bit into the stop bit. So the total time that matters for a frame is 9 bits. |_0|B0|B1|B2|B3|B4|B5|B6|B7|_1| At 115,200 baud each bit is about 8.68us so the time from the middle of the start bit to the end of B7 is 8.5*8.68us or 73.78us. The time from the middle of the start bit to the middle of the stop bit (ideal case) is 9*8.68us or 78.12us. The time from the middle of the start bit to then of the stop bit is 9.5*8.68us or 82.46us. This gives the range of valid bit rates for the transmitter. Min is 82.46us for 9 bits or 9/82.46 or 109,143 (-5.25% error) Perfect is 78.12us for 9 bits or 9/78.12us or 115,200 (0.00%) Max is 73.78us for 9 bits or 9/73.78 or 121,984 (+5.88% error) The accuracy is not dependent on baud rate but on the numbers 8.5,9 and 9.5 9/8.5 = 1.058 (or +5.88% error) 9/9.5 = 0.947 (or -5.26% error) I assumed an ideal sampler on the receiver. The slower the sampler the larger the error may be that the first sample of the start bit is not truely 1/2 bit width after the falling edge. I forget what the PIC is using but it is either 4x, 8x or 16x. So there is a bit of error introduced by the sampler. Somewhere between a 1/4 to 1/16 of a bit. With 4x sampling: 9/(8.5+0.25) = 1.0285 (or +2.86%) 9/(9.5-0.25) = 0.9730 (or -2.70%) With 16x sampling: 9/(8.5+0.0625) = +5.11% 9/(9.5-0.0625) = -4.636% This is with ideal rise and fall times at the end of the cable but with modern drivers and cables, the waves look darn near ideal so the -1.4% error that I use seems to be tolerated just fine. I've pumped data through at this rate continuously for my cheap logic analyzer without ever seeing a transmission problem. I'll admit that I send more data to the host than I receive in the PIC and I would guess that the PC reciever uses a higher sampling rate than the PIC. I'll stop now. I'm clearly digging too deep. Someone else can take over by adding more detail and correcting any mistakes that I may have made.
14. ## Build Or Buy That Ultimate Pic Programmer?

I like the look of the Russian text but I can't understand it. Is there a translation of this site?
15. ## Conserving Ram

We upgraded the forum to the latest version.You can still wrap code in [ code ] [ /code ] (or use the leftermost button on the tool bar) blocks to preserve formatting, that way you should be able to just cut and paste your code - no messing required. Regards Dave Thanks Dave. I never thought to just type in the word code. It works just fine.

Binary is as binary is: check = (ADRESH<<8) | ADRESL; check will be the 10 bit number you are looking for. Your code never sets check to 0 inside the while loop so the value will just keep increasing. Also, you only look at 6 bits instead of 8. But, just replace the table and for loop with the single line above and I think you will be much happier.
17. ## Conserving Ram

Maybe instead of saving the entire string in RAM you can parse them as each character arrives. Maybe you could create a software state machine could do the job. Also, the machine could decode the strings on word boundaries so that only a word would have to be accumulated before being acted on by the state machine. For example the string, "Pos X=25 Y=17" could be handled with: ----Sorry about the formating. I've grown tired of trying to figure out how to insert code as the UI changed for this forum. The dang thing keeps eating my spaces and tabs can't even be entiered. I refuse to mess with all the indent crap. ------- #define STATE_FETCH_COMMAND 0 #define STATE_FETCH_X 1 #define STATE_FETCH_Y 2 #define STATE_FETCH_VALUE 3 #define MODE_POS 0 #define MODE_GUNK 1 char Buf[10]; main() { unsigned char Mode,State,BufIndex,c; int X,Y; State = STATE_FETCH_COMMAND; BufIndex = 0; while(1){ c = getch(); if(c==' ' || c=='\' || c=='\n'){ // Delimiter found Buf[bufIndex++] = 0; switch(State){ case STATE_FETCH_COMMAND: if(!strcmp(Buf,"Pos")){ Mode = MODE_POS; State = STATE_FETCH_X; } if(!strcmp(Buf,"Gunk")){ Mode = MODE_GUNK; State = STATE_FETCH_X; } // Add more commands here ... break; case STATE_FETCH_X: if(Buf[0]=='X' && Buf[1]=='='){ X = atoi(&Buf[2]); } else{ // Error } State = STATE_FETCH_Y; break; case STATE_FETCH_Y: if(Buf[0]=='Y' && Buf[1]=='='){ Y = atoi(&Buf[2]); switch(Mode){ case MODE_POS: // Position is X,Y break; case MODE_GUNK: // Gunk is X,Y break; } } else{ // Error } State = STATE_FETCH_COMMAND; break; } } else{ Buf[bufIndex++] = c; if(BufIndex>=10){ // die } } } }
18. ## Serial Input/output Inversion

If you are using a software UART then you can invert it with that software. If you are using the hardware UART you have to invert the signal externally (either with a single transistor or a TTL gate).
19. ## Silly Printf() Question

You may not even need the printf as the PIC simulator provided with SourceBoost is quite excellent. You can single step through your code, set break points, and even connect to virtual devices.
20. ## Do You Know Why ?

Make sure you have a decoupling cap across the suppy lines entering you PIC. A 0.1uF ceramic seems to be the way to go. Put it as close to the pins as possible. By supply lines I mean betwen Vcc and GND.
21. ## Include Floats In Boostc And Boostc++

I agree. It would be great if it was built in and smart about it. If you use floating point math, you get a pile of crud. If you don't use it you don't get the crud. Just like if you use multiplies you get some multiply subroutines added to your code. I don't follow the logic that if it is not supported in hardware the compile should not support it as 16-bit math is not performed in hardware (nor multiply or divide) but I don't hear compliants that these features should be removed.

23. ## What Does This Mean?

I think you could just toss the ul and all would be well. All the math you are trying to do can be done with 16 bit math so there is no need to use 32-bit math hints. You can check the results by creating an unsigned int and assigning the value and looking at the code generated. It is not rocket science. #define TX_BUFFER_SIZE 128 #define TXSTART (8192 - (TX_BUFFER_SIZE + 8)) main(){ unsigned int What; // 16-bit variable What = TXSTART; }
24. ## Need Help!

I came at this problem using my computer graphics background (first single chip geometry accelerator at HP in 1993). What I did was allocate a section of memory to be my "frame buffer" where I could "render" characters, pictures whatever at whatever rate I wanted. Then I set up an interrupt routine to "refresh" the display a periodic rates. This simplifies the main code so that it does not worry how the display is drawn. This display was connected up in row/column format so that each time the interrupt handler is called (controlled by a timer) the column data for the current row is output. Then, the row counter is advanced to the next row for the next interrupt. pseudo code for a 5x7 display: unsigned char Row = 0; unsigned char FrameBuffer[7]; interrupt handler() { portb = ~(1<<Row); // Row enable is active low portc = FrameBuffer[Row]; // Column data is active high Row++; if(Row>6) Row = 0; } main() { set up interrupts at 10ms rate while(1){ Draw cool pictures into FrameBuffer } }
25. ## Pita Case Issue!

I think you are wrong. C is very much case sensitive. The gcc compiler complains about #IFDEF as well. Use lower case. This is not a bug. This is valid C code: int main(int argc,char *argv[]) { int Hello,hello; Hello = 1; hello = 2; return(0); }
×