|
|
View previous topic :: View next topic |
Author |
Message |
mnqobilozo
Joined: 02 Sep 2014 Posts: 1
|
switching a relay when a voltage detector detects no voltage |
Posted: Tue Sep 02, 2014 6:06 am |
|
|
i am currently making a UPS for a school project. im using a pic16f877a and a LM35 sensor to monitor the UPS temperature. i have been able to do that but now i have a problem with additionally switching a relay if the output of the UPS is zero detected by a voltage detector. the voltage detector input is PIN_B2 and the relay output is PIN_B4.
here is the program
[color=orange]/*
PIC16F877A and LM35 Based Temperature Monitor
MACHI M.C
20403715
*/
#include <16f877a.h>
#device adc=10 // Set ADC resolution to 10Bit
#fuses XT,NOLVP,NOWDT,NOPROTECT
#use delay(crystal=4000000)
#use rs232(baud=960,xmit=PIN_C6,rcv=PIN_C7,ERRORS)
#include <lcd.c>
#define LOAD PIN_B7
#define THRES 70.0 // load switching threshold in Celsius
#define OFF 50.0 // fan stops when temparature reaches value in degrees
#define ADC_OFF 0 // ADC off
#define RELAY PIN_B4
#define R2 PIN_B2
#define R1 PIN_B1
#include <stdlib.h>
int16 digital_reading; // ADC resolution is 10Bit, an 8Bit integer is not enough to hold the reading
float temp;
void main()
{
/* ADC Initialization */
setup_adc(ADC_CLOCK_INTERNAL); // initialize ADC with a sampling rate of Crystal/4 MHz
setup_adc_ports(RA0_ANALOG); // set PIN_A0 as analog input channel
set_adc_channel(0); // point ADC to channel 0 for ADC reading
delay_ms(1); // ADC module is slow, needs some time to adjust.
disable_interrupts(GLOBAL); // DISABE ALL INTERRUPTS.
SET_TRIS_B(0X0F); //set RB0,RB1,RB2 & RB3 as inputs, RB4,RB5,RB6 & RB7 as output.
output_low(RELAY); // relay initialy off
if (input(PIN_B2)==0)
{
output_high(PIN_B4);
}
else if (input(PIN_B2)==1)
{
output_low(RELAY);
}
/* Peripherals Configurations */
lcd_init(); // Turn LCD ON, along with other initialization commands
output_low(LOAD); // the load is initially OFF
lcd_gotoxy(1,1); // point LCD cursor to col1 row1
lcd_putc("Temperature is:"); // print on LCD
{
while(1) // infinite loop
{
digital_reading = read_adc(); // capture current temperature reading
delay_us(100); // 0.1ms delay for ADC stabilization
temp = digital_reading * 0.4883; // convert reading to Celsius
lcd_gotoxy(1,2); // point LCD cursor to col1 row2
printf(lcd_putc,"%2.1f C",temp); // print value on LCD
if(temp>=THRES)
Do
{
output_high(LOAD); // Control Load
}
while (temp>=OFF);
else output_low(LOAD);
delay_ms(1000); // 1 second delay between readings
}
}
}[/code][/color] |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Tue Sep 02, 2014 7:42 am |
|
|
Start by not using colour, and using the code buttons properly. Trying to post the code in orange has just resulted in a mess....
Then you have a fundamental problem about using a digital input to use this. A logic input only sees a '0' when it is below 0.6v, and is indeterminate between 0.6, and about 2.4v. However, the peripheral that can do what you want, is the comparator. This can be programmed to switch an output at a specific voltage from the internal voltage reference module, and once setup, does it for you.....
You'd need to change the pins being used, but it will be the better solution.
Now, I've pointed out some problems with the existing code in the comments. Some parts are probably wrong, but you have several things being 'not used', such as the 'OFF' threshold value, so the logic is not totally clear:
Code: |
#include <16f877a.h>
#device adc=10 // Set ADC resolution to 10Bit
#fuses XT,NOLVP,NOWDT,NOPROTECT
#use delay(crystal=4000000)
#use rs232(baud=960,xmit=PIN_C6,rcv=PIN_C7,ERRORS)
#include <lcd.c>
#define THRES 700 // load switching threshold in 0.1 Celsius
#define THRES_OFF 500 // fan stops when temparature reaches value in 0.1 degrees
#define LOAD PIN_B7
#define RELAY PIN_B4
#define R2 PIN_B2
#define R1 PIN_B1
/* first comment. You make these defines, so use them.... */
#define OFF(x) output_low(x)
#define ON(x) output_high(x)
#include <stdlib.h>
void main()
{
int16 digital_reading; // ADC resolution is 10Bit, an 8Bit integer is not enough to hold the reading
int16 temp; //Avoid floats
//Get in the habit of making variables local, not global. Only use global, when
//things want to be global
/* ADC Initialization */
//setup_adc(ADC_CLOCK_INTERNAL); // initialize ADC with a sampling rate of Crystal/4 MHz
setup_adc(ADC_CLOCK_DIV_8); //Your remark is wrong, and the selection is wrong. Needs /8 for 4MHz
setup_adc_ports(RA0_ANALOG); // set PIN_A0 as analog input channel
set_adc_channel(0);
delay_ms(100); //LCD needs boot delay
//disable_interrupts(GLOBAL); // DISABE ALL INTERRUPTS.
//all interrupts wake up disabled
//SET_TRIS_B(0X0F); //set RB0,RB1,RB2 & RB3 as inputs, RB4,RB5,RB6 & RB7 as output.
//Not needed you are using standard IO, so compiler controls TRIS
OFF(RELAY);
/* Peripherals Configurations */
lcd_init(); // Turn LCD ON, along with other initialization commands
OFF(LOAD); // the load is initially OFF
lcd_gotoxy(1,1); // point LCD cursor to col1 row1
lcd_putc("Temperature is:"); // print on LCD
while(TRUE) // infinite loop
{
digital_reading = read_adc(); // capture current temperature reading
//LM35 returns 10mV/degree. ADC input has an imaginary 1024 levels (only 1023
//actually returned) for 5v. So each step is 0.48828degrees. However the unit is
//just not that accurate. 1% at best, so _simplify_ the maths for space
temp=(digital_reading*5)-(digital_reading/8)
//This gives *4.875, many times faster than the float
//temp = digital_reading * 0.4883; // convert reading to Celsius
lcd_gotoxy(1,2); // point LCD cursor to col1 row2
printf(lcd_putc,"%4.1Lw C",temp); // print value on LCD
//In C, the number in front of the decimal, is the _total field width_
//Not the digits in front. Your format will have been overflowing every time....
if(temp>=THRES)
ON(LOAD); // Control Load
else
OFF(LOAD); //Your logic is not quite clear here.
//No control of fan etc...
delay_ms(1000);
}
}
}
|
Now go, and look at ex_comp.c. This shows how to setup the comparator, and use it to signal when a voltage goes below a programmed level.
If you want to do it in software, then remove the delay, and instead have a short delay like 50uSec, and a counter for the inner loop. Just update the temperature when this gets to zero (so count to 20000), and each time round the short loop while waiting, test the input. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|