Jump to content
Clashlab

Problems Reading Porta In Interrupt

Recommended Posts

Hello,

 

In am experiencing a wired problem trying to make a led blink.

 

I what to use a timer (TMR0) to know when I need to change the led state. So I have a function that turns on the led and sets the timer.

Then every 20 timer overflow I test the led state and change it. This is where I have a problem.

When I am directly testing the led state, the led never blinks (it is like reading the led state always returns 0) so I need to use a variable to keep track of the led state.

 

I really don't understand the problem and need your help to figure this out.

 

Here are the files (led.h, led.c, main.c) I am using BoostC 6.84 lite license on a 16f88. You only need to provide power to the pic and tie a led (+ resistor) to porta bit4.

I included a #define PROBLEM1:

  • If you declare PROBLEM1, the led never blinks (which is wired).
  • If it is not declared the led blinks (using a state variable).

Trying to figure out what was wrong I found another problem :

When using a variable to keep track of the led state (PROBLEM1 not defined) if I set another led (LED_RED, porta bit3) to 1 at each timer overflow it get wired again.

I included a #define PROBLEM2:

  • If you declare PROBLEM2, the LED_BLUE blinks but stays on for a short period of time and surprisingly LED_RED goes off for a very short time repetitively.
  • If it is not declared the led blinks (well if PROBLEM1 is not defined :)).

I have included an archive containing the 3 source files and 3 hex files:

  • led.hex: PROBLEM1 and PROBLEM2 NOT defined ==> LED_BLUE blinks
  • ledProblem1.hex: only PROBLEM1 defined ==> LED_BLUE doesn't blink
  • ledProblem2.hex: only PROBLEM2 defined ==> LED_BLUE stays on furtively LED_RED goes off furtively

What have I done wrong?

Thanks for your help.

 

led.h

#ifndef LED_H
#define LED_H

#define LED_BLUE  porta.4
#define LED_RED  porta.3

#define ON	 1
#define OFF	0

#define TMR0_PRESCALER  6
#define LED_PRELOAD  100

/*
CLOCK_FREQ = 8 MHz
TMR0: Prescaler 1/128, preload: 100 => IT every 0.00998400 sec
*/
void  ledInit  ( void);
void  ledBlink ( unsigned char onDuration);
void  IT_led   ( void);

#endif /* LED_H */

 

led.c

#include <system.h>

#include "led.h"

#define PROBLEM1
/*#define PROBLEM2*/

static unsigned char ledTimer = 0;
static unsigned char blink = 0;
#ifndef PROBLEM1
static bit ledState = 0;
#endif

void ledInit( void)
{
  option_reg &= 0xC0;	 /* 0b11000000 We keep the 2 MBS unchanged */
  option_reg |= TMR0_PRESCALER;
}

void ledBlink( unsigned char duration)
{
  /* Save duration for use in IT_led */
blink = duration;
/* Set the number of timer overflow */
ledTimer = blink;

LED_BLUE = ON;
#ifndef PROBLEM1
  ledState = ON;
#endif

/* Load timer */
tmr0 = LED_PRELOAD;

/* Allow timer IT*/
  intcon.TMR0IF = 0;
  intcon.TMR0IE = 1;
}

void IT_led( void)
{
#ifdef PROBLEM2
  LED_RED = ON;
#endif

  /* If duration has elapsed */
if ( --ledTimer == 0 )
{

  /* Change led state */
#ifdef PROBLEM1
  /* DOESN'T WORK : LED_BLUE STAYS ON */
  if ( LED_BLUE == ON )
	{
	 LED_BLUE = OFF;
	}
	else
	{
	 LED_BLUE = ON;
	}
#else
  /* WORKS : LED_BLUE blink when using another variable to test the led state */
  if ( ledState == ON )
  {
	 LED_BLUE = OFF;
	 ledState = OFF;
  }
  else
  {
	 LED_BLUE = ON;
	 ledState = ON;
  }
#endif
  /* Set the number of timer overflow */
  ledTimer = blink;
}
  /* Load timer */
tmr0 = LED_PRELOAD;
}

 

main.c

#include <system.h>

#include "led.h"

#pragma DATA _CONFIG1, _WDT_OFF & _PWRTE_OFF & _INTRC_IO & _MCLR_OFF & _BODEN_OFF & _LVP_OFF & _CPD_OFF & _WRT_PROTECT_OFF & _DEBUG_OFF & _CCP1_RB0 & _CP_OFF;
#pragma DATA _CONFIG2, _FCMEN_ON & _IESO_ON;


static void init( void)
{
  porta = 0;
  portb = 0;
  trisa = 0b00100100;
  trisb = 0b11000001;

  osccon = 0x72;
}


void interrupt(void)
{
  if (intcon.TMR0IE == 1 && intcon.TMR0IF == 1)
  {
  IT_led();

  intcon.TMR0IF = 0;
  }
}


void main( void)
{
  /* General initialisation */
  init();

  /* Module initialisation */
  ledInit();

  intcon.GIE = 1;

  ledBlink( 20);

  for (;;);
}

BlinkLed.zip

Share this post


Link to post
Share on other sites

Exactly how have you wired up the LEDs to the port pins.

 

Remember that when reading a port it is the voltage level on the pin that is read and not the value of the output latch. Just because you write a 1 to the outout latch does not mean that you will read back a 1. the logic level will depend on the voltage on the pin which could be less than the required threshold.

Setting/resetting individual port bits will perform a read/modify/write instruction which can screw things up if the voltages on the pins do not meet the spec.

If this is the case for you, then always use a shadow register for the port outputs.

 

Cheers

 

Reynard

Share this post


Link to post
Share on other sites

I had a big long reply to the same effect, but FF crashed on me and I didn't have the heart to rewrite it.

 

A simple way to flip the value on the pin is simply to XOR the value with 1. (0 XOR 1 = 1, 1 XOR 1 = 0). That should work, methinks.

 

Also, I think you're inadvertently messing up your interrupt call frequency. When the interrupt function is called (when the timer overflows), the PIC must store in memory everything that it's playing with along with its position in code. Then it performs the interrupt function. Then recalls stuff to memory and returns to the code. A finite amount of time passes between the timer overflow and the beginning of the interrupt. Check it out on debug, if you wish. Monitor the timer and put a breakpoint on the first line of the interrupt function. When you set the value of the timer at the end of the interrupt you basically set the time between the end of the interrupt call and the start of the next, if you get me. To guarantee that the interrupt is called every X ms you should probably += the value of the timer rather than simply =ing it. Though with your timer scaling mightn't make much difference.

Share this post


Link to post
Share on other sites

Hi,

 

The way I connected the led to the pic is very simple:

PIC (5v) ---- Resistor (470 Ohm) ---- Led ---- 0v

 

I tried several other value for the resistor, form 47 Ohm to 2.7 kOhm but that doesn't change anything.

 

I think your right about the origin of my problem, it explain the two situation I encountered.

I also found that RA4 on a 16f88 is a schmitt trigger, but using RA3 (TTL) doesn't help.

 

So how can I make sure that when I put a 1 on the led output I read a 1 after?

Share this post


Link to post
Share on other sites
Hello,

 

In am experiencing a wired problem trying to make a led blink.

 

I what to use a timer (TMR0) to know when I need to change the led state. So I have a function that turns on the led and sets the timer.

Then every 20 timer overflow I test the led state and change it. This is where I have a problem.

When I am directly testing the led state, the led never blinks (it is like reading the led state always returns 0) so I need to use a variable to keep track of the led state.

 

I really don't understand the problem and need your help to figure this out.

The answer is simple.

 

The 16F88 has analog I/O that is enabled by default.

 

This code is from the Microchip datasheet (DS30487C), section 5.1:

	BANKSEL PORTA; select bank of PORTA
CLRF	PORTA; Initialize PORTA by
			 ; clearing output
			 ; data latches
BANKSEL ANSEL; Select Bank of ANSEL
MOVLW   0x00 ; Configure all pins
MOVWF   ANSEL; as digital inputs
MOVLW   0xFF ; Value used to
			 ; initialize data
			 ; direction
MOVWF   TRISA; Set RA<7:0> as inputs

 

Try changing your init function:

static void init( void)
{
  porta = 0;
  ansel = 0; // <--- add this to your init fuction.
  cmcon = 7; // <--- add this to your init fuction.
  portb = 0;
  trisa = 0b00100100;
  trisb = 0b11000001;

  osccon = 0x72;
}

Share this post


Link to post
Share on other sites

Absolutely cac001, you hit the nail on the head. Disable those analogue inputs.

 

I must have had my head in the clouds for not spotting that one. Must be all that global warming stuff.

 

Cheers

 

Reynard

Share this post


Link to post
Share on other sites

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...