Jump to content


  • Content Count

  • Joined

  • Last visited

Everything posted by trossin

  1. 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
  2. It sounds to me that this is a digital problem and not an analog problem (although digital is analog). You state that you have already converted the signal from the card into binary 0's and 1's but it does not sound like you have a reference clock or valid pulse to determine when to sample the data. I think we need a little bit more info to answer your question. For one, is the goal to just oversample the input at a fixed rate, store the data in the PIC and then upload the data to a PC to post process the data to recover the 96-bit ID? If so, this sounds like a simple logic analyzer function where you read the input and accumate 8 samples by shifting an accumlator left then ORing in the read data bit. Once you have 8 samples loaded write the accumulator to RAM and advance the memory location. Based on the sample rate you could use a timer interrupt handler or if it is really fast you will need assembler code and precise timing loops. If you have a refrence clock or valid pulse, then the answer is very simple since you could use a tiny loop that waits for the rising edge of the clock or valid pulse then reads the data and stores it. Either way, I don't see a need to use the analog to digital converter. Maybe you could explain why you think this would be needed. For the logic analyzer approach do a google search of "pic logic analyzer". You should find my geocities solution and another person's solution.
  3. 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. 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. 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. 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. 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. 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. 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. http://www.geocities.com/ted_rossin/Electronics/Pic/Pic.html
  11. 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?
  12. I do not recommend this technique: http://www.romanblack.com/one_sec.htm Use it only if you have to use timer 0. You can get crystal accurate 1 second delays using timer 2 without having to add the external 32KHz crystal. The reason for the technique at romanblack.com is that timer 0 can not be programmed up to interrupt at a reliable cycle rate. Microchip fixed this limitiation with timer 2 in new PIC processors. With timer, 2 you can program it up to generate an interrupt every N clicks so that it is possible to use a 4,10 or 20 MHz system crystal and use that to drive timer 2 such that you get an interrupt at a nice happy rate. Timer 2 is only an 8-bit counter but it does have a prescaler. You can use a 20 MHz crystal (system clock will be 5 MHz) and then set N to 250 (you have to actually write 249). If you then set the prescaler to 2 you get an interrupt at a lovely rate of 100us or 10 KHz. This is a nice rate that you can do something with. The following code implements a clock. Since I always try to talk out of both sides of my butt, the code below does implement a techique similar to romanblock.com but it is to fine tune out the crystal errors instead of the digital timer errors. You could remove that part of the code and it will still behave nicely. Also, I implemented some code to make a beep. This could also be removed. // // clock.c // This code implements a real time clock with adjust to allow // crystal errors to be adjusted. It also provides functions to // delay for a desired amount of time. // // Ted Rossin // 3-27-2006 // 10-31-2006 // #include <system.h> #include "clock.h" static unsigned char LocalTick100us,GlobalTick100us; static unsigned int LocalTickms; static signed char TickAdjust = 0; static unsigned char LocalSec; ClockType ClockCurrentTime; static unsigned char EnableTone = 0; static unsigned char ToneTickRate; static unsigned char ToneTick; static unsigned char ToneToggle = 0; void interrupt( void ) { // Handle timer2 interrupt if(test_bit(pir1,TMR2IF)){ clear_bit(pir1,TMR2IF); LocalTick100us++; if(LocalTick100us==10){ LocalTickms++; LocalTick100us = 0; if(EnableTone && (LocalTickms&0x07)==0x01){ ToneTickRate++; if(ToneTickRate==15){ EnableTone = 0; } } } if(EnableTone){ ToneTick++; if(ToneTick>ToneTickRate){ ToneTick = 0; if(ToneToggle){ set_bit(porta,1); ToneToggle=0; } else{ clear_bit(porta,1); ToneToggle=1; } } } GlobalTick100us++; if(GlobalTick100us==10){ ClockCurrentTime.Tickms++; GlobalTick100us = 0; if(ClockCurrentTime.Tickms==1000){ ClockCurrentTime.Second++; LocalSec++; if(TickAdjust<0){ if(LocalSec <= -TickAdjust){ ClockCurrentTime.Tickms = 0xffff; // Slow down clock } else{ ClockCurrentTime.Tickms = 0; } } else{ if(LocalSec<=TickAdjust){ ClockCurrentTime.Tickms = 1; // Speed up clock } else{ ClockCurrentTime.Tickms = 0; } } if(ClockCurrentTime.Second==60){ ClockCurrentTime.Second = 0; ClockCurrentTime.Minute++; if(ClockCurrentTime.Minute==60){ ClockCurrentTime.Minute = 0; ClockCurrentTime.Hour++; if(ClockCurrentTime.Hour==24){ ClockCurrentTime.Hour = 0; ClockCurrentTime.Day++; } } } } } } } void ClockBeep(void) { EnableTone = 1; ToneTickRate = 2; ToneTick = 0; } void ClockInitTimer(void) { // Create interrupt every 100us pr2 = 249; // Timer2 period register - 1 t2con = 0x0c; // Timer on divide by 2 // Enable timer 2 interrupt set_bit(intcon, PEIE); set_bit(pie1, TMR2IE); set_bit(intcon, GIE); LocalTick100us = 0; LocalTickms = 0; LocalSec = 0; GlobalTick100us = 0; ToneTick = 0; ToneTickRate = 2; ClockCurrentTime.Day = 0; ClockCurrentTime.Hour = 0; ClockCurrentTime.Minute = 0; ClockCurrentTime.Second = 0; ClockCurrentTime.Tickms = 0; } void ClockWaitms(unsigned int Num) { LocalTickms = 0; while(LocalTickms<Num); } void ClockWait100us(void) { LocalTick100us = 0; while(LocalTick100us<2); } // Returns 0 if equal, -1 if A<B or 1 if A>B signed char ClockCompareTime(ClockType &A,ClockType &B) { if(A.Day<B.Day){ return(-1); } if(A.Day==B.Day){ if(A.Hour<B.Hour){ return(-1); } if(A.Hour==B.Hour){ if(A.Minute<B.Minute){ return(-1); } if(A.Minute==B.Minute){ if(A.Second<B.Second){ return(-1); } if(A.Second==B.Second){ return(0); } else{ return(1); } } else{ return(1); } } else{ return(1); } } else{ return(1); } } // A = A + B void ClockAdvanceTime(ClockType &A,ClockType &B) { A.Second += B.Second; if(A.Second>59){ A.Minute++; A.Second -= 60; } A.Minute += B.Minute; if(A.Minute>59){ A.Hour++; A.Minute -= 60; } A.Hour += B.Hour; if(A.Hour>24){ A.Day++; A.Hour -= 24; } A.Day += B.Day; } void ClockTickAdjust(signed char Amount) { TickAdjust = Amount; }
  13. 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. I like the look of the Russian text but I can't understand it. Is there a translation of this site?
  15. 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.
  16. 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. 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. 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. 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. 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. 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.
  22. I thought the whole point of a senior or graduation project is to prove that you can take an abstract idea and implement it by doing research and design. Asking for help on the web just proves that you should not graduate. I would not hire a person if I knew they did what you are doing as it just proves they are not able to do the job. Why don't you try reading the data sheet on the LM35. It is not very complicated. You would figure out how to implement this project quicker by reading the data sheet than by asking others to do your work. Here is the only help you should receive from this forum. You could have done this yourself with a google search. http://www.national.com/pf/LM/LM35.html
  23. 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. 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. trossin

    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); }
  • Create New...