Hey, just wanted to say thanks to GioppY for this circuit. It helped me a lot. I built my own modeled after this one. I also rewrote the firmware, in C. I couldn't make heads or tails of the BASIC code. Ironic. Anyway, thought I would post my source in case anyone else was looking at this circuit.
Some pictures of my setup:http://www.mrkowasaki.com/cpgallery/...s.php?album=10
Code:
/***************************************************************************\
* *
* *
* *
* *
* Description: Firmware for the PIC 12F675 micro controller. Monitors a *
* 0-5v analog signal across pin GP0 and scales to the original input *
* signal. *
* *
* *
* NO WARRANTY, EXPRESS OR IMPLIED. YOUR MILEAGE MAY VARY. *
* *
* Software written by Demus *
* Circuit designed by GioppY *
* *
* Compiler: mikroC DEMO version *
* *
* Notes: mikroC is very bloated. Any use of the math functions increased *
* the ROM size over the 1K limit. This tiny little bit of software left *
* only 17 bytes of free space. Virtually every part of the source was *
* groomed for space concerns, hence the "strange" style of code. I used *
* this circuit in conjunction with the Linksys MAX233 hack to monitor *
* several solar powered wifi stations remotely. *
* Enjoy. *
* *
* *
\***************************************************************************/
// Miscellaneous debugging functions. Due to space constraints you're better
// off embedding the function contents wherever you had planned on calling it
// from. It saves a few call/ret instructions worth of space.
void write_crlf ()
{
Soft_Uart_Write (10);
Soft_Uart_Write (13);
}
// Wrapper
// Again, only useful for debugging.
void uart_write_str (char *data)
{
while (*data)
Soft_Uart_Write (*data++);
}
// This is where the real magic happens. Using some very basic
// algebra and my own resistance measurements of the circuit
// I was able to device a formula to obtain the battery voltage
// to two decimal places without using any floating point math.
// The PIC converts a 0-5V signal to a digital signal, a number
// between 0 and 1023. Converting back to an analog voltage
// representation is fairly easy and given by this formula:
// (digital value/1024) * 5V = GP0 voltage
// I then measured the voltage drop after the potentiometer,
// and then right at the battery to determine the correct
// ratio for MY circuit. It was 0.242 and leads way to this formula:
// GP0 voltage / BAT voltage = 0.242
// With some simple math, these two formulas can be substituted into
// each other and we arrive at:
// (digital value/1024) * 5V = 0.242 BAT voltage
// Convert the decimal to a fraction, solve for BAT and then multiply
// both sides by 100. This gives you the two decimal precision without
// having to deal with floating point numbers. The math libraries are too
// big to use for this project. And I couldn't find any reasonable
// way to output the float in anything but raw notation.
void displayVoltage (unsigned long value)
{
unsigned long batCentiVolts;
unsigned long a,b;
// Simplified formula, technically we'll end up with centi-volts.
batCentiVolts = value * 500000 / 247808;
// The only issue with converting our number to a string this way is
// that A must not contain less digits than the number we are processing.
// Since we know exactly what range of numbers we will be dealing with
// it's ok in the situation.
a = 10000; // Maximum of 100V
// Skip any leading digits
while (batCentiVolts < a)
a /= 10;
// Strip off one digit at a time, and output to the serial console
// This is pretty much long division.
while (batCentiVolts)
{
// Determine quotient
b = batCentiVolts / a;
// Add value to base ASCII code for '0'.
Soft_Uart_Write ((unsigned char) (b + 0x30));
// If we've just done the 3rd last digit, it means we
// need to output the decimal.
if (a==100)
Soft_Uart_Write (0x2E); // '.'
// Carry over the remainder and repeat
batCentiVolts %= a;
// Reduce the divisor
a /= 10;
}
// Send a CR LF to keep the output nicely formatted
Soft_Uart_Write (10);
Soft_Uart_Write (13);
}
// It's very important to keep your oscillator calibration
// Software UART is extremely unreliable otherwise.
// For reference, the calibration is stored in the two bytes
// of the ROM.
void set_osc_cal(void) {
asm {
bsf STATUS, RP0
call 0x3ff
movwf OSCCAL
bcf STATUS, RP0
}
}
void init_ports ()
{
CMCON = 7; // Turn off the comparators
VRCON = 0; // Turn off CVref circuit
WPU = 0; // Disable pull up
IOCB = 0;
TRISIO = (1<<0) | (1<<3); // Configure pins 0 and 3 as input
ADCON0 = (1<<0) | (1<<7) ; // Enable ADC and select right justified results
ANSEL = (1<<6) | (1<<4) | (1<<0); // Select analog processing for pin 0
set_osc_cal ();
Soft_Uart_Init(GPIO, 2, 5, 9600, 0); // Setup UART (9600,N,1)
}
void main() {
init_ports ();
while (1) {
// Infinite loop - Poll every two seconds
displayVoltage (Adc_Read(0)); // Convert the analog signal to digital and send our results
GPIO |= (1<<4); // Turn the LED on
Delay_ms(1000); // Delay 1 second
GPIO &= ~(1<<4); // Turn the LED off
Delay_ms(1000); // Delay 1 second
}
}
Bookmarks