PLEASE HELP WITH ADC PIC16F877A - Page 1
Forum section: electronics / beginners

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 01, 2016, 11:07:23 pm
content: Gidday all,Can someone please help me with setting up and displaying ADC on a PIC16F877A using MPLAB.I have spent quite a bit of time trying to find sample files on line but they all seem to be incomplete with custom header files missing or written for some other compiler.It seems to be a bit of a tradition, not to share some of the secrets of programming in MPLAB although most people are more than keen to help once a question is asked.I have found lots of other compiler versions that look to be complete but as I am a newbie I have no idea how to convert them to MPLAB.I will supply my code if it is a help.I am using a 1602 LCD.I want to display something likeSUPPLY IMBALANCE+15.1V -14.8VORD.C. VOLTS = +15.0VD.C. VOLTS = -14.9VIn my code there are severalif ------ else if (FAULT_?==0) .These should be self explanatory.They display an error message for faults etc. in a power supply I am building.Thank you for being so patient with us newbie's with what may seem to you to be silly or simple question.waiting your helpBILL.

author: pyroesp
author_rank: Regular Contributor
timestamp: September 01, 2016, 11:57:39 pm
content: First thing I see is this:Code:unsigned int a;TRISA = 00000; // UNUSED A/D TO BE SET AS REQUIREDTRISB = 00000000; // LCD DATA AT B0 - B3 ICSP AT B6 & B7TRISC = 11111111; // EIGHT INPUTSTRISD = 00000000; // currently set to all outputTRISE = 000; // UNUSED A/D TO BE SET AS REQUIREDYou binary constant should be prefixed by "0b", if not, they're just integers.EDIT:You should have a look at this link :https://electrosome.com/adc-pic-microcontroller-hi-tech-c/The code shown should be pretty much what you need.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 02, 2016, 03:04:13 am
content: Thank you for that.I will have a go with the code but have one questionI understand that the value read, needs to be calculated from the 10bit data as it can't be displayed directly but also needs formatting into a string so it can be displayed on the 16x02 LCD something like"Volts = +15.15V ""Volts = -14.90V "I hope to display volts as 12.34 ie. 2 decimal places.Thank you,BILL.

author: Ian.M
author_rank: Super Contributor
timestamp: September 02, 2016, 03:33:52 am
content: The ADC is only 10 bit, which meand it only has 1024 counts over its full range. If you arrange the reference voltage and input divider so that the LSB (1 count) represents 0.01V, the full scale reading will be 10.23V. However you are giving examples around 15V so you cant get two decimal places resolution unless you ofsset the zero (i.e a voltmeter that only reads from 10V to 20V) The best you could hope for would be a last digit that goes 0 2 4 6 8, and a full scale reading of 20.46V.If it was a multimeter it would only be a 3 digit one. A 4 digit one would need a 14 bit ADC, better than most MCUs have on-chip.

author: DTJ
author_rank: Super Contributor
timestamp: September 02, 2016, 04:34:24 am
content: I'm a novice myself but here's my take....1) Get your voltage into a form that represents your voltage.ie Volts = 1250 where volts is a unsigned int (0-65535 range)2) Use the integer to ascii to convert the volts value to characters for display to your lcdCreate a array called volt_charsThen do the integer to ascii conversionitoa(voltage ,volt_char ,10)Voltage is your input integer representing voltagevolt_char is the array the characters will end up inthe 10 is for radix 10so runningitoa(1250,volt_char,10)will result in the volt_char array containing:volt_char = '1' = 0x31volt_char = '2' = 0x32volt_char = '5' = 0x35volt_char = '0' = 0x303) Now you have characters in registers that you can more easily output to the display.Set cursor to line 1 position 0 and write "Volts = "then:send volt_char to LCDsend volt_char to LCDsend '.' to LCDsend volt_char to LCDsend volt_char to LCDdisplay will show 'Volts = 12.50'I've done this off the top of my head so there may be some errors. Check with your compiler as some compilers have the input value and output array transposed in the itoa() expression.I hope this is of some help.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 02, 2016, 01:37:21 pm
content: I have been rather busy today but I will have a look at your suggestions tomorrowand try them out.Thank youBILL.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 05, 2016, 01:23:01 am
content: Still not having much luck.I forgot to mention that I am a 63 year old newbie, using MPLAB.I have a couple of units working.One running the code I have supplied in the OP at the top.This has a PIC16F877A and is the one I want to incorporate into the power supply.The other is a PIC16F84A project, both with 1602 LCD displays..why do we say LCD Displays.LIQUID CRYSTAL DISPLAY DISPLAY???As suggested by IAN.M I have revised my plans to be 1 decimal place.I also think my description of output was a little misleadingSUPPLY IMBALANCE+15.1V -14.8VORD.C. VOLTS = +15.0VD.C. VOLTS = -14.9Vthese were just numbers out of my head.The power supply I am building is actually 30 volts 3 amps per rail.The display should be more like---SUPPLY IMBALANCE+25.0V -24.6VORD.C. VOLTS = +25.0VD.C. VOLTS = -24.6VI think I prefer the latter version.I want the Micro Processor to monitor the voltages on each rail and display a message if there is a difference of more than say 0.3vI know I will have to invert the neg rail to be able to read it or would the comparators be able to do this job without inverting the Neg rail?If so how would I do this.I have added to my code//************************* START ADC ***************************************void ADC_Init(){ADCON0 = 0x41; //ADC Module Turned ON and Clock is selectedADCON1 = 0xC0; //All pins as Analog Input//With reference voltages VDD and VSS}unsigned int ADC_Read(unsigned char channel){if(channel > 7) //If Invalid channel selectedreturn 0; //Return 0ADCON0 &= 0xC5; //Clearing the Channel Selection BitsADCON0 |= channel<<3; //Setting the required BitsDelayMs(2); //Acquisition time to charge hold capacitorGO_nDONE = 1; //Initializes A/D Conversionwhile(GO_nDONE); //Wait for A/D Conversion to completereturn ((ADRESH<<+ADRESL); //Returns Result}//******************************* END ADC *********************************that smiley face should be 8 close bracket with no spaceand inside the void main(void) // MAIN PROCESSING HERE //else if (FAULT_7==0){unsigned int V, DisplayVolt, i;char Volt = "00.0"; // has error 358char buf;V = ADC_Read(0); //Read Analog Channel 0DisplayVolt = V * 2;Volt = (DisplayVolt/1000) + 48; // has error 981Volt = (DisplayVolt/100)%10 + 48; // has error 981Volt = (DisplayVolt/10)%10 + 48; // has error 981Lcd_Init(); // initialize LCDLcd_Clear(); // clear LCDLcd_Set_Cursor(1,1);Lcd_Write_String ("test");Lcd_Set_Cursor(2,1);sprintf (buf, "volts = : %a",i); // has error 975Lcd_Write_String(2,5,Volt); // has error 186 & 357DelayMs(500); // Hold for 500 mswhile(1); //Infinite Loop}this section has several errorsI am using mplab compilerProduct Version: MPLAB X IDE v2.10Java: 1.7.0_25; Java HotSpot(TM) 64-Bit Server VM 23.25-b01System: Windows 8 version 6.2 running on amd64; Cp1252; en_AU (mplab)Userdir: C:\Users\BILL\AppData\Roaming\.mplab_ide\dev\v2.10taken from HELP\ABOUTactually using Windows 10I await your any help I can getThank youBILL.

author: DTJ
author_rank: Super Contributor
timestamp: September 05, 2016, 04:46:39 am
content: Quote from: neko efecktz on September 05, 2016, 01:23:01 amI'm not far behind you Bill!I'm pretty green at this too so I'm not too flash at reading your code. To get mine working I broke it down into very small pieces.ADC===I set up the ADC and wrote the value into a register so I could view it.I'd put a break point or a while(1); instruction after this to stop the code execution.This allowed me to focus on getting the ADC working.Conversion of ADC result to integers for display=================================Instead of using the ADC output I just put a fixed value in a register and played with the itoa() function until I got the correct ASCII characters in the array.This approach makes it easy to see if the itoa() works for all the expected values etc.Sending it to the LCD===============Using the same approach as for the ADC I sent known values to the LCD.Once I got this working I swapped in the values from the array filled by the itoa() function.To format it on the LCD================I wrote functions to;1) put the cursor at a defined location "LCD_cursor()"2) write a string to the LCD "LCD_string()"3) write a character to the LCD "LCD_char()"So to get your preferred format:D.C. VOLTS = +25.0VD.C. VOLTS = -24.6VSet cursor to line 1 location 1.Write string "D.C. VOLTS = " <16 characters including spacesPut cursor at line 1 position 13Write character "tens" to LCDWrite character "units" to LCDWrite character "." to LCDWrite character "tenths" to LCDThen go to line 2 position 1 and repeat for the second line.Breaking it up to small chunklets makes it easier to fault find.I think you will need to invert the negative rail monitoring.

author: Ian.M
author_rank: Super Contributor
timestamp: September 05, 2016, 07:23:35 am
content: Although there are kludges that let you avoid inverting the -ve rail monitoring signal (e.g. a potential divider between -ve rail and +vref), using an OPAMP lets you minimise the input impedance seen by the ADC without having to have a lot of current through the potentisal divider. I therefore would recommend an inverting buffer for the -ve rail and a non-inverting one for the +ve rail. If you use a 4.096V reference, a 7:1 divider for the +ve rail to give a gain of 1/8 and an input resistor 8 times the feedback resistor for the inverting buffer for a gain of -1/8, you can use a 5V rail to rail dual OPAMP for the buffers, and it will read up to 32.77V with 32mV resolution. Round to the nearest 0.1V for display.Its well worth using an external reference as otherwise you need to maintain your 5V rail accurate and stable to 0.1%, which is likely to be difficult when it is also powering a HD44780 compatible LCD. You probably can also share the reference with the PSU's control circuits.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 06, 2016, 02:28:46 am
content: Thank you IAN.M and DTJ.I'm a shift worker, 2:30pm to 12:30am so I've just got out of bed a few minutes ago and found your replies.I'm usually up around 9:00 to 9:30 but had a bit of a sleep in this morning.I have found a few circuits using a duel opamp for the inputs and was the way I intended to go once I got a basic setup running.I will have a go at DTJ's suggestions and see if I can get that working.Thank you for your helpBILL.

author: Ian.M
author_rank: Super Contributor
timestamp: September 06, 2016, 02:52:37 am
content: N.B. 8 bit PIC ADCs rapidly loose accuracy if Vref < 2/3 Vdd. (rule of thumb, but can be confirmed by individual specs in datasheets) If you are using a 5V PIC, DO NOT use a 2.56V or lower reference as it will loose more accuracy than one gains by reducing the input range.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 06, 2016, 03:51:52 am
content: Thank you Ian.I have started to work on the code but got side tracked for lunch now I'm off to work.nearly 2:00pm.Hope to have more time tomorrow.Bill.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 09, 2016, 12:07:30 am
content: Still having trouble displaying my analog reading.You may think I am a bit dumb but as I said I'm a newbie and just can't get my head around some things.Too many grey hairs.Please have a look at the attached file and make suggestions.Some of this code I found on line and others I used suggestions from DTJThank youBILL

author: Ian.M
author_rank: Super Contributor
timestamp: September 09, 2016, 01:04:26 am
content: For *MOST* code problems, screenshots of the code in an IDE are a PITA for your audience to debug. MPLAB X is specifically known to have dodgy error hiliting so seeing the actual red squiggles is not normally helpful, especially since they don't help locate compile time errors within a line.If you don't mind disclosing your whole sourcecode, its better to attach the .c file (and any custom .h files it relies on). For multi-file projects, use the MPLAB 'package' option on the project menu, which creates a ZIP archive of the minimal set of files to reproduce the project. Copy/Paste the error messages from the output window into CODE tags for inline posting or a text file for attaching.We can then see *ALL* the definitions/declarations in your program using our preferred programming editor or IDE, cross-referencing it to the line numbers given in the error messages and, assuming we have compatible toolchains installed, even try fixing stuff.However the issue this time is the definition of Volt_Char, which needs to be an array, and the use of LCD_Write_String() which expects a null terminated string (i.e a pointer to a character aray containing that), not the single char returned by accessing a single element of a char array. I'd probably make the Volt_Char array large enough to include the decimal point and initialise it with a dummy value including the decimal point. e.g:Code:char Volt_Char="nn.n";N.B. XC8 is an ANSI C89 compiler with *SOME* poorly documented C99 extensions. You should stick to C89 style definitions/declarations which means they need to come before ALL other statements in any block. The block starts at line 324 with its opening brace {. You then invoke ADC_Init() then start declaring variables - this is at least bad style and at worst under a strict C89 compiler, illegal. Move ADC_Init() to after the declarations, and for your sanity, leave a blank line between the last declaration and the first actual statement!

author: DTJ
author_rank: Super Contributor
timestamp: September 09, 2016, 01:19:39 am
content: Ian, is;char Volt_Char="nn.n"the same as;char Volt_CharExcept I imagine the former will initialise the array with n,n,.,n and the 2nd one will initialise all values as 0x00Bill - it looks like you are almost there! Are you using break points to stop the program and examine variables to see if they contain what you expect?

author: Ian.M
author_rank: Super Contributor
timestamp: September 09, 2016, 01:30:46 am
content: No. as you've forgotten the null terminator. Its equivalent to:Code:char Volt_Char="nn.n";One *could* alternatively use an uninitialised array:Code:char Volt_Char;and explicitly assign the '.' and the null terminator in sequence with processing each digit, which might save a couple of instructions if program memory is really tight.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 09, 2016, 01:31:33 am
content: here is the main c file and header filethank you for your quick responseBILL.

author: Ian.M
author_rank: Super Contributor
timestamp: September 09, 2016, 01:47:43 am
content: Although one can put executable code and variable initialisation in header files, its *EXTREMELY* bad style to do so except for certain special cases involving inline functions. Seehttp://www.gamedev.net/page/resources/_/technical/general-programming/organizing-code-files-in-c-and-c-r1798As soon as you resolve the current errors, I strongly recommend refactoring the LCD code into seperate LCD.c and LCD.h files.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 09, 2016, 02:12:31 am
content: IAN and DTJ.My original version of this project used a sample file by hi-Techit used 3 custom header files plus stdio.h, stdlib.h and xc.h and 2 .C files main.c & lcd.c.I found the one I'm currently using on line published by ELECTROSOME.It seemed a but better and most of it I understood a bit better then the Hi-Tech one.I did some editing in the header file like adding my own #defines in place of the ones that were there and made a couple of other minor changes.I did find a couple of errors in both of the files but was able to sort them out OK.one major problem I found in the Hi-Tech version is setting of delays.QUOTE from the header file...Note that there are range limits: x must not exceed 255 - for xtal frequencies > 12MHz the range for DelayUs is even smaller.To use DelayUs it is only necessary to include this file; to use DelayMs you must include delay.c in your project.to get a delay of 1 second i had to useDelayMs(250;DelayMs(250;DelayMs(250;DelayMs(250;even then is was not quite 1 second.and it didn't seem to matter what crystal I was using 4 ,8, 10, 12 or 20Meg.Note... the delay also varied.The ELECTROSOME version seems to work with any value entered. tested to about 10 sec but seems OK using the same range of crystals.I will however look at the code soon to split it up.I'm still working on how to produce an array etc.any help would be appreciated.BILL

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 09, 2016, 02:19:53 am
content: IANyou mentioned those silly red squiggles,I was watching a video a couple of months ago, of a dude creating a LCD driver program and his screen was full of the red dots.Probably half of the lines visible on the screen at any one time scrolling up and down had them but he was able to compile and upload to his PIC then run it without problems.When it went back to the screen the dots were gone and a lot of the code that was visible had changed.As Dave says "smells like B.S."BILL.

author: Ian.M
author_rank: Super Contributor
timestamp: September 09, 2016, 04:03:20 am
content: Videos are usually fairly pointless for tutoring you to write code. They can be useful for stuff like leaning the IDE or setting up a debug session, or even tutoring you about algorithms.A good code tutorial will usually be a PDF + source files - anything that doesn't let you take your time reading it, scroll up and down, annotate and copy stuff from it is counterproductive. If it contains video, it will only be short snippits e.g. to show you how to configure the project if that invoolves many complex dialogs or pages of settings.Due to the structure of the C language, it is difficult for the compiler to recover from some types of syntax error so a single error often causes many lines of bogus errors after it. Fix the original error and any identical ones and most or all of the rest usually simply vanish at the next build.However I agree that a video showing code apparently changing during a build stinks!The old HiTech compiler had fairly crude delay routines. More recent versions and XC8 implement a _delay() psuedofunction, inserted by the linker and it is used to support __delay_ms() and __delay_us() macros for fixed delays defined in the standard headers. They cant generate variable delays, nor generate very long delays (over a threshold defined in Tcy in the release notes) so you still need a looping delay function for those cases.Your LCD header is still borked - Lcd_Port() is using hard-coded pin names so the #defines for D4 - D7 are meaningless!

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 09, 2016, 04:29:53 am
content: Thanks Ian,have just // out the 4 lines// #define D4 RB0 // LCD PIN 11 TO CHIP PIN 33// #define D5 RB1 // LCD PIN 12TO CHIP PIN 34// #define D6 RB2 // LCD PIN 13 TO CHIP PIN 35// #define D7 RB3 // LCD PIN 14 TO CHIP PIN 36I will leave them in the code for reference, just disabled.As I said I watched the video and was disillusioned by it.unfortunately the bloke involved has a lot of videos on line and started to cause so much confusion I think it set me back a few months considering I have only been messing about with PIC's for a few months I'm back to where I started..by the wayDoes this forum have a spelling checker/corrector .It does a spelling check but i can't find an equivilent to Words  commandThanksBILL.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 09, 2016, 07:26:48 am
content: gidday IAN,I just got the ADC kind of working.I Think I just Need to mess about with the maths to get the right voltage to display.DisplayVolt = ADC_Read(0); //Read Analog Channel 0Volt_Char = (DisplayVolt/1000) + 48;Volt_Char = (DisplayVolt/100)%10 + 48;Volt_Char = (DisplayVolt/10)%10 + 48;I had to reduce each of the divisors by half. ie. 1000 now = 500 100 now = 50 10 now = 5need to work in this area some more.I do remember there was a divide by 2 in there somewhere but I must have deleted it. I will try to find the sample code I used.Any idea what the %10 is for?I had to change String to Char in 3 places.Lcd_Write_Char(Volt_Char); // was Lcd_Write_String (Volt_Char);Lcd_Write_Char(Volt_Char);Lcd_Write_String(".");Lcd_Write_Char(Volt_Char);If you look at the code that does the maths I think that is all wrongI'm applying 4.85 volts and displaying 05.1 volts error of 0.25volts3.269 volts displays 4.3 volts error of 1.031 voltsGrounding the input gives 00.0 voltsLeaving it open circuit gives 05.1 voltsCan you see where it is wrong.I will have a play with it and see how I go.Thank youBILL.

author: DTJ
author_rank: Super Contributor
timestamp: September 09, 2016, 12:18:16 pm
content: Quote from: neko efecktz on September 09, 2016, 07:26:48 amHey Bill have you tried using a break point or just sticking a while(1); in the code to see if the ADC result is reasonable, then move the break point and see if the calculated value is reasonable?Sounds like your getting there.

author: dannyf
author_rank: Super Contributor
timestamp: September 09, 2016, 03:32:00 pm
content: I would suggest that you step back for a while.Coding isn't about putting a bunch of code together so it produces the desired outcome.To me, it is first about the objectives and logic to achieve that objective effectively and efficiently.For simple tasks like yours, it may not sound that necessary but as you start to work on more complex projects, it becomes increasingly life and death, figuratively speaking.Two things for you to think about:1. It is generally unwise to put code in a .h file. Create a LCD.C file to hold the code instead.2. You probably don't need all the LCD initialization in the while loop.I would also encourage you to read up on coding standard in C. Your code is in pretty good shape structure wise but more modulization will help.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 10, 2016, 12:14:55 am
content: Thanks DTJ and dannyf.I knew about the coding practices having minimal code in a header file but just wanted to get away from the hi-tech version that had 3 .h files and 2 .c files while the whole thing had some major problems that even I as a newbie could see.max delay of 255 ms and less for micro seconds and having to use the delay.c file just to use milli seconds.See my post from Yesterday at 12:12:31 PMThe note was taken from the delay.h fileIan.m recommended to look at an instruction Manual Yesterday at 11:47:43 AMSeehttp://www.gamedev.net/page/resources/_/technical/general-programming/organizing-code-files-in-c-and-c-r1798I have downloaded it into a Word document which will allow me to easily add notes etc for future reference.There is a link to an updated version but it looks the same except diagrams are now in B/W instead of colour / color ?? why change it when it was ok ??and a couple of places I found quote marks " " addedkept the original version.DTJ.I will try putting a while(1) into the code and see what happens.tick tick tick "time passing" tick tickNo different, only getting "DC VOLTs = +02.5"with about 4.72V appliedand "DC VOLTs = +01.8" with 3.269 volts applied.grounding the input gives "DC VOLTs = +00.0"The error is non linier.The values I gave last night were after I had modified the code to try to get more accurate values.I have since changed back to original valuesVolt_Char = DisplayVolt/1000 + 48; // I had changed 1000 to 500Volt_Char = (DisplayVolt/100)%10 + 48; // I had changed 100 to 50Volt_Char = (DisplayVolt/10)%10 + 48; // I had changed 10 to 5but other similar examples I found were using the 1000, 100, 10can anyone tell me what the purpose of the % is for???here is the code I'm using//********************** READ AND DISPLAY ADC VALUE ****************************else if (FAULT_7==0){char Volt_Char, DisplayVolt, InVolt; // sample code didn't have this line but i get errors if I take it out.ADC_Init(); // Volt_Char is the 5 correct. I substituted  and it still worked .InVolt = ADC_Read(0); //Read Analog Channel 0DisplayVolt = InVolt *2;Volt_Char = DisplayVolt/1000 + 48;Volt_Char = (DisplayVolt/100)%10 + 48;Volt_Char = (DisplayVolt/10)%10 + 48;Lcd_Init(); // initialize LCDLcd_Clear(); // clear LCDLcd_Set_Cursor(1,1);Lcd_Write_String ("DC VOLTs = + "); // DISPLAY TO READLcd_Set_Cursor (1,13); //"DC VOLTS = +00.0"Lcd_Write_Char(Volt_Char);Lcd_Write_Char(Volt_Char);Lcd_Write_String(".");Lcd_Write_Char(Volt_Char);DelayMs(500); // Hold for 500 mswhile(1); //Infinite Loop}//********************** END READ AND DISPLAY ADC VALUE ************************I'm currently usingProduct Version: MPLAB X IDE v2.10would it be an advantage to go to MPLAB IDE v8 or at my level of non expertise stick with what I have for the moment.Thank you for all your help so far and in the future.BILL.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 10, 2016, 01:23:08 am
content: Just been doing some checking.OBSERVATION...Input AN0 is selected InVolt = ADC_Read(0); //Read Analog Channel 0Input pin has a measured voltage on it of 4.88 volts. not applied to it, coming out of it.Input pin AN1 - AN7 all have 0 volts coming out.Changed active input input AN1 is selected InVolt = ADC_Read(1); //Read Analog Channel 0Input pin has a measured voltage on it of 4.88 volts. not applied to it, coming out of it.Input pin AN1 - AN7 all have 0 volts coming out.HoweverUsing input 1 InVolt = ADC_Read(1);I am still getting the same reading for 4.89Volts in, displays "DC VOLTS = +02.5"for 3.12 volts in I am reading "DC VOLTS = +00.4"using input 6 InVolt = ADC_Read(6);I am still getting the same reading for 4.89Volts in, displays "DC VOLTS = +02.5"for 3.12 volts in I am reading "DC VOLTS = +00.4"using input 7 InVolt = ADC_Read(7);I am still getting the same reading for 4.89Volts in, displays "DC VOLTS = +02.5"for 3.12 volts in I am reading "DC VOLTS = +00.4"BILL

author: Ian.M
author_rank: Super Contributor
timestamp: September 10, 2016, 02:51:13 am
content: ADC non-linearity is usually a result of mis-configuring the ADC, or not allowing enough settling time before each conversion, or excessive input impedance.Also, you need to look at the raw ADC results, so it would be a good idea to display them. (Hint: look up UTOA in appendix A of the XC8 manual)Lets see your current schematic. I also strongly recommend packaging your project and attaching it as we need to see your current code anyway, and that will make it much easier for us if we want to build it to check any changes we propose.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 10, 2016, 05:56:37 am
content: Gidday IAN,Sorry about the delay,had to go shopping and get a hair cut. took longer than I expected.I found we can't send .rar files but that's all I have.I had a time limited version of winzip but it requires purchase to keep using it.I changed the extension from .zip to .rar in hope of fooling the system.It used to work but not sure now dayswell here goes.BILL

author: Ian.M
author_rank: Super Contributor
timestamp: September 10, 2016, 06:26:43 am
content: No problems.IZARChandled your archive seamlessly even with the mismatched extension. I dumped WinZip many many moons ago. IZARC is freeware, the licence permits commercial use, and it can do just about everything WinZip can.What about the schematic? Preferably in 16 colour GIF or PNG format for best resolution with minimum file size.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 10, 2016, 06:40:38 am
content: IAN,I don't have a schematic done to my exact pin layout and I will try to do one tonightI have a version of Proteus that I can print from but have only tried once.might take a while.I have someone calling in shortly for an hour or so then it will be dinner time.I will start on the drawing as soon as I post this.Could you tell me what general part of the world you hail from?I'm from NZ living in Australia for 40 years.BILL

author: Ian.M
author_rank: Super Contributor
timestamp: September 10, 2016, 07:13:42 am
content: Your code documents the LCD connections adequately. If Proteus is too much of a PITA, just sketch the ADC input circuits in BLACK ink on WHITE paper and scan it then reduce to greyscale then 16 colour GIF at a usable resolution.N.B. Photos of schematics are rarely satisfactory unless the camera is held rigidly directly over the center of the schematic at a minimum distance of 5x the diagonal paper size, zoomed in to fill the image, under shadow-free noon daylight equivalent lightingI've already found one bug - main.c line 158:Code:TRISA = 0b00000; // UNUSED A/D TO BE SET AS REQUIREDwhich means your AN0 - AN4 ADC inputs are all configured asOUTPUTS!That certainly wont work for reading analog voltages.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 10, 2016, 07:59:59 am
content: Thanks IAN,just tried changing TRISA = 0b11111;still reading 2.5 volts instead of 4.8 whatevwer voltsI thought that they were all turned on as analogthis is part of the code I downloaded.After changing TRISA the 4.8volts from A0 has gone, but now all of PORTA has about 355mV outputvoid ADC_Init(){ADCON0 = 0x41; //ADC Module Turned ON and Clock is selectedADCON1 = 0xC0; //All pins as Analog Input//With reference voltages VDD and VSS}will keep tryingThank youBILL.

author: Ian.M
author_rank: Super Contributor
timestamp: September 10, 2016, 08:17:39 am
content: Quote from: neko efecktz on September 10, 2016, 07:59:59 amThat's normal with a 10Meg DVM on an O/C input pin. See datasheet section 17.2:Quote1uA through 1Meg is 1V.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 10, 2016, 08:28:51 am
content: here is the schematic.As I said only tried the program out once before.A lot of mucking about in hyper_space but i got there.

author: Ian.M
author_rank: Super Contributor
timestamp: September 10, 2016, 08:57:48 am
content: We needed to know about the analog input circuits you were using. How were you applying the 3.12V you mentioned?Unless you are doing something weird involving current or resistance sensing, normal PIC ADC inputs should always be connected to a voltage source, and to maintain the specified accuracy it should have a source impedance of less than 2.5K (required to maintain 1/2 LSB error limit with max +/-1uA leakage current). If you leave the ADC inputs floating they will certainly give weird results. Due to the current surge required to charge the internal hold capacitor, the reading for a floating pin or one with excessive source impedance will almost certainly not correspond to the pin voltage as measured with a DVM. A capacitor to ground at the pin >= 0.25uF (for this family) will ensure that the voltage at the pin does not change by more than 1/2 LSB during sampling, which helps stabilize the reading if you are violating the source impedance limit.You can and should groundunusedones by clearing both their Port and Tris bits.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 10, 2016, 10:33:23 am
content: Ian.Just finished dinner,I am feeding the known voltage directly into the ADC pin.no series, no shunting.The two input voltages I was working with are from one of those power supplies that piggyback onto a breadboard.It is being supplied by a 9V 1A switch mode plug packs.They are supposed to be 5.00v and 3.30v but they are cheep ones and not very good.When I first started playing with PICs I started using a 5V 2A plug pack directly and then found it was putting out just over 6.1 volts.Quickly put that one away.At the moment I am measuring 4.99V at the input pin with my dvm and displaying 02.5V.this is with TRISA = 0b00001 only AN0 set to input.BILL.

author: Ian.M
author_rank: Super Contributor
timestamp: September 10, 2016, 11:02:43 am
content: So what's the raw ADC result?It should be 1023 (decimal) or 0x03FF (hex) with AN0 tied to Vdd and 0 with AN0 tied to Vss, all with the ADC configured for internal references: Vdd as Vref+ and Vss as Vref-.If its anything else the chip's suspect.Code:{unsigned int V, DisplayVolt, i;char Volt = "00.0";char buf;V = ADC_Read(0); //Read Analog Channel 0DisplayVolt = V * 2;Volt = (DisplayVolt/1000) + 48;Volt = (DisplayVolt/100)%10 + 48;Volt = (DisplayVolt/10)%10 + 48;Lcd_Init(); // initialize LCDLcd_Clear(); // clear LCDLcd_Set_Cursor(1,1);Lcd_Write_String ("test");Lcd_Set_Cursor(2,1);sprintf (buf, "volts = : %a",i);Lcd_Write_String(2,5,Volt);DelayMs(500); // Hold for 500 mswhile(1); //Infinite Loop}DisplayVolt = V * 2;is suspect. 1023*2 is 2046. Your display routine would show that as "2.04"Try:Code:DisplayVolt = (V * 625U+312U)>>7; // scale by 1000 * 5.00/1024 with rounding

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 10, 2016, 12:38:16 pm
content: Ian,I was starting to suspect the chip myselfthat large section of code you sent back is from an early attempt at getting it all running.in the files I uploaded today and i think in the one I uploaded the other day they were rem'd out as a block with /* */the correct one is just below it in the code.I added the lineDisplayVolt = (V * 625U+312U)>>7; // scale by 1000 * 5.00/1024 with roundingsubstitutingInVoltforV.now it is only displaying02.2How do I check the raw ADCI have set up a break point on line 343 (may be changed since I sent it to you.run the programhover the mouse over key words ie. InVolt, Display_Volt etcI'm not finding anything that looks like 1023 (decimal) or 0x03FF (hex)if I hover over Volt_charI get 5 lines representing the 5 parts to the arrayVolt_char = 0; 0x30Volt_char = 2; 0x32Volt_char = nul; 0x00Volt_char = 2; 0x32Volt_char = nul; 0x00the display is showing 02. the last digit is not showing

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 10, 2016, 01:07:51 pm
content: just thought of why the last digit was missingI was stopping the program before it had a chance to display it.BILL,

author: Ian.M
author_rank: Super Contributor
timestamp: September 10, 2016, 01:16:57 pm
content: Ah, I was using PFE, (an editor that doesn't do syntax hiliting) as I didn't have MPLAB X open, so I missed the fact it was commented out.This chunk?Code://********************** READ AND DISPLAY ADC VALUE ****************************else if (FAULT_7==0){char Volt_Char, DisplayVolt, InVolt;ADC_Init();InVolt = ADC_Read(0); //Read Analog Channel 0DisplayVolt = InVolt *2;Volt_Char = DisplayVolt/1000 + 48;Volt_Char = (DisplayVolt/100)%10 + 48;Volt_Char = (DisplayVolt/10)%10 + 48;Lcd_Init(); // initialize LCDLcd_Clear(); // clear LCDLcd_Set_Cursor(1,1);Lcd_Write_String ("DC VOLTz = + "); // DISPLAY TO READLcd_Set_Cursor (1,13); //"DC VOLTS = +00.0"Lcd_Write_Char(Volt_Char);Lcd_Write_Char(Volt_Char);Lcd_Write_String(".");Lcd_Write_Char(Volt_Char);DelayMs(500); // Hold for 500 ms// while(1); //Infinite Loop}//********************** END READ AND DISPLAY ADC VALUE ************************That works a bit differently as I see you aren't stuffing the decimal point into the string. However if InVolt doesn't contain what you expect, something's badly borked.You may want to insert a line:Code:NOP();where you want to be able to put a breakpoint, as due to a peculiarity of the debug silicon known as 'breakpoint skidding' it stops on the instruction *AFTER* the breakpoint address.Applying voltages directly to the ANn]analog pins while they were configured as output pins wasn't very kind to it. If you haven't got a 'known good' spare PIC, disconnect AN0, set all ANn]pins as inputs (bad practice to leave them floating but if a pin is borked tying it to either rail may cause more problems), and try again using a ANn]pin you haven't previously messed with! Don't forget to change the code to match the pin you've chosen.For future reference, copying what Microchip do on their demo boards - i.e .a 10K pot between Vdd and Vss with 0.1uF cap to Vss from its wiper, and a 1K resistor between the wiper and the ADC input - is a far better choice for testing. The 1K resistor prevents any damage if the pin is set as output. It doesn't quite meet the ADC input impedance specs so it may be out a count or two

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 10, 2016, 01:54:37 pm
content: I tried several other inputs. No Good.Looks like as you said, I may have fried the analog inputs.But would eight damaged inputs all behave the same and give the same results?Will try to pick up some more chips over the next few days.I'll let you know how I go.Thanks for all of your help.BILL...

author: Ian.M
author_rank: Super Contributor
timestamp: September 10, 2016, 05:42:35 pm
content: It depends what's happened to the pin's I/O circuits. All the ANnpins have a MOSFET transmission gate (a type of analog switch) that connects them one at a time to the actual ADC module input. If one of those transmission gates is damaged, all other ADC inputs will be affected. Try tying /MCLR low to hold all I/O pins tristate and go round the ANnpins checking if any are stuck high or low or have excessive leakage current.I've taken the HiTech C v9.83 LCD/ADC demo for a PIC16F877A on a PICdem 2 Plus board, ported it to XC8, improved its ADC code for a 10 bit result and changed it to display the raw ADC result and the voltage to 2 DP using fixed point maths. You'd have to alter the pin definitions in LCD.h to suit your board, but I thought it would help to have some simple code to run the ADC so you can be reasonably confident the hardware is good.Here's the main loop so you can see how simple outputting a voltage to the LCD can be:Code:unsigned int adres, last_value;unsigned int volts, decivolts;unsigned char outString;Code:last_value=-1; // Force update on first passwhile(1){adres=ReadADC(0);if(adres!=last_value){volts=( // scale to voltage as fixed point, 2DP, with rounding.adres*(unsigned long)(MAXVOLTAGE*100)+ADCMAX/2)/ADCMAX;decivolts=volts%100; // extract decimalsvolts=volts/100; //extract integer voltslcd_clear();sprintf(outString,"AN0: %3.3Xh, %u.%2.2uV",adres,volts,decivolts);lcd_puts(outString);}last_value=adres;}N.B. I haven't got the hardware available to test the port at the moment - I've been careful not to mess up the ADC settings and have simulated it thoroughly so it *should* be O.K. Its a MPLAB 8 zipped project because I couldn't be arsed to port it to MPLAB X !

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 11, 2016, 02:07:23 am
content: Thanks Ian,I tried your suggestion with tying MCLR down.Here are the results.ALL ANALOG AS INPUT UP TO >1.0V ON EACH PIN MY HAND PROXIMITY TO THE METER LEAD CAUSES TO TO GO UPALL ANALOG AS OUTPUT UP TO >1.0V ON EACH PIN MY HAND PROXIMITY TO THE METER LEAD CAUSES TO TO GO UPAN4 AS INPUT ALL OTHERS AS OUTPUT UP TO >1.0V ON EACH PIN DITTOAN4 AS OUTPUT ALL OTHERS AS INPUT UP TO >1.0V ON EACH PIN DITTOWHILE THE PICKIT3 WAS CONNECTED THE VOLTAGES WERE ALL DOWN AROUND 70mVI have some work to do around the house today but I will look at using the code you uploaded.I will also look at RS COMPONENTS for some more chips.Is there much work in conversion from PIC16F877A to PIC16F887?I know that the CLK1/OSC1 and CLK2/OSC2 are shared with RA6 & RA7. and MCLR is shared with RE3There was another 40 pin chip i think you mentioned one time, would you remember what it was?.ThanksBILL.

author: Ian.M
author_rank: Super Contributor
timestamp: September 11, 2016, 03:31:19 am
content: Tying /MCLR low disables the PIC, (assuming it isn't one that supports disabling /MCLR) so it doesn't matter what code you have in it. I assume you were measuring between Vss and each pin. The results indicate that none of the pins are hard-shorted to Vss or Vdd. Repeat with the meter between Vdd and each pin and see if the voltages are similar which would indicate input leakage currents of around +/- 0.1uA, well within spec.Its *REMOTELY POSSIBLE* there is a shorted transmission gate, but they are a lot harder to diagnose because only one is normally turned on at a time, for a very brief pulse for ADC sampling at the start of each conversion. Just about the only way to detect that would be to set all possible inputs as Analog, and run code that samples the ADC as fast as possible discarding the result. Pull the input being sampled high, then check all the other inputs with a scope. If any have a brief high going pulse at the sample rate, that channel has a shorted transmission gate. Repeat, sampling a different pin to reduce the possibillity you picked a bad channel to sample.Other possibilities are that the 6.1V overvoltage on Vdd damaged the PIC. This is extremely unlikely, unless that was just an average and the actual USB PSU output was very spiky as its rated for up to 5.5V normal operation and to withstand 7.5V without damage.You can also get odd things happening if any of the Vdd or Vss pins are disconnected, or there isn't enough decoupling near the chip. As a rough rule of thumb, use 0.1uF between Vdd and Vss right next to the chip at *EVERY* pair of Vdd and Vss pins. The ADC converter pulls significant current spikes from +Vref and -Vref during operation so if the supply pins are poorly decoupled for internal Vref, you can get bogus results.Are you 100% certain you have a 4MHz crystal installed? Any crystal above 10MHz would result in your code not giving the ADC a long enough Tad, which is known to cause incorrect results. Also a much lower crystal frequency can cause problems - if Tad is far too large, enough charge leaks off the sampling and successive approximation caps to give a bad result.Otherwise, once you've eliminated low probability hardware problems, it must be a code issue, which is why I ported the HiTech PICdem 2 Plus code, so you'd have some sample code for the ADC that has a high probability of working. You can either use its LCD routines, patching the pin and port definitions to match your board, or patch in your own LCD library. It uses sprintf() for formatted output, which one generally avoids on small 8 bit systems because the printf routines are generally bloated overkill for most applications, however that gets you working fixed point display with a lot less user code than other options.The PIC16F887 is fairly similar from a C programmer's point of view. The ADC module is a little different - instead of selecting analog input configurations by row number from a table, each input has an individual control bit, (in the ANSEL and ANSELH SFRs). The Vref+ and Vref- source selections also have individual control bits. However once you've got it configured, you use it in the same way as on an '877A. You don't need to worry about the differences in the oscillator pins - in any of the crystal modes or EXTRC they are '877A compatible. Its only if you use the internal oscillator that you get them back as extra I/O pins. Generally one leaves RE3 configured as /MCLR, with an external pullup, but sometimes it can be convenient to make it an input. However it must *NOT* be left floating. I have one on a demo boad with a breadboard, so if you get stuck I am likely to be able to actually run your code on real hardware.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 11, 2016, 07:48:05 am
content: IAN,I have a bit of time to do some writing but still have some work around here to do.The missus gets cranky if i spend too much time on line.And wasting time and money on that bloody junk.I tell her IT'S A HOBBY, women, cant live with them not allowed to shoot them.I will see if I can insert your code into mine tomorrow morning.or look at the full Hi-Tech code.I will also fire up my old CRO , Tektronix-422 circa 1965 according the the dates on the pcbs.has micro valves called NuvistorThe 8056 Nuvistor used in the input amplifier of the 422 can be replaced by a MPF102 JFET.It works so it might do the trick.The 6.1 volts I mentioned was with my first project using PIC16F84A.One night I was working late with this one and i accidently inserted the chip into the ZIF base back to front. power pins are dirrectly opposite each other in pin 5 and 14 the two middle pins.Took a couple of minutes to figure out why the PICKIT-3 couldnt see the chip.I spent some time trying to see if I had configured PICKIT-3 wrong.Chip still works ok. is running a display inn front of me now.Can't remember if that was with the 6.1v or not.I have placed 4 bypass caps each 0.1uF in the board.One each side of the chip and the others are about 30mm away basically at each end of the chip.One of them is about 10mm from the 10uF tant cap.Attached is a PDF of my board.First double sided board in over 30 years but done with laser printer / iron on process.It needed about 18 feed through links.I have made a couple of mods to it and have put in a couple of bodge wires so I can fully use PORT B for the display and ICSPI still have a little work to do on the revised version.If I go for the PIC16F887 I would still use the same board and use MCLR as a reset as in the current board..Thank you once again for your help.BILL

author: StillTrying
author_rank: Super Contributor
timestamp: September 11, 2016, 08:06:32 am
content: it must *NOT* be left floatingYep.Before you give up on that chip go around it and check there's no floating inputs, it's easiest to just set them as outputs, - just one floating input digital or analog can make it go nuts.

author: Ian.M
author_rank: Super Contributor
timestamp: September 11, 2016, 08:34:56 am
content: The PCB layout doesn't look too bad. At least its got enough decoupling. I'd have used a topside ground plane, but I'm fussy that way! I assume you've had other stuff running OK on that board.A reversed supply could have FUBARed the whole ADC module (or any other part of the chip), but usually on a current limited supply, that sort of mistake doesn't do any damage as the I/O pin ESD protection clamp diodes short out the supply. The '877A has 33 I/O pins, each with clamp diodes with a max rating of 20mA so the odds ar it will survive if the supply current limit is under 660mA.Its probably not worth chasing down the remote possibility of a blown transmission gate with your scope - I'd jump straight to trying different code. or a different PIC if you have one handy.I generally buy chips for development three at a time - one to use, one for a spare , and one to keep in its packet till I need one that's 'factory fresh'.

author: Ian.M
author_rank: Super Contributor
timestamp: September 11, 2016, 09:19:29 am
content: Meanwhile I've been putting together a fast fixed point unsigned int to ASCII routine that avoids any use of the % modulo or / division operators (except for division by 2 because its not safe to right shift a signed number (implementation defined sign bit handling) and one cant assume char is unsigned).The intention is to replace the slow/bloated printf in the HiTech based code I posted or the clumsy digit extraction with % and / by powers of 10 in your code. Unfortunately I haven't commented it properly yet as the ancient DOS compiler I was testing it under doesn't support single line // comments.Code:/************************************************************** utoafp() - converts an unsigned integer to 5 digit ASCII* string with leading zeros and (optionally) inserts a* decimal point.* Parameters:* n - unsigned integer to convert.* s - pointer to string buffer, min. 7 bytes.* p - places in front of the d.p.* dp - no. of decimal places, 0 won't insert a '.'.* Returns:* pointer to the string or NULL if theres been an error* (i.e. if n is too big for the number of places p).**************************************************************/char* utoafp(unsigned int n, char* s, char p, char dp){const unsigned int subtbl[]={40000,4000,400,40,4};const char subtbl_len=sizeof(subtbl)/sizeof(unsigned int);char digit,e,t,j, *sp;unsigned int q;if(dp>5 || dp<0) return(NULL);if(p>5 || p<0) return(NULL);if(dp+p>5) return(NULL);sp=s;for(j=5-p-dp;j<subtbl_len;j++){if(j==subtbl_len-dp) *(sp++)='.';digit=0;e=4;q=subtbl;do{if(n>=q){digit+=e;n-=q;}else{q>>=1;e/=2;}}while(e);if(digit>9) return(NULL);*(sp++)='0'+digit;}*sp=0;return(s);}Usage:Code:r=utoafp(1234, s, 2, 3);with s defined as an array of char and r as a pointer to char, will return a pointer to the string "01.234". If you try to convert something that wont fit, it returns a NULL pointer. It does NOT add a leading zero in front of the d.p. if the no. of places (p) in front of the d.p. is 0. if the decimal places (dp) is 0, it omits the d.p.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 13, 2016, 01:47:31 am
content: Good morning Ian,I have Just started to look at he Hi_Tech code you uploaded and there seems to be a file or two missing.I think there is supposed to be a couple of files called DELAY.C and LCD.H* LCD interface example* Uses routines from delay.c* This code will interface to a standard LCD controller* like the Hitachi HD44780. It uses it in 4 or 8 bit modeIf You could find it and upload it I would appreciate it.I ordered some chips today should be here in a couple of days.Thanks for all your help.BILL.

author: Ian.M
author_rank: Super Contributor
timestamp: September 13, 2016, 02:42:42 am
content: That comment on line 3 of lcd.c is a lie. HiTech never updated it when they changed the code to use the compiler's builtin delays. I didn't edit lcd.c at all, but if you want to blank line 3 (apart from the * to keep the same line numbering), go ahead.The zip I attached toreply #42has four source files:* picdem2.c - The main program, also ADC and fixed point number functions.* lcd.c - LCD routines.* lcd.h - Header for LCD routines.* cfg16F877A.c - PIC CONFIG only, as its bad style to put #pragma config directives in a header.Its also got the MPLAB 8 project file picdem2.mcp, which you can import into MPLAB X. However, as MPLAB X import from 8 is rather flakey, its probably easier just to create a new empty PIC16F877A XC8 project, uzip the lot in its .X folder and add all the source files.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 13, 2016, 03:17:26 am
content: IAN,Ok will do that.I Had a look through the code and there is a lot I don't understand but give me a few days and I will try to figure it outI will, as you said need to configure the LCD pins for my board.I will probably Be back about Friday.I have 3 day week ends and work 10 hours per day.Mean while I ordered 2 new PIC16F877A from RS components at $8.09 eachFarnells / Element 14 wanted $13.28 ea.I'll be back an 2 or 3 days with a progress report.BILL.

author: DTJ
author_rank: Super Contributor
timestamp: September 13, 2016, 05:52:01 am
content: Quote from: neko efecktz on September 13, 2016, 03:17:26 amPlus Farnell want you to pay delivery!

author: Ian.M
author_rank: Super Contributor
timestamp: September 13, 2016, 06:50:11 am
content: You might want to drop $19.22 on afive-pack of PIC16F887-I/P. It would be easy to port your code to them, they are more versatile and less than half the price per chip.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 14, 2016, 01:35:55 am
content: Good morning IAN and DTJ and any one else listening in,DTJ, I thought I had lost you.The new PIC16F877A chips arrived this morning at about 9:30. Only placed the order yesterday at 10:20am.I was still asleep when they arrived.I inserted one and it made no difference.Ian,The other day you asked to confirm the crystal to be 4MHzIt is labeled and checks out with frequency counter and scope to be 4MEG. CONFIRMEDYou commented on my pcb layout.You suggested a top side ground plane.I will be adding that to the updated design once I get this project working correctly.When I set up the files you sent, into a new project there were red dots on every__delay_us and __delay_msI inserted theDELAY.Hsupplied with Hi-Tech samples.The same one is used in several projects and in each project they look the same.UnfortunatelyDELAY.Hhas no delay ms so I had to also installDELAY.Cwhich contains what is requiredHowever, Why was it able to work / simulate on your system but not on mine without a delay header file.I had to add#include "delay.h"into the code.I will go through all of the samples and see if there is one that contains both micro seconds and milli secondsThis is the ADC initialization I have used.from what I have read the Acquisition time should be about 20 - 25us not ms.I changed it to 25us and the ADC is still giving the wrong results.Can you see anything else that may be the problem.What aboutclk division factorI have read that it is required but I don't seem to have it in my code.I'm not even sure where it would go but I figure somewhere within the ADCON part ofvoid ADC_Init()//*******************************************void ADC_Init(){ADCON0 = 0x41; //ADC Module Turned ON and Clock is selectedADCON1 = 0xC0; //All pins as Analog Input With reference voltages VDD and VSS}unsigned int ADC_Read(unsigned char channel){if(channel > 7) return 0; //If Invalid channel selected Return 0ADCON0 &= 0xC5; //Clearing the Channel Selection BitsADCON0 |= channel<<3; //Setting the required BitsDelayUs(25); //Acquisition time to charge hold capacitor// was DelayMs(25);GO_nDONE = 1; //Initializes A/D Conversionwhile(GO_nDONE); //Wait for A/D Conversion to completereturn ((ADRESH<<8)+ADRESL); //Returns Result}//********************************************I am starting to work out what I need to change in your code to match up to my board with the LCD.The way it is done is a little different to what I have worked on, only 2 projects including this one.anyway thanks for your helpBILL.

author: DTJ
author_rank: Super Contributor
timestamp: September 14, 2016, 02:25:44 am
content: Quote from: neko efecktz on September 14, 2016, 01:35:55 amNah I'm still here. Ian's the expert, I don't have much to contribute so I'm following along to learn what I can.

author: StillTrying
author_rank: Super Contributor
timestamp: September 14, 2016, 02:34:13 am
content: ADCON0 = 0x41; //ADC Module Turned ON and Clock is selectedADCON1 = 0xC0I make them Fosc/64, = the value for a 20M osc.

author: Ian.M
author_rank: Super Contributor
timestamp: September 14, 2016, 02:42:26 am
content: MPLAB X red squiggles *LIE*! Try building the code. If the compiler gives any errors you have a real problem, otherwise its just MPLAB X being stupid. There was a specific problem with older versions of MPLAB X and the XC8 compiler, where the toolsuite was passing different options to the Netbeans syntax checker/hilter than those it put in the makefile so the syntax checker never saw the #defines for the delay macros in pic.h so red squiggled every occurrence even though the compiler had no problem using them.The clock division factor is set by various ADCS bits in ADCON0 and ADCON1. Most newer devices have then grouped in a single register, but the old ones with the original 10 bit ADC are a P.I.T.A that way. Actually, arguably they are named wrong in the datasheet as ADCS2 is the LSB!WTF were Microchip smoking at the time ?!?The actual clock divisor used is 2(ADCS1 ADCS0 ADCS2)+1, apart from (11 x) which are the Frc clock.I'll be expressing them with ADCS2 as the LSB henceforth.You've got them defined in two magic numbers:Code:ADCON0 = 0x41; //ADC Module Turned ON and Clock is selectedADCON1 = 0xC0; //All pins as Analog Input With reference voltages VDD and VSSIf you expressed them in binary and provided a key, you'd know what was going on:Code:// ADCON0: ADCS1 ADCS0 CHS2 CHS1 CHS0 GO/DONE --x-- ADONADCON0 = 0b01000001; //ADC Module Turned ON and Clock is selected// ADCON1: ADFM ADCS2 --x-- --x-- PCFG3 PCFG2 PCFG1 PCFG0ADCON1 = 0x11000000; //All pins as Analog Input With reference voltages VDD and VSSSo its obvious that the ADC ADCS bits are set to(00 1)(01 1), which TABLE 11-1 in the datasheet tells us is16 Tosc.4 Tosc and is invalid[ for Fosc>2.5MHz!You would need 8 Tosc for a Tad of 2us (must be >1.6us) sowill need tocouldchange the ADCS bits accordingly (to0 01)as faster conversions are generally preferable if you have a lot of other processing and are busy-waiting for the ADC result. N.B. Grossly excessive Tad can cause loss of accuracy due to charge leakage. however 4ms is within the acceptable range.Here's how I'd handle it, bearing in mind my comment about their order:Code:PIE1bits.ADIE=0;// not interrupt drivenADCON1bits.PCFG=0b0000; // All analog, internal refs. See DS39582B-page 128.ADCON0bits.ADCS1=0; // ADCS=(01 0), Tad=8*Tosc (2us @Fosc=4MHz)ADCON0bits.ADCS0=1;ADCON1bits.ADCS2=0; // Datasheet WTF: ADCS2 is LSB !!!ADCON1bits.ADFM=1; // Right JustifiedADCON0bits.ADON=1;// *FINALLY* enable A2D converterMagic numbers in your code are *BAD*. Used once and properly documented they are forgiveable but without that documentation they are *EVIL*. I wouldn't be surprised to find four hex digits you didn't document have wasted nearly two weeks of your time and $16 of your money.@StillTrying,Quote from: StillTrying on September 14, 2016, 02:34:13 amI don't think so! You obviously misread the *EVIL* *MAGIC* *NUMBERS* !However you can be forgiven as its not your code, and I misread them myself earlier in this topic when I checked the O.P'scode attached to reply #28.Edit: Thanks for the correction by Still trying - I misread the Tad setting yet again inspite of showing correctly how to decode it. Dyslexia and Binary is a bad combo!

author: StillTrying
author_rank: Super Contributor
timestamp: September 14, 2016, 03:19:12 am
content: I haven't looked at any of the attachments in this thread, I just got the hex values from 3 posts above, converted to binary in my head and tried to lay them over the data sheet table.I haven't got MPLAB X so can't open that link!Code:Rar! }ÔHƒ)I 3, PIC16F877A LCD.X\build\default\debug\main.p1 °ÿæt Í Í}ÔHƒ)I 3, PIC16F877A LCD.X\build\default\debug\main.p1 °ÿæt Í

author: Ian.M
author_rank: Super Contributor
timestamp: September 14, 2016, 05:00:29 am
content: @StillTrying: Its a misnamed RAR archive.IZARC(freeware) opens it just fine. Inside it is a folder with the source + a lot of MPLAB X crap. However for your convenience, I'll attach it as a real ZIP file containing a MPLAB 8 ZIP packged project and no MPLAB X crap.To double check, I just openedExcalibur 2.0, put it in Comp Sci mode entered:41C0and got:0100 0001 1100 0000bwhich is exactly the same as I posted and decoded above. Humans don't do mental arithmtic in binary very well . . .

author: StillTrying
author_rank: Super Contributor
timestamp: September 14, 2016, 02:29:01 pm
content: Yeah, if I write the binary nibbles down I get Fosc/16 = 4 us for the ADC clk.I'm not very good with embedded C, so only looking at small snippets, from main.c in PIC16F877A LCD.zip this bit doesn't look right.else if (FAULT_7==0){charVolt_Char, DisplayVolt,InVolt;ADC_Init();InVolt = ADC_Read(0);//Read Analog Channel 0

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 15, 2016, 01:36:42 am
content: GOOD MORNING EVERYONE. (a bad impression of Robin Williams there.)Ian, DTJ and StillTryinggood newsIan,I incorporated the ADC parts from your code and I am getting a display if 5.00v with an input of 4.94 voltsand 3.30V with an input of 3.2 volts.There is one small problem. But I know what the problem is.With the 5 volt supply connected across a 10k pot I am able to take the input down to zero v and display 0.00VAs I wind the pot up, the display seems to be showing near to the correct voltage however the refresh rate of the LCD seems to change and it flickers badly.Or is this the ADC taking longer to read?So much so that the display is only readable when I turn up the contrast.It is only at each end of the pot that the display is clear and stable, Not Flashing.I duplicated the experiment with 2 x 2k2 resistors and the display was flashing, at mid point, slightly but much easier to read.I added 3 more resistors to the chain Now 10.1k and the display is about the same as using the pot.This is most likely input impedance not giving a good read.The display is showing approx 100mV high across most of the range.Now all I have to do is work out how to pre-scale the input to allow for reading > 30 volts. Probably Max 35 volts ie. divide by 7.In the final project I will need about 4 analog input for V+ V- and two for temperature of each of the heat sinks.Each ADC will only be displaying anything if a fault occurs. ie. over temp or supply imbalance.I will however have a switch to allow me to manually monitor voltages and temperatures.Thank you for all of your help and suggestions.Come over for a BBQ and some beer one day.BILL. (Much Happier.)

author: Ian.M
author_rank: Super Contributor
timestamp: September 15, 2016, 01:47:43 am
content: Try 0.1uf from the ADC input pin to Vss. It should take a lot of the 'flicker' out over the middle half of the pot's range.

author: DTJ
author_rank: Super Contributor
timestamp: September 15, 2016, 02:02:03 am
content: Bill are you updating the LCD with readings "as fast as you can"?As Ian says the 0.1uF will clean up the signal. In addition to this perhaps try putting a delay in so the LCD only updates say every 200mS or whatever so you can see what's going on. If you still have problems with a noisy sample perhaps sample multiple times and do an average.It's great when it works isn't it!

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 15, 2016, 02:54:20 am
content: OK.That worked.the caps didn't do a lot.made some difference but not a cure.The delay is perfect.I got sooo excited about getting it all working I forgot to put the delay back in that I had in the original attempts.I had some photos of the PCBDuring various stages of construction but my phone died and had to be replaced under warranty.Tomorrow I will take some more pictures of the completed board and put then into this feed.I will have to clear a space and set it all up before taking pictures.My desk is a bit of a mess.Once againThank you for all of your help.BILL.

author: StillTrying
author_rank: Super Contributor
timestamp: September 15, 2016, 03:24:54 pm
content: Well I'm glad you're getting accurate readings from the ADC, - but it's not bleeding obvious to me what the final fix was.Display flicker, other than use a delay, move the print position (only) and just update the 4 characters 'V.VV', or don't update them at all if their value hasn't changed from last time.Am I looking at an obsolete version of main.c ? I still can't see how you get the 10 to 16 bits of the ADC reading into a 8 bit char. Is it one of those C things that works, - until it doesn't.else if (FAULT_7==0){charVolt_Char, DisplayVolt,InVolt;ADC_Init();InVolt = ADC_Read(0);//Read Analog Channel 0DisplayVolt =InVolt*2;

author: Ian.M
author_rank: Super Contributor
timestamp: September 15, 2016, 04:01:04 pm
content: Must be an obsolete version of main.c. Bill hasn't attached any code since I posted the XC8 port of the HiTech C demo code for the ADC on a PICdem 2 Plus with PIC16F877A fitted. back in reply #42.@Bill (O.P.): Package your projectUSING THE MPLAB X PROJECT MENU OPTION TO DO SOand attach it That puts us in a much better position to help you with getting it working for multiple channels and correct scaling. I suggested much earlier that if you care about the accuracy, you'd use a 4.096V external reference rather than the PIC's 5V rail. You'll also need to calibrate your input dividers and inverting buffer for the -ve rail. You can either physically twiddle presets (which should be chosen to have an adjustment range only slightly greater than the wort case error due to fixed resistor and reference tolerences, or you can do the calibration is software. The more complex way is to have a calibration mode i.e. store the factors and any offsets in EEPROM, but if you are building this as a one-off project and don't mind recompiling for your specific board, one could simply measure the voltages accurately, and calculate and hard code the calibration factors as #defined constants in a header file.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 16, 2016, 12:04:44 am
content: Good morning everyone.I have done some more mods to the program and have included some pictures and the latest version of main.cI had to go to work just a few minutes after my last post yesterday so I didn't have time to do the pictures and tidy up the main.cI was messing about this morning with the #define MAXVOLTAGE 5.00and made it 500.00 a picture of the result is included.After I set up the second line on the display and had it working, I found in the code/* this is the maximum value of an A2D conversion. */#define MAXVOLTAGE 5.00 // prescale here#define ADCMAX (1U<<10) // One greater than max. count for 10 bit ADCvoid init(void){// lcd_init(FOURBIT_MODE);PIE1bits.ADIE=0; // not interrupt drivenADCON1bits.PCFG=0b1110; // Only AN0 as analogADCON0bits.ADCS0=1; // ADCS=0b001, Tad=8*Tosc (2us @Fosc=4MHz)ADCON0bits.ADCS1=0;ADCON1bits.ADCS2=0;ADCON1bits.ADFM=1; // Right JustifiedADCON0bits.ADON=1; // enable A2D converter}I hadn't change this value but the AN1 still worked when I setTRISA = 0b00011;Also I noticed there are only 4 I/O in that line of code but there are actually 8 AN I/O or am I misreading the way the code is written?Anyway my next step is to design the hardware to get the power supply connected to the inputs.I will be using OpAmps to reduce the voltage to the right level and polarity.Plus a 5.1v zener diode on each input for safety.I will also be including thermal sensors and display temperature of two heat sinks and maybe the transformers.The whole power supply will be going into a ABS 2RU rack enclosure mounted on 3mm aluminium plate.I picked up a couple from Jaycar Electronics for about $8.50 each and a couple of 1RU for $6.50 each. Unsold StockOnce again I would like to thank everyone that has helped me in this project with comments and suggestionsand a special thank you to Ian, without your help Ian, I was about to give up on the Whole idea of having analog.

author: dannyf
author_rank: Super Contributor
timestamp: September 16, 2016, 12:22:15 am
content: That's not the best code you could have written: when you write a piece of code, try to isolate them into modules in a logic fashion so that those modules can be used later on in other projects. For every piece of code you write, you should write them in a way that you don't need to write them in the future.Take the latest example: I would have written them this way:Code:void init(void){lcd_init(FOURBIT_MODE); //initialize the lcdadc_init(); //initialize the adc//other functions here}//initialize the adcvoid adc_init(void) {PIE1bits.ADIE=0; // not interrupt drivenADCON1bits.PCFG=0b1110; // Only AN0 as analogADCON0bits.ADCS0=1; // ADCS=0b001, Tad=8*Tosc (2us @Fosc=4MHz)ADCON0bits.ADCS1=0;ADCON1bits.ADCS2=0;ADCON1bits.ADFM=1; // Right JustifiedADCON0bits.ADON=1; // enable A2D converter}Put those files in the appropriate .h/.c files, like adc.h/adc.c, or lcd.h/lcd.cSo in the future, all you do is to copy those files into your new project and reconfigure them for the appropriate pins. Hit the compile and you are confident that your code will work.Again, the only reason you are writing a piece of code is so you don't have to write them in the future. Those pieces are "investments" of yours so you can rip the benefits over and over again.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 16, 2016, 12:51:54 am
content: DANNYF,Thank you for your comments, but I didn't write the code.It was taken from a Hi-Tech program supplied to me by Ian.I know my code needS a little better structure but I am still learning.I have to tidy up my LCD.H file which is working fine but I knew from the start I would need to break it down into a couple of files.However, as I am only just starting to work with PICS and my first projects use LCD I have everything together in just two files.I will be splitting it up at a later date.LCD.H into LCD.H and LCD.Cand MAIN.C into MAIN.C and ADC.C or something like that. (Modified this post. Fixed a file name mistake)Hopefully by my next project post I will have things a little better.Thank you for your comments.BILL.

author: dannyf
author_rank: Super Contributor
timestamp: September 16, 2016, 12:56:39 am
content: QuoteDoesn't really matter where you got it. Anyone, Hi-Tech included, is perfectly capable of writting shitty code, like this example demonstrates. There are tons of hd44780 code out there and you should have no trouble getting them to work for y ou.QuoteYou generally want to have a main.c,

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 16, 2016, 01:10:44 am
content: Point taken DannyI dont know Why I put PIC16F877A.C It actually is MAIN.CSorry about the confusion.BILL

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 16, 2016, 03:03:58 am
content: Dear all,Please find the attached zip file of my LCD program with ADC.I have left it with max voltage set to 30v #define MAXVOLTAGE 30.0This actually displays as 99.99V not 99.9V as I thought it would.If you make it to be greater than 100.00 volts it displays 4 or 5 digits ie. 99.99v 999.99vSo Long And Thanks For All The Fish.I'll Be Back.BILL.

author: StillTrying
author_rank: Super Contributor
timestamp: September 17, 2016, 02:31:30 am
content: All of the 'main.c's including the last one posted, are Last Modified 10/9/2016 15:43 which seems a long time ago!But while there I tried to see (from its files) what the compiler does with the char/int InVolt problem when it needs the 2 bytes, Ithinkit overwrites the first byte of int HADFAULT.

author: neko efecktz
author_rank: Regular Contributor
timestamp: September 17, 2016, 06:47:08 am
content: very sorry about that.I picked up an older version and didn't notice.here is the latest version.I have started to pull the files apart into a more logical set up as suggested.Been shopping today and just found your request.This version is working properly as far as I can tell, but needs more work to tidy it up and add more ADC inputs, to measure temperature.once again sorry bout that.BILL.Sorry I forgot that I couldn't send .rar files in this forumhere is a zip file of the complete set up as of to date.BILL.