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] PIC16F877A: how to set a time limit for my DC motor to run on?

Status
Not open for further replies.

desmond1310

Member level 1
Joined
Apr 5, 2010
Messages
39
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,286
Location
Malaysia
Activity points
1,665
Hi all, I have a problem here. I have managed to use the PWM function of the PIC, and now I would like my motor to run on a time limit basis, and stop running afterwards. I am also using a 16x2 LCD display to display the following:

When motor runs:
Line 1: Drying In
Line 2: Process

When motor stops:
Line 1: Drying Process
Line 2: Completed!

My time limits have a minimum of 10 mins, maximum of 60 mins with increments of 10 mins. Please recommend me a way to solve this problem in C-programming? A source code reference would be good too. Thank you!
 


I am also on that forum btw. Could you possibly recommend me a project number which does have this function i plan to use?

Guys, any help is very welcomed.
 
Last edited:

i think PR12..but it not use 16f77a..but u can refer how they display the lcd..for your timing funtion, u just need to manipulate the variable by using input button..
 

basically my main problem is to set time limit for motor to run on.. i would say i don't have a problem with the LCD also. i'm currently trying out this:

void tenminutes(void)
{
unsigned char u=10; //For a start, i am trying to let the motor run for 10 seconds, where i roughly estimated that data = 130000 is about 1 sec in real time.
for(;u>0;u-=1)
{
unsigned long data;
for(data=130000;data>0;data-=1)
{
motor_1 = 1;
motor_speed = 115;
lcd_clr() ;
lcd_goto(0) ;
send_string("Drying In ");
lcd_goto(20);
send_string("Process");
}
}
if (u=0)
{
motor_1 = 0;
motor_speed = 0;
lcd_clr() ;
lcd_goto(0) ;
send_string("Drying Process ");
lcd_goto(20);
send_string("Complete! ");
}
}

But i kept having problems; the timing is very NOT accurate. I selected this '10 seconds' mode and it will only run at sometimes lesser than 5 secs, or more than 10 secs, or other random figures. Also during the motor is running, my LCD displays alot of rubbish and everything flickers/blinks very fast. Why is this happening?

Also, when it finishes, it resets itself to the main menu, which it shouldn't happen. It should just display "Drying Process Complete!", but no it did not. Is there an explanation?

Any help is welcomed, thank you.
 

ok..im not really good in mplab..but i know how your code flow..
put this after your include file..
__CONFIG ( 0x3F32 );
 

The method of timing 10 minutes you're using is imprecise. You might have much more success using a timer (and 16F877A has plenty of those).
You'll be able to find all the needed info on how timers work in the PIC16F877A datasheet.
 

@lockman_akim: i already have that in my codes.

@jumper2high: i'm sorry but i am very new in this. reading the datasheet is one thing, but writing a c program is another. i just don't know as to how or what to set or write. how does it make sense and all. i tried finding for guides from forums to read about, but every case is different, so its hard for me to add everything up. i could really use a sample code and probably have some explanations/comments by the side. please, any help in this form is greatly appreciated.
 

desmond,
Please just try to read the TIMER0 chapter of the datasheet. It will tell you how TIMERS work (in general) which will help you understand the C-program that uses timers.
 

@jumper2high: I've been reading about Timer1 and i did some research, coming upon this from here

Code:
volatile unsigned int sysclock;		/* 16-bit Global system clock */ 


/*--- Init Timer 1 ---*/

static void initTimer1(void)
  {
  T1CON = 0x01;
  TMR1IF = 0;
  TMR1IE = 1;
  }

/*--- Timer 1 interrupt vector ---*/

static void interrupt isr(void)
  {
  if(TMR1IF == 1)
    {
    sysclock++;

    TMR1ON = 0;		/* Pre-load for 1mS interrupt */
    TMR1L = 0;
    TMR1H = 0x3d;
    TMR1ON = 1;
    TMR1IF = 0;
    }
  }

/*--- Wait mS timer ---*/

static void wait_mS(unsigned int mS)
  {
  unsigned int timer = sysclock;

  while((sysclock - timer) < mS){
    CLRWDT();
    }
  }

/*--- End of File ---*/

Please correct me if I am wrong. I can understand that:
Initialization Part:
1) it enables Timer1 by setting T1CON = 0x01.
2) enables Timer interrupt by setting TMR1IE = 1 and clearing TMR1IF = 0.

ISR part:
1) if(TMR1IF == 1) means if the interrupt flag bit overflows?
2) sysclock++ meaning sysclock +1
3) Now this part I am lost; please explain this part to me?

TMR1ON = 0;
TMR1L = 0;
TMR1H = 0x3d; (what does this line do? what is 0x3d? Its in Hex right? What value does it represent?)
TMR1ON = 1;
TMR1IF = 0;

Wait mS timer part:
1) they set timer = sysclock
2) while timer minus sysclock is still smaller than mS, clear watch dog timer? how does this help in counting 1 sec delay?

Overall, will this code help my cause?

I read the datasheet and this:

Timer mode is selected by clearing the TMR1CS
(T1CON<1>) bit. In this mode, the input clock to the
timer is FOSC/4. The synchronize control bit, T1SYNC
(T1CON<2>), has no effect since the internal clock is
always in sync.

T1CON<1> means T1CON = 0x01;? I can't digest this well.
 
Last edited:

Desmond,
What you're doing is using existing code to try and make your program work. I'm trying to suggest an alternative approach, by first figuring out how the timer works and then making your own code without ever having to resort to reverse-engineering.

So, here goes:

In simple terms a timer 'counts' instructions. Every time an instruction is executed, the timer value increases. All timers have prescalers of certain ratio. A prescaler ratio is the number of instructions that need to be executed for a timer to increment once. On a 1:1, the timer counts every instruction (obvious), and on a 1:256 prescale every 256 instructions the timer will increment once.

Now, let's assume your microcontroller is working at 4MHz which gives it an instruction rate of 1MHz (it takes 4 clock cycles for one instruction to execute). So, to make a 1 second delay, we'd need to have an interrupt occur every 1.000.000 instructions. Timer1 is a 16 bit timer, so it will (by default) generate an interrupt every 65535 instructions. If we prescale it with 8, we get about 524280 instructions (a bit over half a second in our 4MHz scenario). Now, to spare us the hassle, instead of having the timer start from 0 every time, we'll tell it to start from 3035 (8*3035 = 24280) so it will generate an interrupt after 500.000 instructions, ergo - exactly half a second.

Now, the good thing about timers is that NO MATTER WHAT you do in the program code, an interrupt will always occur after the same time interval. This is not the case with delay subroutines.

So, what you wanna do is:

Set up the timer to use Instruction rate as the counting source by setting the right bits to the desired values
Set up the timer prescaler to 1:8 by setting the right bits to desired values
Tell the timer to start from 3035 by setting appropriate values to it's HIGH and LOW registers

Finally, when you're ready to 'start' the delay, enable the timer by setting the T1CON<0> bit to one (T1CON<0> marks the first bit, T1CON<1> would be the second bit, etc...)

As for longer delays, it's quite straightforward - if an interrupt occurs every half a second, every second interrupt is 1 second. Every 120 interrupts is 1 minute, and every 1200 interrupts is 10 minutes, so use a few temporary general purpose registers to count up to 1200 and you got your 10 minutes precisely timed.
 

So for my case, i'm using a 20MHz crystal, interrupts should occur every 5,000,000 instructions.
Timer1 = 16 bit timer, hence, 2^16 = 65,536 instructions, prescaling by 8 gives me 524,288.
5,000,000/524,288 = 9.54Hz, T = 0.105 secs.
For it to interrupt exactly 0.1 secs, i need it to start at.. 24288/8 = 3036! Hence, 10 interrupts = 1 second, 600 interrupts = 1 minute, 6000 interrupts = 10 minutes!

I understood it! You're really a great teacher jumper2high! Thank you!

With this, to begin timing, a friend of mine reminded me smtg about using the TMR1IF flag bit. I came across a code and now it makes sense to me, let me try to explain it to you?

Code:
static void interrupt isr(void)
{
if(TMR0IF==1){
TMR0IF=0;
counter++;
if(counter>=PULSE){         //PULSE = 19531
counter=0;
second++;}
if(second>=60){
second=0;
minute++;}
if(minute>=60){
minute=0;
hour[0]++;}
if(hour[0]>12){
hour[0]=1;
hour[1]++;}
if(hour[1]>1){
hour[1]=0;
date++;
day++;}
if(day>=7){
day=0;}
if(date>mo[month-1]){
date=1;
month++;}
if(month>12){
month=1;
year++;}
}
}

So as each interrupt at 500,000 instructions, this will give me exactly 0.1 seconds, timer will increment, meaning the interrupt flag bit, TMR1IF increases by 1, or to put it simply, TMR1IF == 1? By the order of this code, whenever TMR1IF == 1, it should be set to 0 instantly, and plus counter by 1. Until counter increases to equal/pass 19531, counter = 0, seconds plus 1. And so on.

@jumper 2 high, what do you think of my explanation?
 
Last edited:

TMR1IF is the "Timer 1 Interrupt Flag" - which is 1 if Timer1 interrupt occurred.

Good practice for any interrupt routine is to make sure you do the following:

Disable interrupts by setting the GIE (Global Interrupt Enable) bit to 0
Save Working register (WREG) to a temporary place (one of the GPRs)
Save STATUS register to a temporary place (another GPR)
Re-set the Interrupt Flag (TMR1IF)

Do all your interrupt processing as required

Restore the saved Working register (WREG)
Restore the STATUS register
Re-enable interrupts
Return from interrupt
 

May I ask why do we need to do such a routine?

Also, i'm trying to compile my codes now with MPLAB, but its showing me this error:

Error [196] G:\Program1\NEW.c; 394.15 struct/union required
Error [196] G:\Program1\NEW.c; 395.15 struct/union required
Error [196] G:\Program1\NEW.c; 396.15 struct/union required
Error [196] G:\Program1\NEW.c; 397.14 struct/union required
Error [196] G:\Program1\NEW.c; 398.14 struct/union required
Error [196] G:\Program1\NEW.c; 399.14 struct/union required

which is all of my timer1 codes below:
Code:
void init_timer1(void)
{
//Timer1 Registers Prescaler= 8 - TMR1 Preset = 3036 - Freq = 10.00 Hz - Period = 0.100000 seconds
T1CON.T1CKPS1 = 1;   // bits 5-4  Prescaler Rate Select bits
T1CON.T1CKPS0 = 1;   // bit 4
T1CON.T1OSCEN = 1;   // bit 3 Timer1 Oscillator Enable Control bit 1 = on
T1CON.T1SYNC = 1;    // bit 2 Timer1 External Clock Input Synchronization Control bit...1 = Do not synchronize external clock input
T1CON.TMR1CS = 0;    // bit 1 Timer1 Clock Source Select bit...0 = Internal clock (FOSC/4)
T1CON.TMR1ON = 1;    // bit 0 enables timer
TMR1H = 11;             // preset for timer1 MSB register
TMR1L = 220;             // preset for timer1 LSB register
}

why is this happening? i already declared it as a global function/at the start of my codes.
 

May I ask why do we need to do such a routine?
Why do we need to save W and STATUS?

We never know exactly when the interrupt is going to occur. It will occur after 500.000 instructions, but where that is, we don't know.

Since WREG and STATUS are used for almost every instruction (including the instructions in the interrupt routine), if you have code that does:

MOVLW 0x01
MOVWF PORTB

What would happen if an interrupt ocurred after MOVLW but before MOVWF and the working register was used inside the interrupt routine?

MOVLW 0x01
{interrupt}
MOVWF PORTB

As you may have figured, in this case, there's no telling what might be in WREG after the interrupt routine, so there's no telling what will be moved to PORTB.

Naturally, if you save the state of WREG inside the interrupt routine, and restore it just before continuing with normal program, that "unknown" is eliminated.



As for the error - I think you may be missing a header file include or something, so that the structures that represent registers and their bits are missing.
 

Alright I understand now, I will add those shortly. However, can you take a look at my previous' post's problem? Why is it asking me to use struct and union?

---------- Post added at 21:56 ---------- Previous post was at 21:19 ----------

Can anyone explain to me why am i getting such errors? I don't understand why i should be using struct/union in this case.

Error [196] G:\Program1\NEW.c; 394.15 struct/union required
Error [196] G:\Program1\NEW.c; 395.15 struct/union required
Error [196] G:\Program1\NEW.c; 396.15 struct/union required
Error [196] G:\Program1\NEW.c; 397.14 struct/union required
Error [196] G:\Program1\NEW.c; 398.14 struct/union required
Error [196] G:\Program1\NEW.c; 399.14 struct/union required

Code:
void init_timer1(void)
{
//Timer1 Registers Prescaler= 8 - TMR1 Preset = 3036 - Freq = 10.00 Hz - Period = 0.100000 seconds
T1CON.T1CKPS1 = 1;   // bits 5-4  Prescaler Rate Select bits
T1CON.T1CKPS0 = 1;   // bit 4
T1CON.T1OSCEN = 1;   // bit 3 Timer1 Oscillator Enable Control bit 1 = on
T1CON.T1SYNC = 1;    // bit 2 Timer1 External Clock Input Synchronization Control bit...1 = Do not synchronize external clock input
T1CON.TMR1CS = 0;    // bit 1 Timer1 Clock Source Select bit...0 = Internal clock (FOSC/4)
T1CON.TMR1ON = 1;    // bit 0 enables timer
TMR1H = 11;             // preset for timer1 MSB register
TMR1L = 220;             // preset for timer1 LSB register
}

I looked up how to write them, but it seems odd as i get more errors regarding my T1CON needing to be redefined and asking for missing ';'

Error [323] G:\Program1\NEW.c; 391.7 struct/union tag or "{" expected
Error [269] G:\Program1\NEW.c; 391.7 inconsistent type
Error [314] G:\Program1\NEW.c; 394.19 ";" expected
Warning [374] G:\Program1\NEW.c; 394.28 missing basic type; int assumed
Error [314] G:\Program1\NEW.c; 394.28 ";" expected
Warning [374] G:\Program1\NEW.c; 394.30 missing basic type; int assumed
Error [314] G:\Program1\NEW.c; 394.30 ";" expected
Warning [374] G:\Program1\NEW.c; 394.31 missing basic type; int assumed
Error [261] G:\Program1\NEW.c; 395.19 struct/union member "T1CON" redefined
Error [261] G:\Program1\NEW.c; 395.19 struct/union member "T1CON" redefined
Error [314] G:\Program1\NEW.c; 395.19 ";" expected
Warning [374] G:\Program1\NEW.c; 395.28 missing basic type; int assumed
Error [314] G:\Program1\NEW.c; 395.28 ";" expected
Warning [374] G:\Program1\NEW.c; 395.30 missing basic type; int assumed
Error [314] G:\Program1\NEW.c; 395.30 ";" expected
Warning [374] G:\Program1\NEW.c; 395.31 missing basic type; int assumed
Error [261] G:\Program1\NEW.c; 396.19 struct/union member "T1CON" redefined
Error [261] G:\Program1\NEW.c; 396.19 struct/union member "T1CON" redefined
Error [314] G:\Program1\NEW.c; 396.19 ";" expected
Warning [374] G:\Program1\NEW.c; 396.28 missing basic type; int assumed
Error [314] G:\Program1\NEW.c; 396.28 ";" expected
Warning [374] G:\Program1\NEW.c; 396.30 missing basic type; int assumed
Error [314] G:\Program1\NEW.c; 396.30 ";" expected
Warning [374] G:\Program1\NEW.c; 396.31 missing basic type; int assumed
Error [261] G:\Program1\NEW.c; 397.19 struct/union member "T1CON" redefined
Error [261] G:\Program1\NEW.c; 397.19 struct/union member "T1CON" redefined
Error [314] G:\Program1\NEW.c; 397.19 ";" expected
Warning [374] G:\Program1\NEW.c; 397.27 missing basic type; int assumed
Error [314] G:\Program1\NEW.c; 397.27 ";" expected
Warning [374] G:\Program1\NEW.c; 397.29 missing basic type; int assumed
Error [314] G:\Program1\NEW.c; 397.29 ";" expected
Warning [374] G:\Program1\NEW.c; 397.30 missing basic type; int assumed
Error [261] G:\Program1\NEW.c; 398.19 struct/union member "T1CON" redefined
Advisory[1] too many errors (21)

Code:
union void init_timer1(void){
struct {
//Timer1 Registers Prescaler= 8 - TMR1 Preset = 3036 - Freq = 10.00 Hz - Period = 0.100000 seconds
T1CON.T1CKPS1 = 1;   // bits 5-4  Prescaler Rate Select bits
T1CON.T1CKPS0 = 1;   // bit 4
T1CON.T1OSCEN = 1;   // bit 3 Timer1 Oscillator Enable Control bit 1 = on
T1CON.T1SYNC = 1;    // bit 2 Timer1 External Clock Input Synchronization Control bit...1 = Do not synchronize external clock input
T1CON.TMR1CS = 0;    // bit 1 Timer1 Clock Source Select bit...0 = Internal clock (FOSC/4)
T1CON.TMR1ON = 1;    // bit 0 enables timer
TMR1H = 11;             // preset for timer1 MSB register
TMR1L = 220;             // preset for timer1 LSB register
} intialize;
}

At this point, i'm lost at what i am to do :\ please help.
 

OK i have managed to compile after deleting 'T1CON.' from every line. Will update more on my progress later :)
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top