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.

[SOLVED] LCD command during ISR PIC16F877A problem

Status
Not open for further replies.

sana_akhtar

Member level 2
Joined
Apr 21, 2012
Messages
47
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,286
Activity points
1,606
Hey
This code is triggering the timer on RA4 and every timer interrupt add 1 to "count" variable. I want to display this count on LCD But there is some mistake I couldnt figure out because of which it is not displaying on LCDIt is working with internal Clock but not from external transition at the pin. WHYYYY?? Frustrated :(

Code:
#include <htc.h>
#include <stdlib.h>
//#include <stdio.h>
#include "lcd.h"
#include "uart.h"


#ifndef _XTAL_FREQ
 // Unless specified elsewhere, 4MHz system frequency is assumed
 #define _XTAL_FREQ 4000000
#endif

#define sensor RA4
#define len1 10

int count=0;

void interrupt isr(void)           // Here be interrupt function - the name is
{
    count+=1;            // Add 1 to count - insert idle comment
    T0IF = 0;           // Clear interrupt flag, ready for next
	GIE=1;
	T0IE=1;
}

void main(void)
{	
    unsigned char jj[len1];
	TRISA=1;
    PORTA=0;
    
  	UART_Init(9600);
	lcd_init();
	lcd_goto(0);
	lcd_puts("No. of Sh:");
	lcd_goto(11);
   
	T0IE=1;
	GIE=1;
	PEIE=1;
	T0CS=1;     // if T0CS=0, it works. But I want to work with external interrupt. 
	T0SE=0;
	PSA=0;
	PS0=0;
	PS1=0;
	PS2=0;
	
	while(1)
	{
		lcd_goto(11);
		itoa(jj,count,10);
		lcd_puts(jj);	
		UART_Write_Text(jj);
					
	} 
}
 
Last edited:

When you say 'not working', what exactly DO you observe happening ?
And what sort of external input are you connecting ?
 

I'm not familiar with HTC but you probably don't want to change GIE or re-enable the T0IE bit inside the ISR.

Incidentally, you are asking for an external clock, not an external interrupt. The interrupt will only happen when TMR0 rolls over, in other words every 256 pulses at the external input. Use RB0 if you want to take action at every pulse on a pin.

Brian.
 

I can use only this pin. I want to take input from sensor on this pin and then want the timer to start at every sensor response. Sorry, I used wrong word for that. I meant i was giving an input to the pin and want timer to start it the positive edge transition. How can that be possible?
In other words, I want to use timer0 (RA4) as a counter.
 
Last edited:

I'm still not clear on what you want.
Is it:
1. You want to count each positive edge transition, using TMR0 to keep the total number of positive edges.
2. You want a positive edge transition to start TMR0 running and counting something else. In other words use the edge to trigger another counting process.

Why I am confused is your code uses the output of TMR0 to cause an overflow interrupt (when T0IF is set). If you do that the value of 'count' will only increase after TMR0 has reached 256 and rolled over to zero again. In other words 'count' will only increase once for 256 positive edges.

Brian.
 

Also, count should in either case probably be qualified as volatile.

Regards, Dan.
 

Indeed, if count is supposed to increment inside the ISR it should be volatile. I suspect in this case the interrupt is a mistake and the timer value itself rather than the interrupts it generates is what sana_akhtar is really wanting to use.

Brian.
 

hmmm.. sorry for not being so clear

I want to use timer0 (RA4) as a counter. Input is coming from a sensor and I want to count it. How I can do this?
 

Remove the ISR and all the code that sets the interrupt flags then use the value in TMR0 instead of 'count'.

Be warned that the maximum count is 255 (0xFF) before it goes back to zero again.

Brian.
 

but how I will count it? When timer overflows it add one to a variable. Timer is used so that it keep running while other code is working.
 

If you use the external input to TMR0 and set it's configuration it will increment at each positive edge of signal on the external input.
The value will increment while the rest of the code carries on running, if you want to know WHEN it has incremented (when a positive edge has been seen) take a copy of TMR0 value in your main program loop and compare it with the present value, if it has changed you know a pulse has been received, when it has, update your copy with the new value so it is ready for the next change.
If you need to count more than 255 there are two ways to do it:
1. (easy way) just see if the present value is less than the copied value, if it is the timer rolled over so add 256 to the value in TMR0 to get a new total.
2. (harder) use the ISR again and at each T0 interrupt, add 256 to the total.

Brian.
 
Thank you soooooo much. it worked. I was doing the stupidest mistake.

Now I want to count the time between two inputs. How can I do that? another timer?
 

It's easier if you directly control TMR1 but as you have to use RA4 as the input and count the edges I would do it this way:

1. Configure TMR1 to count internal clocks, you can adjust it's prescaler to set the time measurement between the input signals.
2. Using your existing code, when you increment 'count' read the TMR1 value then reset TMR1 (TMR1H = 0; TMR1L = 0;).
3. Use the value you read in step 2 as the time interval.

What you would be doing is making TMR1 count upward from zero continuously at the speed you decide from your crystal frequency and how much you divided it by in the prescaler register. At each input edge, your program counts it in TMR0 and also reads the count value from TMR1. The value in TMR1 is the number of counts since it was last reset, in other words since the previous input signal, it therefore holds a number representing the interval between the two signals.

Brian.
 

I tried this. Here is the code. But its isnt working the way I want. I want to display just the final value in the TMR1L. If I place it outside while loop, it wont update the variable, and in while loop it is updated on every loop circle. :(

Code:
#include <htc.h>
#include <stdlib.h>
#include <stdio.h>
#include "lcd.h"
#include "uart.h"

#ifndef _XTAL_FREQ
 #define _XTAL_FREQ 4000000
#endif

#define sensor RA4
#define len1 10

int count=0;
int timer_count=0;

void main(void)
{	
    unsigned char count_str[len1];
	unsigned char time_str[len1];
	TRISA=1;
    PORTA=0;
    
  	UART_Init(9600);
	lcd_init();
	lcd_goto(0);
	lcd_puts("Sheets:");
	lcd_goto(0x40);
	lcd_puts("sh/h:");

    // counter
	TMR0=0;
	TMR0=0;
	T0CS=1;    
	T0SE=0;
	
	//timer
	TMR1CS=0;
	T1OSCEN=0;
	T1CKPS1=1;
	T1CKPS0=1;
	TMR1L=0;
	TMR1ON=1;
    
	while(1)
	{		
		timer_count= TMR1L;    //timer
		count=count +TMR0;     // counter
		TMR0=0;	
		lcd_goto(8);
		itoa(count_str,count,10);
		lcd_puts(count_str);
		lcd_goto(0x48);
		itoa(time_str,timer_count,10);
		lcd_puts(time_str);					
	} 
}
 

My first thought though is that you are not checking for the change in TMR0 and not resetting TMR1 after reading it.

Try something like this (I'm working away at the moment so I can't test it):

1. add "int old_count = 0;' after the other variable declarations.
2. instead of the 'while(1);' check if TMR0 has changed by using:

Code:
if(TMR0 != old_count) 
{
old_count = TMR0;
timer_count = TMR1L;
TMR1L = 0;
<the remainder of the LCD routines>
}

See if that works. There is a serious bug in what I proposed but see if it does what you want first. It will probably work but occasionally give a wrong result, can you see why?

Brian.
 

I did some changes in your too. But now problem is, the value doesnt remain constant. I am checking the code on Proteus 8.1, so instead of sensor, I am just giving pulse at RA4. Therefore, time between two pulses must remain constant. What can be he possible problem?
Code:
#include <htc.h>
#include <stdlib.h>
#include <stdio.h>
#include "lcd.h"
#include "uart.h"

#ifndef _XTAL_FREQ
 #define _XTAL_FREQ 4000000
#endif

#define sensor RA4
#define len1 10

int new_count=0;
int old_count=0;
float timer_count=0;

void main(void)
{	
    unsigned char count_str[len1];
	unsigned char time_str[len1];
   // TRISA=1;
   // PORTA=0;
    
  	UART_Init(9600);
	lcd_init();
	lcd_goto(0);
	lcd_puts("Sheets:");
	lcd_goto(0x40);
	lcd_puts("sh/h:");

    // counter
	TMR0=0;
	T0CS=1;    
	T0SE=0;
	
	//timer
	TMR1CS=0;
	T1OSCEN=0;
	T1CKPS1=1;
	T1CKPS0=1;
	TMR1L=0;
	TMR1ON=1;
        		
	while(1)
	{
		new_count=old_count + TMR0;     // counter
		TMR0=0;	
		lcd_goto(8);
		itoa(count_str,new_count,10);
	    lcd_puts(count_str);       //print counter on LCD
		if (old_count!= new_count)
		{
			TMR1ON=0;
			timer_count=3600/((TMR1H,TMR1L)*0.00000025); // timer .. calculate time b/w two counts
			// no. of sensor response per hour. 
			TMR1ON=1;
			lcd_goto(0x46);
			my_float_func(time_str,timer_count); //display time on LCD
			TMR1L=0;
			TMR1H=0;
		}
		old_count=new_count;					
	}
}
 

Perhaps it woud be easiest if you give a complete specification of what you want. The program has changed significantly and it is no longer clear what you are trying to achieve. Originally you wanted to count positive edges on RA4, now you are trying to measure pulses per hour.

There are two immediate problems I can see:
Code:
new_count=old_count + TMR0;     // counter
why are you adding TMR0 to the 'old_count'? the idea is that TMR0 increments when it sees a hardware signal on RA4 and the difference between it's present value and the value when it was previously read is used to indicate it has actually changed. By adding TMR0 each time you make new_count jump by any value between zero and 255 when you really only want it to increase by 1.

Code:
timer_count=3600/((TMR1H,TMR1L)*0.00000025); // timer .. calculate time b/w two counts
I don't use HTC so I will assume (TMR1H,TMR1L) returns the total value in TMR1. The math is basically correct but when you use very small numbers you will see a serious error due to the limtations of floating point multiplication. You may also see an occasional crash because if TMR1 contains zero you get a 'divide by zero' situation.

In general, when measuring period or frequency there are two methods. There is no sudden change-over when one is better than the other but one gets more accurate at high frequency and the other more accurate at low frequency. It is up to you to choose which is best in your application and with some clever coding it is possible to chage from one method to the other depending on the result you get. Below by 'pulses' I mean the signal edge you are testng on RA4.

method 1: this is best when the frequency is low (long periods between pulses). Instead of timing how many pulses per hour you get, which means you have to wait an hour to see what the total will be, you count how many smaller intervals fit between the pulses. For example, you set up a counter to increment (from the system clock) once per second. You zero the count when a pulse is seen and then wait for another pulse. When the second pulse arrives, you read the timer to see how many seconds have elapsed then make it's value zero again so it starts counting the next interval. The value you read is seconds between pulses so you can convert that to pulses per hour by using '(seconds per hour)/number of seconds counted'. This is similar to the method you are trying to use.

method 2: when the frequency is higher (short period between pulses) it is better to fix the measurement 'window' and count how many pulses occur within it. For example if you use a timer to count a fixed one second interval and count how many pulses arrive before the second has elapsed you get the frequency directly in Hz (because Hz = cycles per second). The advantage of this method at higher frequencies is you can shorten the window (also called 'gate period') so fewer pulses are counted in it so it is easier to scale the measurement as the frequency gets higher.

You can see the difference between the two methods is that one counts pulses in a fixed time interval (frequency) and the other measures time intervals between pulses (period). As frequency = 1/period it is easy to convert from one to the other.

Brian.
 

Thank you so much Betwixt. It worked by second method. :)
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top