|
|
View previous topic :: View next topic |
Author |
Message |
Leif Steinhour
Joined: 28 Sep 2004 Posts: 6
|
Problems with sleep and the ADC on the PIC 12CE674 |
Posted: Tue Sep 28, 2004 12:47 pm |
|
|
Hey:
I've got some code that's doing something screwy: it's driving Pin 6 (GP1) low even though I've set it a bunch of times to be an input and an analog one at that. The chip's mostly in sleep mode, but it's using WDT events to wake up, so it should just be restarting. I am using the right pointers, have the chip hooked up correctly (no shorts to ground!), set the ADC up right, etc. In the actual code I'm really pushing the chip (using both Timer0 and WDT and all the pins in various manners). Anyone had this same problem?
Here's the code:
#include <12CE674.h>
#device PIC12CE674 *=8 ADC=8
#include <math.h>
#use delay(clock=4000000)
#use fast_io(A)
#fuses INTRC,WDT,PUT,NOPROTECT,NOMCLR//,NOBROWNOUT // Need to fix this piece of it
#rom 0x7ff = {0x3494} // This is for a 12CE674 Device
#define VOLTAGE_CHANNEL 1 // Correct
#define MAXVOLTAGE 199 // This should correspond to 12.6 volts for an 8 bit A/D
#define MINVOLTAGE 141 // This should correspond to 9 volts for an 8 bit A/D
#define NINEpONE 143 // This should correspond to 9.1 volts for an 8 bit A/D
#define NINEpFIVE 168
//#define WATCHDOG_TIMER
#define THERM_CHANNEL 0
#define MAXTEMP 204 // This corresponds with 65 degrees, and let's the operator know he's about to die
#define GREENLED PIN_A2 // Correct
#define REDLED PIN_A4 // Correct
#define BULB PIN_A5 // Correct
#define BUTTON PIN_A3 // Correct
#define CONSTANT0 4080 // This defines the duty cycle for the LED
//#byte STATUS_REG = 03h
// Global Variables
int1 green_led_state=0, red_led_state=0;
int1 green_led_flash=0, red_led_flash=0;
int duty_cycle;
long dummy=0;
int constant=CONSTANT0;
int pressnumber;
// This receives the last A/D conversion
int value;
// This is the main counter for the pwm
int pwm=0, duty=0;
int1 start=0, lamp_on=0;
#INT_TIMER0
void PWMoutput()
{
pwm++;
if (pwm == 256) {
pwm=0;
if (lamp_on) { output_high(BULB); }
}
if (duty == pwm)
{
output_low(BULB);
}
if ((!start) && (lamp_on)) // Lamp has not been started yet
{
if (duty<duty_cycle) duty++;
}
} // End PWMoutput
void buttonpress()
{
if (!(input(BUTTON))) {
pressnumber++;
if (pressnumber>=3)
{
pressnumber=0;
}
delay_ms(100);
restart_wdt();
}
}
void sandman()
{
lamp_on=0;
output_low(BULB);
disable_interrupts(INT_TIMER0);
while (pressnumber==0)
{
buttonpress();
sleep();
}
}
void startbackup()
{
setup_wdt(WDT_1152MS);
enable_interrupts(INT_TIMER0);
set_tris_a(0x0B); // Setup the register as follows: 0b0001011 Correct (ones are inputs)
setup_adc_ports(AN0_AN1_ANALOG); // Set all of these pins as analog inputs
setup_adc(ADC_CLOCK_DIV_32); // Set the clock for the fastest mode, not that it matters
}
void flash_redgreen()
{
int i;
for (i=0; i<10; i++)
{
restart_wdt();
delay_ms(250);
restart_wdt();
delay_ms(250);
output_high(GREENLED);
output_low(REDLED);
restart_wdt();
delay_ms(250);
restart_wdt();
delay_ms(250);
output_low(GREENLED);
output_high(REDLED);
}
output_low(REDLED);
pressnumber=0;
sandman();
startbackup();
}
void flash_red()
{
int8 i;
output_low(GREENLED);
for (i=0; i<10; i++)
{
buttonpress();
restart_wdt();
delay_ms(100);
restart_wdt();
delay_ms(100);
restart_wdt();
delay_ms(100);
restart_wdt();
delay_ms(100);
restart_wdt();
delay_ms(100);
output_low(REDLED);
restart_wdt();
delay_ms(100);
restart_wdt();
delay_ms(100);
restart_wdt();
delay_ms(100);
restart_wdt();
delay_ms(100);
restart_wdt();
delay_ms(100);
output_high(REDLED);
}
pressnumber=0;
sandman();
startbackup();
}
main ()
{
byte value;
int i;
// Setup Pins
pressnumber=0;
set_tris_a(0x0B); // Setup the register as follows: 0b0001011 (ones are inputs)
setup_adc_ports(AN0_AN1_ANALOG); // Set all of these pins as analog inputs
setup_adc(ADC_CLOCK_DIV_32);
setup_timer_0(RTCC_INTERNAL); // This will give us overflows every 255 instructions, just fine for PWM work
setup_wdt(WDT_1152MS); // We have to set this afterwards so the prescaler does it's thing
enable_interrupts(GLOBAL);
enable_interrupts(INT_TIMER0);
output_high(GREENLED);
output_low(BULB);
delay_ms(100);
output_low(GREENLED);
output_low(REDLED);
restart_wdt();
delay_ms(100);
restart_wdt();
if (restart_cause() == WDT_TIMEOUT)
{
output_high(GREENLED);
output_high(REDLED);
restart_wdt();
while (1) {
delay_ms(100);
sleep();
}
}
// The interrupt turn ons were here...
// First, check to see if the temp is out of range. If so, go to redgreen flash routine
while (1)
{
buttonpress();
if (pressnumber==0)
{
output_low(REDLED);
output_low(GREENLED);
sandman();
startbackup();
set_adc_channel(THERM_CHANNEL);
value = read_adc();
if (value>=MAXTEMP)
{
flash_redgreen();
}
setup_wdt(WDT_1152MS);
}
restart_wdt();
set_adc_channel(VOLTAGE_CHANNEL);
value=read_adc();
dummy=constant/value;
dummy=dummy/value;
duty_cycle=dummy;
if (value<MINVOLTAGE) // We need to soft charge the battery
{
flash_red();
}
if (value>NINEpFIVE)
{
output_high(GREENLED);
output_low(REDLED);
}
else if (value>NINEpONE)
{
output_low(GREENLED);
output_high(REDLED);
}
else
{
duty_cycle=(duty_cycle/4);
restart_wdt();
delay_ms(250);
restart_wdt();
delay_ms(250);
restart_wdt();
output_low(REDLED);
delay_ms(250);
restart_wdt();
delay_ms(250);
restart_wdt();
output_high(REDLED);
}
if (pressnumber==1)
{
lamp_on=1;
}
if (pressnumber==2)
{
duty_cycle=duty_cycle/2;
}
restart_wdt();
delay_ms(250);
restart_wdt();
delay_ms(250);
restart_wdt();
delay_ms(250);
restart_wdt();
delay_ms(250);
restart_wdt();
// end main loop
}
}
[/code] _________________ To watch plants grow, blink more slowly. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Sep 28, 2004 1:24 pm |
|
|
Quote: | The chip's mostly in sleep mode, but it's using WDT events to wake up, so it should just be restarting. |
That's not true. If you read section 9.8.1, WAKE-UP FROM SLEEP,
http://ww1.microchip.com/downloads/en/DeviceDoc/30561b.pdf
in the 12CE674 data sheet, it says:
Quote: | External MCLR Reset will cause a device reset. All
other events are considered a continuation of program
execution and cause a "wake-up". |
So a WDT wakeup does not cause it to restart. It causes it
to continue program execution.
I didn't look closely at your code because you put it in italics,
which makes it very hard to read. If you need us to look
further at your code, please edit your post and use the "Code"
button to highlight your code instead of italics. (And post a new
reply, to let us know that you did this.) |
|
|
Leif Steinhour
Joined: 28 Sep 2004 Posts: 6
|
Correction |
Posted: Tue Sep 28, 2004 2:41 pm |
|
|
I meant "continuing" rather than "resetting". I knew about that, and the code is planned accordingly. As per your request, here's the code in the correct format:
Code: |
#include <12CE674.h>
#device PIC12CE674 *=8 ADC=8
#include <math.h>
#use delay(clock=4000000)
#use fast_io(A)
#fuses INTRC,WDT,PUT,NOPROTECT,NOMCLR//,NOBROWNOUT // Need to fix this piece of it
#rom 0x7ff = {0x3494} // This is for a 12CE674 Device
#define VOLTAGE_CHANNEL 1 //
#define MAXVOLTAGE 199 // This should correspond to 12.6 volts for an 8 bit A/D
#define MINVOLTAGE 141 // This should correspond to 9 volts for an 8 bit A/D
#define NINEpONE 143 // This should correspond to 9.1 volts for an 8 bit A/D
#define NINEpFIVE 168
#define THERM_CHANNEL 0
#define MAXTEMP 204 // This corresponds with 65 degrees, and let's the operator know he's about to die
#define GREENLED PIN_A2 //
#define REDLED PIN_A4 //
#define BULB PIN_A5 //
#define BUTTON PIN_A3 //
#define CONSTANT0 4080 // This defines the duty cycle for the LED
// Global Variables
int1 green_led_state=0, red_led_state=0;
int1 green_led_flash=0, red_led_flash=0;
int duty_cycle;
long dummy=0;
int constant=CONSTANT0;
int pressnumber;
// This receives the last A/D conversion
int value;
// This is the main counter for the pwm
int pwm=0, duty=0;
int1 start=0, lamp_on=0;
#INT_TIMER0
void PWMoutput()
{
pwm++;
if (pwm == 256) {
pwm=0;
if (lamp_on) { output_high(BULB); }
}
if (duty == pwm)
{
output_low(BULB);
}
if ((!start) && (lamp_on)) // Lamp has not been started yet
{
if (duty<duty_cycle) duty++;
}
} // End PWMoutput
void buttonpress()
{
if (!(input(BUTTON))) {
pressnumber++;
if (pressnumber>=3)
{
pressnumber=0;
}
delay_ms(100);
restart_wdt();
}
}
void sandman()
{
lamp_on=0;
output_low(BULB);
disable_interrupts(INT_TIMER0);
while (pressnumber==0)
{
buttonpress();
sleep();
}
}
void startbackup()
{
setup_wdt(WDT_1152MS);
enable_interrupts(INT_TIMER0);
set_tris_a(0x0B); // Setup the register as follows: 0b0001011
setup_adc_ports(AN0_AN1_ANALOG); // Set all of these pins as analog inputs
setup_adc(ADC_CLOCK_DIV_32); // Set the clock for the fastest mode, not that it matters
}
void flash_redgreen()
{
int i;
for (i=0; i<10; i++)
{
restart_wdt();
delay_ms(250);
restart_wdt();
delay_ms(250);
output_high(GREENLED);
output_low(REDLED);
restart_wdt();
delay_ms(250);
restart_wdt();
delay_ms(250);
output_low(GREENLED);
output_high(REDLED);
}
output_low(REDLED);
pressnumber=0;
sandman();
startbackup();
}
void flash_red()
{
int8 i;
output_low(GREENLED);
for (i=0; i<10; i++)
{
buttonpress();
restart_wdt();
delay_ms(100);
restart_wdt();
delay_ms(100);
restart_wdt();
delay_ms(100);
restart_wdt();
delay_ms(100);
restart_wdt();
delay_ms(100);
output_low(REDLED);
restart_wdt();
delay_ms(100);
restart_wdt();
delay_ms(100);
restart_wdt();
delay_ms(100);
restart_wdt();
delay_ms(100);
restart_wdt();
delay_ms(100);
output_high(REDLED);
}
pressnumber=0;
sandman();
startbackup();
}
main ()
{
byte value;
int i;
// Setup Pins
pressnumber=0;
set_tris_a(0x0B); // Setup the register as follows: 0b0001011
setup_adc_ports(AN0_AN1_ANALOG); // Set all of these pins as analog inputs
setup_adc(ADC_CLOCK_DIV_32); // Set the clock for the fastest mode, not that it matters
setup_timer_0(RTCC_INTERNAL); // This will give us overflows every 255 instructions, just fine for PWM work
setup_wdt(WDT_1152MS); // We have to set this afterwards so the prescaler does it's thing
enable_interrupts(GLOBAL);
enable_interrupts(INT_TIMER0);
output_high(GREENLED);
output_low(BULB);
delay_ms(100);
output_low(GREENLED);
output_low(REDLED);
restart_wdt();
delay_ms(100);
restart_wdt();
if (restart_cause() == WDT_TIMEOUT)
{
output_high(GREENLED);
output_high(REDLED);
restart_wdt();
while (1) {
delay_ms(100);
sleep();
}
}
// The interrupt turn ons were here...
// First, check to see if the temp is out of range. If so, go to redgreen flash routine
while (1)
{
buttonpress();
if (pressnumber==0)
{
output_low(REDLED);
output_low(GREENLED);
sandman();
startbackup();
set_adc_channel(THERM_CHANNEL);
value = read_adc();
if (value>=MAXTEMP)
{
flash_redgreen();
}
setup_wdt(WDT_1152MS);
}
restart_wdt();
delay_ms(100);
restart_wdt();
set_adc_channel(VOLTAGE_CHANNEL);
value=read_adc();
dummy=constant/value;
dummy=dummy/value;
duty_cycle=dummy;
if (value<MINVOLTAGE) // We need to soft charge the battery
{
flash_red();
}
if (value>NINEpFIVE)
{
output_high(GREENLED);
output_low(REDLED);
}
else if (value>NINEpONE)
{
output_low(GREENLED);
output_high(REDLED);
}
else
{
duty_cycle=(duty_cycle/4);
restart_wdt();
delay_ms(250);
restart_wdt();
delay_ms(250);
restart_wdt();
output_low(REDLED);
delay_ms(250);
restart_wdt();
delay_ms(250);
restart_wdt();
output_high(REDLED);
}
if (pressnumber==1)
{
lamp_on=1;
// output_low(GREENLED);
// output_high(REDLED);
}
if (pressnumber==2)
{
duty_cycle=duty_cycle/2;
// output_high(GREENLED);
// output_low(REDLED);
}
restart_wdt();
delay_ms(250);
restart_wdt();
delay_ms(250);
restart_wdt();
delay_ms(250);
restart_wdt();
delay_ms(250);
restart_wdt();
// output_high(REDLED);
// If the switch is pressed after a soft start, then reduce the duty cycle by 50%
// Otherwise turn it off
// main loop
}
}
|
_________________ To watch plants grow, blink more slowly. |
|
|
Ttelmah Guest
|
|
Posted: Tue Sep 28, 2004 2:59 pm |
|
|
You say that the code is written to handle the fact that a watchdog 'continues', from a sleep, but it doesn't really look like it is.
As it stands, the code will have sit looping in the sleep, delaying 100mSec, then going to sleep, waking, executing the allready fetched loop instruction, delaying 100mSec, sleeping again etc..
If you want the chip to restart from the watchdog, you need to sit in a loop for a couple of seconds or more (remember the watchdog 'times' are very approximate), without the sleep instruction, which will then force the watchdog, to trigger a restart. Simply coding 'while(true);' will force a watchdog restart if it is enabled. Otherwise, if you want it to continue (which you then seem to show), code with a layout like:
initialise.
sleep
dummy instruction (delay_us(1))
If you get here the chip has woken from the watchdog.
Best Wishes |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Sep 28, 2004 3:35 pm |
|
|
A couple things before we go any further:
1. What is the version of your compiler ?
This will be a number like 3.188 or 3.212, etc.
You can find it at the top of your list file (.LST)
after you compile a program.
2. You have tons and tons of code like this:
Code: |
restart_wdt();
delay_ms(250);
restart_wdt();
delay_ms(250); |
The #use delay() statement has an optional parameter which
tells the compiler to add code to restart the WDT when it's doing
a delay. If you add this parameter, then you don't need to do
code like you have above. You can clean up your program.
Example:
#use delay(clock=4000000, restart_wdt) |
|
|
Leif Steinhour
Joined: 28 Sep 2004 Posts: 6
|
Compiler Version, etc. |
Posted: Tue Sep 28, 2004 4:19 pm |
|
|
PCM 3.137 on the compiler. I'll definitely take advantage of the #USE directive, that sure makes things cleaner. _________________ To watch plants grow, blink more slowly. |
|
|
Leif Steinhour
Joined: 28 Sep 2004 Posts: 6
|
|
Posted: Tue Sep 28, 2004 4:29 pm |
|
|
Ttelmah wrote: | You say that the code is written to handle the fact that a watchdog 'continues', from a sleep, but it doesn't really look like it is.
As it stands, the code will have sit looping in the sleep, delaying 100mSec, then going to sleep, waking, executing the allready fetched loop instruction, delaying 100mSec, sleeping again etc..
If you want the chip to restart from the watchdog, you need to sit in a loop for a couple of seconds or more (remember the watchdog 'times' are very approximate), without the sleep instruction, which will then force the watchdog, to trigger a restart. Simply coding 'while(true);' will force a watchdog restart if it is enabled. Otherwise, if you want it to continue (which you then seem to show), code with a layout like:
initialise.
sleep
dummy instruction (delay_us(1))
If you get here the chip has woken from the watchdog.
Best Wishes |
It's waiting for a button press, and once it gets one (making pressnumber=1) it exits the loop. All that stuff works, the problem is with the AN1 line. No matter what I do the line seems to get tied low, and I'm sure it's not because of a short, having tested it out pretty thoroughly. I've also tried a couple of different chips and they all seem to be exhibiting this same behaviour, so I'm reasonably sure it's something the program is doing... _________________ To watch plants grow, blink more slowly. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue Sep 28, 2004 6:11 pm |
|
|
Code: |
int pwm=0, duty=0;
int1 start=0, lamp_on=0;
#INT_TIMER0
void PWMoutput()
{
pwm++;
if (pwm == 256) {
pwm=0;
if (lamp_on) { output_high(BULB); }
}
|
You know that an int is 8 bits in CCS, right?? PWM won't ever get to 256.
Code: |
value=read_adc();
dummy=constant/value;
dummy=dummy/value;
|
What happens when value == 0! |
|
|
Leif Steinhour
Joined: 28 Sep 2004 Posts: 6
|
Int problem |
Posted: Wed Sep 29, 2004 10:48 am |
|
|
Surre, that's definitely a typo and a problem, thanks for bringing that to my attention. Having said that, it will skip over that line as it goes past, which is unrelated to the problem I'm worried about: it's grounding AN1 and shouldn't be. I'm pretty sure it shouldn't be having a problem with that line, and yet it is. _________________ To watch plants grow, blink more slowly. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Sep 29, 2004 11:43 am |
|
|
My suggestion is to make a small program that only tests for
the AN1 problem. If you still can't make it work, then post
the test program. |
|
|
drh
Joined: 12 Jul 2004 Posts: 192 Location: Hemet, California USA
|
|
Posted: Wed Sep 29, 2004 12:06 pm |
|
|
You need to delay after changing the ADC channel. Try 20uS. _________________ David |
|
|
Leif Steinhour
Joined: 28 Sep 2004 Posts: 6
|
Fixed it |
Posted: Wed Sep 29, 2004 4:32 pm |
|
|
Thank you, that was it. If anyone else has this problem, the symptom is an intermittent tie to ground. _________________ To watch plants grow, blink more slowly. |
|
|
|
|
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
|