Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Help with PIC16F886 0-55VDC Voltmeter (code adapted fm Arduino)

Status
Not open for further replies.

mcmsat13

Member level 5
Member level 5
Joined
Apr 24, 2013
Messages
94
Helped
4
Reputation
8
Reaction score
4
Trophy points
1,288
Activity points
2,292
Hello all!
As a learner, I have been doing whatever I could, to Learn Embedded programming.

I just started with LCD experiments what i saw in LCDs scared me initially. I later became little settled the time I started to see characters I desired appear on them and where I want them.

Behold! I thought that writing characters are just the same until I wanted to display sensor readings. for days I am hooked in some places...no escape, really!

Below, I will attach everything concerning this project/experiment.
It is about DC Voltmeter; 0-55VDC.
I first sow this project in Arduino and I simulated it with Proteus and actual hardware and it is working perfectly.
Because I am working with PIC Microcontrollers, I tried Port it and incorporate the code to an 16F886 Project I was experimenting on CCS C which I use,but it fail to display the. All the Static characters I earlier displayed on the 20x04 LCD are still displaying at their specified locations without distortion. Still, the DC value could not display anything anywhere on the LCD. Though I have not actually understand Strings and their rules.
Please cau people here do something for for this DC value to display at its position. I promise after this, i will add it to my non-volatile memory.

Arduino.PNG

Above is the Arduino Circuit which i used to Simulate the original Arduino Version of the project. Below is the Arduino Code:

Code:
*/
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
int analogInput = 0;
float vout = 0.0;
float vin = 0.0;
float R1 = 100000.0; // resistance of R1 (100K) -see text!
float R2 = 10000.0; // resistance of R2 (10K) - see text!
int value = 0;
void setup(){
   pinMode(analogInput, INPUT);
   lcd.begin(16, 2);
   lcd.print("DC VOLTMETER");
}
void loop(){
   // read the value at analog input
   value = analogRead(analogInput);
   vout = (value * 5.0) / 1024.0; // see text
   vin = vout / (R2/(R1+R2)); 
   if (vin<0.09) {
   vin=0.0;//statement to quash undesired reading !
} 
lcd.setCursor(0, 1);
lcd.print("INPUT V= ");
lcd.print(vin);
delay(500);
}


Below is the Circuit of the 16F886 Version. Though the Arduino is just to display the Dc Voltage Value but in the 18F886, I displayed some Characters that are STATIC and then the Variable values have their positions inside them as you can see in the picture/circuit:

16F886.PNG

16F886 code:

Code:
//PIC16F886 with 3-wire LCD Experiments with CCS C Ver. 4.140


//LCD module connections
#define LCD_DATA_PIN PIN_B0
#define LCD_CLOCK_PIN PIN_B1
#define LCD_EN_PIN PIN_B2
//End LCD module connections

#include <16F886.h>
#device ADC = 10
#fuses HS,NOWDT,NOMCLR,NOPROTECT,NOLVP
#use delay(clock = 8000000)
#include <3WireLCD.c>


int value = 0;
int16 BV;
float vin = 0.0;
float vout= 0.0; 
float R1 = 100000.0;             // 100k
float R2 = 10000.0;              // 10k


void main()

{
  lcd_initialize();                      // Initialize LCD module
   
  lcd_cmd(LCD_CLEAR);                       // Clear the LCD
   
//***********************************  FIRST ROW ************************    
  lcd_goto(1, 1);                              // Go to column 3 row 1
  printf(lcd_out, "MY FIRST LCD PROJECT");   //These are Static on the LCD
   
 //*********************************  SECOND ROW ***********************      
  lcd_goto(1, 2);                              // Go to column 4 row 2
  printf(lcd_out, "INPUT:  (   V)(  Hz)");   //These are Static on the LCD
      
//********************************  THIRD ROW ****************************      
  lcd_goto(1, 3);                              // Go to column 4 row 3
  printf(lcd_out, "OUTPUT: (   V)(  Hz)"); //These are Static on the LCD
 
 //******************************** FOURTH ROW ***************************  
  lcd_goto(1, 4);                              // Go to column 4 row 4
  printf(lcd_out, "BATTERY:        VDC");  //These are Static on the LCD  
  delay_ms(200);

  setup_adc(ADC_CLOCK_DIV_8);            // 8Tosc ADC conversion time
  setup_comparator(NC_NC_NC_NC);         // disable comparator module
  delay_ms(10);
  setup_adc_ports( sAN0);                // Select Analog Inputs
  set_adc_channel(0);                     //Select AN0 as ADC Input for BV
  delay_ms(1);                            //Wait 1 ms
  BV = read_adc();                        //Read AN0 and stor in BV
  delay_ms(1);                            //Wait 1 ms
  
  vout = (value* 5.0)/1024.0;
  vin = vout/(R2/(R1+R2));
  if (vin<0.09)
  {
  vin=0.0;                       //statement to kill undesired reading !
  }
  {
  lcd_goto(10,4);
  printf(lcd_out,"%s",vin);      // I want the Vin to display its value here
  delay_ms(10);  
}


  while(TRUE)
{
 }
}

The Files are zipped/RAR including Simulation Schematic and 3-wire library:
 

Attachments

  • 16F886 0-55VDC Voltmeter.rar
    50.2 KB · Views: 170

Re: Arduino to PIC16F886 0-55VDC Voltmeter

This appears to be a matter of feeding a voltage to your ADC, placing it in a variable, converting it to a string of characters, then displaying the string. Did you succeed at doing any of these steps with the PIC16F886?

Also see the list of related threads further down this page. They may provide an answer and/or code concerning your query.
 

Re: Arduino to PIC16F886 0-55VDC Voltmeter

Hi,

Don't stress!

I'm not experienced with PIC nor with C#, thus I just comment your circuit.

Your circuit:
Pot's usually are not made for high voltage. Thus I don't recommend to connect a pot directly with 55V.
In your case I'd not use a pot at all. (If you want to calibrate your voltmeter, then do this in software, this is simple, stable and low noise.)
--> Just use two resistors as voltage divider: 100k / 10k.
This is a 11:1 divider. 55V input become 5V.
--> connect a 1uF capacitor in parallel to the 10k to suppress noise.
--> both, the 10k and the capacitor need a valid, clean GND signal, best AGND. There should be no other connection to get best accuracy and noise.

I see you did not connect ARef. Then most probably you use VCC as reference for the ADC. Be aware that any x% deviation of VCC causes x% (about) deviation in your ADC output.
USB voltage is specified to be within 4.5V ... 5.5V (as far as I remember).
Let's assume you input 44.0V as measurement input. It will be divided down to 4.00V at the ADC input.
With ideal 5.00V microcontroller voltage you will see 44.0V in the display.
But with 4.8V at the microcontroller your display will show 45.8V.
--> I recommend to use a stable voltage ADC_VRef.

PIC schematic:
Why do you use the HC164? I currently don't see a benefit. Even a HC595 will be less problematic because it has an output latch.
Don't forget to use bulk capacitor as well as fast ceramics capacitors to stabilize the power supply.

Klaus

Added:
I just had a view on your code.
I see a couple of float variables. Try to avoid them, they need a lot of ressources.
And I see a lot of divisions. Try to replace them with multiplications or shifting.
Also try to do calculations at compile time rather at run time. Some compilers will recognize and optimize this, some not.
Maybe with this project you don't have ressource problems, but sooner or later you will have.
 

Re: Arduino to PIC16F886 0-55VDC Voltmeter

I'm not sure what compiler routines you use but it looks odd to me that you read the ADC into a variable called 'BV' but then do you calculations and display the value in a variable called 'vout'.

Are you playing 'pick and mix' with chunks of code from different sources?

Brian.
 

Re: Arduino to PIC16F886 0-55VDC Voltmeter

Hi,

Like so often I recommend to use good old paper and pencil.
Create a table with columns for your variables...then go through your code line by line ... and every time you calculate a new value .. read the input values from your table ...and write te result down into the table in a new line.

...or use a debugger.

Klaus
 

Re: Arduino to PIC16F886 0-55VDC Voltmeter

I will edit the code for better understanding. The Pot at 55v rail is dummy. It is not real life thing. I know I can't try such circuit in hardware.
 

Re: Arduino to PIC16F886 0-55VDC Voltmeter

Hi,

I know I can't try such circuit in hardware.
What does this mean?
And what do you gain from such a simulation?

Klaus
 

Re: Arduino to PIC16F886 0-55VDC Voltmeter

Hi,


What does this mean?
And what do you gain from such a simulation?

Klaus

Please understand me. I mean that the current stress on the POT, the effect may not stop me from seeing the result of the LCD display.
Where I run this simulation on Real PIC hardware I use well Filtered Variable DC Power supply. I even connected 5V1 zener diode between ADC pin and ground.
 

Re: Arduino to PIC16F886 0-55VDC Voltmeter

Hi,

to me it makes no sense:
* to use the pot in reality, because it won´t withstand the voltage
* to simulate the pot... when you don´t use it in reality (and you already know that it does not work in reality)

Why make the simulation different to your real circuit.

I even connected 5V1 zener diode between ADC pin and ground.
The same applies here: Why not in simulation?
My recommendation: Include the zener in simulaton and see the big difference (measurement error) the zener causes when measuring high voltage.
I assume it makes voltage measurement above 35V almost impossible (depending on zener type and temperature)

--> It´s your choice whether the simulation is able to show you design errors beforehand...

Klaus
 

Re: Arduino to PIC16F886 0-55VDC Voltmeter

Hi,

to me it makes no sense:
* to use the pot in reality, because it won´t withstand the voltage
* to simulate the pot... when you don´t use it in reality (and you already know that it does not work in reality)

Why make the simulation different to your real circuit.


The same applies here: Why not in simulation?
My recommendation: Include the zener in simulaton and see the big difference (measurement error) the zener causes when measuring high voltage.
I assume it makes voltage measurement above 35V almost impossible (depending on zener type and temperature)

--> It´s your choice whether the simulation is able to show you design errors beforehand...

Klaus

I fully understand your point now. The point is to simulate with the real life components. It's a lesson anyway. Your point is positive and well understood.

Thanks.
 

Solved!
I was finally directed by one of the biggest Admins of https://www.ccsinfo.com/forum, as I later transferred this question to that forum, to read a particular topic in CCS C Manual.
Well I did and I saw from the topics where I was failing it and I corrected myself and hence my Code worked. I will post the full working code tomorrow in case other newbies like me who may get helped with it as i use to in posted codes

I thanked all who tried to help me here and it is funny that I am with another request right here now! Please bear with me, one thing is that; Beginners always ask questions especially the curious ones. sometimes I wonder how these our questions will look like to some experts:

My question is, to some people here who handle Arduino as well as Pic Microcntrollers, how can I convert this type of Arduino Code to C? ;

Code:
   uint32_t start_time = millis();
   while((millis()-start_time) < 1000) //sample for 1 Sec

Or is there another thing in compilers like ; MikroC for PIC, Hi-Tech for PIC, CCS C, that can do this Arduino function?

Thanks
 

My question is, to some people here who handle Arduino as well as Pic Microcntrollers, how can I convert this type of Arduino Code to C? ;

Hi mcmsat12

"Arduino code" is also C

Short answer: Learn how to code in C

Long answer: The "Arduino function" is also a C function, if you want to port that then you need to find the C code for the function millis() in your Arduino C libs/incs/whatever and just copy/paste it, unless it calls other "Arduino functions" In which case you also need to copy/paste those. Or you could simply figure out what the function does (I bet it returns the time in milliseconds) and find a equivalent function in your other C environment. If such function does not exist, then google e.g. c return time in milliseconds and you will get 11 million suggestions.
 

The alternative is to start by understanding what the code is doing - in this case it is providing a delay for a given period of time.
I've not used CCS C for many (many) years but it has a built-in/library function called 'delay_ms' (and there are others - look at the user guide).
The alternative is to use a timer and either loop until the timeout flag is set or have that trigger an interrupt that sets the flag to wait for. The advantage of this approach is that you have have the MCU do other things while you are waiting (if that is appropriate) rather than just wasting cycles.
Susan
 

My question is, to some people here who handle Arduino as well as Pic Microcntrollers, how can I convert this type of Arduino Code to C?
Code:
   uint32_t start_time = millis();
   while((millis()-start_time) < 1000) //sample for 1 Sec

Keep in mind that millis() is nothing else than a function that take the current value from a counter running endlessly at precise intervals (not necessarily with a resolution of 1ms) so this is rather a matter of Library and/or implementation of a similar feature at each of these compilers, but all of them will make use of the same hardware resources if you are using the same microcontroller. In short, not everything you see in Arduino is standard on other compiler's libraries, but most of these features are easily doable.

- - - Updated - - -

I've not used CCS C for many (many) years but it has a built-in/library function called 'delay_ms'

Likewise, I also did not use CCS for long so I can be wrong, but I fear that delay_ms() is a blocking feature, isn't it ?
 

As far as I know the 'delay_xxx' functions ARE blocking but so is the code that @mcmsat13 asked about in Post #11 (and you quoted).
They are also unreliable in terms of accuracy as they don't take any interrupt processing into account.
That is why I also mentioned the ISR option so that other things can happen at the same time. Also why I started with saying that you need to understand what the code is doing - perhaps I should have added 'in context'.
Susan
 
Well, I know that Arduino C also. I would have better addressed it as Arduino syntax or style. I use ISR counter in CSS C for pic and the counter I use is like variable, when the delay runs, MCU will not wait on it . Another delay like it may also be running at the same time while other tasks are running. I am not with a sample code now as I am replying on the move. Maybe when I get home I will post what I am describing here.

Thanks.
 

Well, I know that Arduino C also. I would have better addressed it as Arduino syntax or style.

That doesn't change the fact that it is best for you to learn how to code in C and know your compiler(s), then you could easily translate syntax.

You can only translate Chinese to French if you know both languages, or you can obviously use Google translate but then the French wouldn't understand the meaning. Same goes for compilers.

e.g. "uint32_t start_time = millis();" Is a variable declaration and value assignment in one line.

Maybe the CSS compiler doesn't use "uint32_t" to declare a unsigned 32bit integer, check the CSS reference manual https://www.ccsinfo.com/downloads/ccs_c_manual.pdf. And maybe the CSS compiler doesn't allow variable declaration and value assignment in one line, check the CSS reference manual. In which case the translated line looks like this, and you would have to write the millis() function yourself:

unsigned int32 start_time;
start_time = millis();

Then you have "while((millis()-start_time) < 1000)" which is a simple standard while loop.

I don't find any reason in the CSS reference manual to why this shouldn't work as is. If it gives you a syntax error then let me know the error message. Again you would have to write the millis() function yourself.

Now repeat above for every line of code you want to translate.
 
The final code as it worked. The beginning of the code that is commented out is the Original Arduino code.
The two code works the same now. I saw the Arduino code on the Internet while I am working with PIC18F886
Code:
//PIC16F886 with 3-wire LCD Experiments with CCS C Ver. 4.140
////////////////////////////////////////////////////////////////////
/**                                                               //
                                                                  //
#include <LiquidCrystal.h>                                        //
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);                           //
int analogInput = 0;                                              //
float vout = 0.0;                                                 //
float vin = 0.0;                                                  //
float R1 = 100000.0; // resistance of R1 (100K) -see text!        //
float R2 = 10000.0; // resistance of R2 (10K) - see text!         //
int value = 0;                                                    //
void setup()                                                      //
{                                                                 //
   pinMode(analogInput, INPUT);                                   //
   lcd.begin(16, 2);                                              //
   lcd.print("DC VOLTMETER");                                     //
}                                                                 //
void loop()                                                       //
{                                                                 //
   // read the value at analog input                              //                           
   value = analogRead(analogInput);                               //
   vout = (value * 5.0) / 1024.0;                                 //
   vin = vout / (R2/(R1+R2));                                     //
   if (vin<0.09) {                                                //
   vin=0.0;//statement to quash undesired reading !               //
}                                                                 //
lcd.setCursor(0, 1);                                              //
lcd.print("INPUT V= ");                                           //
lcd.print(vin);                                                   //
delay(500);                                                       //
}  /////////////////////////////////////////////////////////////////
**/
/**  I wanted to convert the above Arduino code to CCS C Code but VOLTAGE could
   not be displayed. The circhiut works fine in Arduino.
**/

//LCD module connections
#define LCD_DATA_PIN PIN_B0
#define LCD_CLOCK_PIN PIN_B1
#define LCD_EN_PIN PIN_B2
//End LCD module connections

#include <16F886.h>
#device ADC = 10
#fuses HS,NOWDT,NOMCLR,NOPROTECT,NOLVP
#use delay(clock = 8000000)
#include <3WireLCD.c>

int16 value =0; 
float vin = 0.0;
float vout= 0.0; 
float R1 = 100000.0;          // 100k
float R2 = 10000.0;           // 10k


void init()
{
  setup_adc(ADC_CLOCK_DIV_8);            // 8Tosc ADC conversion time
  setup_adc_ports( sAN0);                // Select Analog Inputs
  delay_ms(10);
  
}

void main()
{
  init();                           // Configure peripherals/hardware
  lcd_initialize();                      // Initialize LCD module
  delay_ms(100);
   
  lcd_cmd(LCD_CLEAR);                       // Clear the LCD
  
  lcd_goto(5, 1);                              // Go to column 5 row 1
  printf(lcd_out, "DC VOLTMETER"); 
  
  while(TRUE)
  
{
  set_adc_channel(0);                     //Select AN0 as ADC Input for BV
  delay_ms(1);                            //Wait 1 ms
  value = read_adc();                     //Read AN0 and stor in BV
  delay_ms(1);                            //Wait 1 ms
  
  
  vout = (value* 5.0)/1024.0;
  delay_ms(1);
  vin = (vout/(R2/(R1+R2)))+0.05;

 if (vin<0.09)
  {
  vin=0.0;                       //statement to kill undesired reading !
  }
  {
  lcd_goto(1,4);                            // Go to column 1 row 4 
  printf(lcd_out,"Voltage = %3.1gV",vin);   // Display Voltage Value   
  delay_ms(100);  
  }
}
}

- - - Updated - - -

That doesn't change the fact that it is best for you to learn how to code in C and know your compiler(s), then you could easily translate syntax.

You can only translate Chinese to French if you know both languages, or you can obviously use Google translate but then the French wouldn't understand the meaning. Same goes for compilers.

e.g. "uint32_t start_time = millis();" Is a variable declaration and value assignment in one line.

Maybe the CSS compiler doesn't use "uint32_t" to declare a unsigned 32bit integer, check the CSS reference manual https://www.ccsinfo.com/downloads/ccs_c_manual.pdf. And maybe the CSS compiler doesn't allow variable declaration and value assignment in one line, check the CSS reference manual. In which case the translated line looks like this, and you would have to write the millis() function yourself:

unsigned int32 start_time;
start_time = millis();

Then you have "while((millis()-start_time) < 1000)" which is a simple standard while loop.

I don't find any reason in the CSS reference manual to why this shouldn't work as is. If it gives you a syntax error then let me know the error message. Again you would have to write the millis() function yourself.

Now repeat above for every line of code you want to translate.

@ Swend, thanks for your guidelines. This is what I needed to be told. You know some experts talk to some beginners without knowing if they have even attained a medium skill in programming. Some of those expert suggestions without an example may even throw the poster to a more confused situation.

Thanks again for your explanations
 

@ Swend, thanks for your guidelines. This is what I needed to be told. You know some experts talk to some beginners without knowing if they have even attained a medium skill in programming. Some of those expert suggestions without an example may even throw the poster to a more confused situation.

Thanks again for your explanations

You can thank by clicking the "Did you find this post helpful?" button, I understand we get a free banana for every click we get, and I'm hungry.
 
@mcmsat13 - your code might be working but what is the point of the 2nd and 3rd 'delay_ms(1)' statements on either side of the calculation of 'vout'?
I can understand the delay after selecting the ADC channel and before reading it (not knowing the functions, can you not select the channel as part of the one-time initialisation?) and possibly the one at the bottom of the loop, but the others seem (literally) a waste of time.
Also be careful of floating point calculations (even integer divisions) on these very small MCUs. I don't know if the Arduino chip that you used has a FPU but these MCUs certainly don't and they even struggle with integer multiplication and division let alone floating point.
Your compiler might come to your rescue for lines such as
Code:
vin = (vout/(R2/(R1+R2)))+0.05;
and try to do some of the consonant calculations (R1 and R2 as floating point constants) but you are far better off if you can do some of these things for your self. For example, the above is equivalent to
Code:
vin = vout * 11 + 0.05;
Personally I would prefer to keep everything as integers. For example, the ADC will give you a 10-bit integer (I assume by the division by 1024) so it will be in the range from 0 to 1023 (equivalent to 0V to 5V). If you combine the two calculations (first of 'vout' and then of 'vin') you effectively get a multiplication by 55. That is equivalent to a range of 0 to 56,265 which can still fit into a 16-bit value.
You compare vin with 0.09 - that is really the equivalent of comparing our integer value with 8 (0.09 *1024/11 = 8.37).
To print the value you could switch to floating point and divide by 1024.0 (the range becomes 0 to 59.94) - after all you then block for 100mS so taking a long time here is of no real consequence. However there are ways to do this with integer values but I'll leave that up to you to read up on 'fixed point arithmetic'
(BTW - on these 8-bit devices, even 16-bit integers require multiple instructions to manipulate but these are always better than the floating point functions.)
Susan
 
Last edited:
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top