CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Can't display data in LCD when use interrupt

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
garen



Joined: 30 Aug 2015
Posts: 17

View user's profile Send private message

Can't display data in LCD when use interrupt
PostPosted: Sat Nov 14, 2015 11:07 am     Reply with quote

Hi everyone

i have a project with encoder motor, i have finished read encoder and show it in lcd. But i just write 3 command in main to show data ,when i write more than command , encorder seem not run and lcd just show 0.00. whether PIC always handler interrupt function and not enough time for main. i don't know what actually problem and what should i do if i want to write more than. This is all of my code

Code:

#include <16f887.h>
#fuses hs,nowdt,nolvp,protect,put
#use delay(clock=16M)
#define LCD_RS_PIN      PIN_E0                                 
#define LCD_RW_PIN      PIN_E1
#define LCD_ENABLE_PIN  PIN_E2                                                           
#define LCD_DATA4       PIN_D4                                 
#define LCD_DATA5       PIN_D5                               
#define LCD_DATA6       PIN_D6                               
#define LCD_DATA7       PIN_D7
#include <lcd.c>
#use pwm(OUTPUT=PIN_C2, TIMER=2, FREQUENCY=1000,stream=PWM1)
int1 status;
unsigned int8 mode;
int16 fulse,duty;
float omega;

#int_timer1
void timer1_isr()      //set 100ms read fulse from encoder
{
   set_timer1(15536);// reload value for timer1
   omega=(float)fulse;  // read fulse every 100ms
   fulse=0;                   //reset fulse
}

#int_ext
void ext_isr()       //increase fulse when it have falling edge
{
   fulse++;
}

void dc_output(int1 dir,int16 duty) // function to control motor, direction and duty of motor
{
   if(dir==0)
   {
      output_a(0x02);       //pin_a0=0;pin_a1=1;=>motor run clockwise direction
      pwm_set_duty_percent(PWM1,duty);
   }
   else
   {
      output_a(0x01);                    //pin_a0=1;pin_a1=0;=>motor invert
      pwm_set_duty_percent(PWM1,duty);
   }
}
void main()
{
   set_tris_a(0x04);output_a(0x00);
   set_tris_b(0xFF);port_b_pullups(0xFF);
   lcd_init();
   
   enable_interrupts(GLOBAL);
   enable_interrupts(PERIPH);
   enable_interrupts(INT_EXT_H2L);
   enable_interrupts(INT_TIMER1);
   
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
   set_timer1(15536);
   fulse=0;
   while(true)
   { 
     dc_output(0,1000);
     lcd_gotoxy(1,1);
     printf(lcd_putc, "%fRPM", (omega/334)*10*60); // calculate speed of motor and show in lcd
      //at here, if i the end of here, everything is fine, speed is showed in line 1 lcd exactly :)
     // but if i write more than command, like a : lcd_gotoxy(1,2);printf(lcd_putc,"Test ok"); lcd just show 0.00 in line 1 , and "Test Ok in line 2" :sad:
   }
}

Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Sat Nov 14, 2015 11:59 am     Reply with quote

Lots of comments:

First, don't enable protect, until you have finished debugging your code.
Having this enabled, means that the chip has to be fully erased any time you reprogram it. This unnecessarily, uses extra lives on the cells of the memory....

Then, you are just using INT_EXT, to count a signal. Why not let the hardware do this?. Timer0 can count an input signal on the T0CKI pin for you. Unfortunately with your rather basic chip, only an 8bit counter (most later chips will offer a 16bit counter here, or on one of the other counters). In fact if you used Timer1, and T1OSI, with an /1 prescaler this will count the signal for you , then you can use Timer0 with /256 prescaler for your 100mSec, just having to set it forward by 100 to give 100mSec timing on this. Only one interrupt needed rather than two. Also generally, setting a timer 'to' a value will not give a good time, since the timer _will_ have advanced when it arrives in the interrupt. Search here about this.

Then there is a problem, since your value may well update while you are displaying it. LCD's are _slow_. Disable the interrupts for a moment, and copy the recorded count to a local variable, then re-enable the interrupt. Any variable larger than an INT8, potentially has this problem, and using a float makes it worse (see below).

Then don't turn the count into a float in the interrupt. This uses a lot of instructions, and is pointless. Leave the number as an integer, and do the maths using integers:

(val/334) * 10 * 60

Could instead be done with

(val * 6000) /334, to give 10* the value in integer, and displayed using %5.1w, to still give a decimal result. Much faster.

You don't need enable_interrupt(PERIPH). 'GLOBAL' turns on everything.
garen



Joined: 30 Aug 2015
Posts: 17

View user's profile Send private message

PostPosted: Sun Nov 15, 2015 12:56 am     Reply with quote

i have ever thought use hardware on counter 1 for get fulse but if my main so long, PIC can't get fulse immediately and i can lose some fulse. Result will be wrong. So i decide to use interrupt to get fulse immediately when Encoder have fulse. Whether i use timer 0 set 100ms and timer 1 get external fulse will be fine???

I tried again with integer instead of float, but it seems no change, i just write 3 command in main, no more, if i show line 2 in lcd, value of speed will stop.

Code:

#include <16f887.h>
#fuses hs,nowdt,nolvp,noprotect,put
#use delay(clock=16M)
#define LCD_RS_PIN      PIN_E0                                 
#define LCD_RW_PIN      PIN_E1
#define LCD_ENABLE_PIN  PIN_E2                                                           
#define LCD_DATA4       PIN_D4                                 
#define LCD_DATA5       PIN_D5                               
#define LCD_DATA6       PIN_D6                               
#define LCD_DATA7       PIN_D7
#include <lcd.c>
#use pwm(OUTPUT=PIN_C2, TIMER=2, FREQUENCY=1000,stream=PWM1)

void dc_output(int1 dir,int16 duty);

int1 status;
int16 fulse,duty;
int32 omega;

#int_timer1
void timer1_isr()
{
   set_timer1(15536);
   omega=fulse;
   fulse=0;
}

#int_ext
void ext_isr()
{
   fulse++;
}

void main()
{
   set_tris_a(0x04);output_a(0x00);
   set_tris_b(0xFF);port_b_pullups(0xFF);
   lcd_init();
   
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_EXT_H2L);
   enable_interrupts(INT_TIMER1);
   
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
   set_timer1(15536);
   fulse=0;duty=1000;
   while(true)
   { 
      dc_output(0,duty);
      lcd_gotoxy(1,1);printf(lcd_putc,"%ldRPM",(omega*600)/334);
      lcd_gotoxy(1,2);printf(lcd_putc,"Test OK")   //when this command is written here ,lcd not run
   }
}

void dc_output(int1 dir,int16 duty)
{
   if(dir==0)
   {
      output_a(0x02);
      pwm_set_duty_percent(PWM1,duty);
   }
   else
   {
      output_a(0x01);
      pwm_set_duty_percent(PWM1,duty);
   }
}


what should i do next :(
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Sun Nov 15, 2015 4:43 am     Reply with quote

Time for some thinking.

How fast is your motor rotating?
What is the pulse rate you are asking the interrupt to handle?
How long does it take to get into and out of an interrupt?
Why not use Mr T's suggestion of using only one interrupt?

I doubt your code as shown is what you actually used.
Code:
      lcd_gotoxy(1,2);printf(lcd_putc,"Test OK")   //when this command is written here ,lcd not run
The line above should cause the compiler to complain (its missing a ";").

Mike
garen



Joined: 30 Aug 2015
Posts: 17

View user's profile Send private message

PostPosted: Sun Nov 15, 2015 5:35 am     Reply with quote

My motor is a encoder motor 334RPM (334 fulse for 1 round) and when i measure with full duty 100%, i see 700 fulse for 100mSec.

My purpose is get fulse immediately and read fulse every 100mSec to show in line 1 LCD. if it that so, i finished, but when i try to show more than information in line 2 lcd, lcd still show line 2 but, speed is not run(not show) in line 1. Whether this forum have a post short video. If it have i will show you real image.

With suggestion of Mr.T, first time i have something don't understand but now, i think he right. Maybe i will try again with this way.

With ";" of command, sorry because i copy missing.
temtronic



Joined: 01 Jul 2010
Posts: 9246
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sun Nov 15, 2015 8:25 am     Reply with quote

this equation....

(omega*600)/334);

could be reduced to omega *1.8

and it'd be a LOT faster as division takes a LONG time......

Jay
garen



Joined: 30 Aug 2015
Posts: 17

View user's profile Send private message

PostPosted: Sun Nov 15, 2015 9:01 am     Reply with quote

i was rewrite my code according Ttelmah's advice. However i still face this problem. Beginning with get fulse from counter 1( counter of timer 1), no calculate, do nothing, just get fulse and show in lcd, this problem appeared.

When i just show pulses per 100ms in lcd, this is ok , but when i write some more, pulse value is stop (stand by present value and just show only this value).

Code:

#include <16f887.h>
#fuses hs,nowdt,nolvp,noprotect,put
#use delay(clock=16M)
#define LCD_RS_PIN      PIN_E0                                 
#define LCD_RW_PIN      PIN_E1
#define LCD_ENABLE_PIN  PIN_E2                                                           
#define LCD_DATA4       PIN_D4                                 
#define LCD_DATA5       PIN_D5                               
#define LCD_DATA6       PIN_D6                               
#define LCD_DATA7       PIN_D7
#include <lcd.c>
#use pwm(OUTPUT=PIN_C2, TIMER=2, FREQUENCY=1000,stream=PWM1)

int16 omega;

#int_rtcc
void rtcc_isr()         //set timer 0 is interrupt every 4000us
{
   
   int8 time_count;
   set_timer0(125);
   if(++time_count==25)   {time_count=0;omega=get_timer1();set_timer1(0);}  //every 4000*25=100 000us then get fulse from encoder
}

void main()
{
   set_tris_a(0x04);output_a(0x00);
   set_tris_b(0xFF);port_b_pullups(0xFF);
   lcd_init();
   
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_RTCC);
   setup_timer_0(T0_INTERNAL|T0_DIV_128);
   set_timer0(125);
   
   setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1);
   set_timer1(0);
   
   while(true)
   { 
      output_a(0x02);
      pwm_set_duty_percent(PWM1,1000);                            // motor'direction is inverted, full speed duty=1000
      lcd_gotoxy(1,1);printf(lcd_putc,"%ldRPM",omega);// at here, if that so, everything is ok ,lcd show pulse per 100ms
      //but if i replace with lcd_gotoxy(1,1);printf(lcd_putc,"%ldRPMKKK",omega); LCD stand by at present value and don't update pulse in lcd
   }
}


This is some real image
_when i just use lcd_gotoxy(1,1);printf(lcd_putc,"%ldRPM",omega); everything is fine, lcd show pulse well



when i replace with this command lcd_gotoxy(1,1); printf(lcd_putc,"%ldRPMKKK",omega); lcd is always stand by at a random number (i don't know number and it not pulse i need) and it not update pulse in lcd, i don't know whether interrupts was stopped. This image show my problem
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Nov 15, 2015 9:39 am     Reply with quote

Ttelmah told you this but you didn't see it:
Quote:

Disable the interrupts for a moment, and copy the recorded count to a
local variable, then re-enable the interrupt. Any variable larger than an
INT8, potentially has this problem, and using a float makes it worse (see
below).


First do this test. Add the code shown in bold below.
Does it fix the problem ?
Quote:

void main(void)
{
int16 temp;
.
.
.
while(TRUE)
{
output_a(0x02);
pwm_set_duty_percent(PWM1,1000);

// Copy omega into a local variable with interrupts disabled,
// to avoid reading a partially updated int16 omega.
disable_interrupts(GLOBAL);
temp = omega;
enable_interrupts(GLOBAL);

lcd_gotoxy(1,1);
printf(lcd_putc, "%ldRPMKKK", temp);
}

}

Some other suggestions:
Don't put multiple C statements on one line. It makes your program
harder to read. Do like I did above, with one statement per line, and
put a blank line between blocks of related code.
garen



Joined: 30 Aug 2015
Posts: 17

View user's profile Send private message

PostPosted: Sun Nov 15, 2015 10:04 am     Reply with quote

I was fix my code like your help, but if just have lcd_gotoxy(1,1);printf(lcd_putc,"%ldRPM",temp); lcd will show 700RPM
when i add more lcd_gotoxy(1,1);printf(lcd_putc,"Speed=%ldRPM",temp); lcd show Speed=923RPM and if i add line 2 lcd_gotoxy(1,2);printf(lcd_putc,"Direction:"); lcd will show in line 1:Speed=1093RPM and line 2: Direction

pulse will as increase as write more command. and pulse value maybe not right. :(

Code:

#include <16f887.h>
#fuses hs,nowdt,nolvp,noprotect,put
#use delay(clock=16M)
#define LCD_RS_PIN      PIN_E0                                 
#define LCD_RW_PIN      PIN_E1
#define LCD_ENABLE_PIN  PIN_E2                                                           
#define LCD_DATA4       PIN_D4                                 
#define LCD_DATA5       PIN_D5                               
#define LCD_DATA6       PIN_D6                               
#define LCD_DATA7       PIN_D7
#include <lcd.c>
#use pwm(OUTPUT=PIN_C2, TIMER=2, FREQUENCY=1000,stream=PWM1)
int1 tt;
int16 omega,temp;

#int_rtcc
void rtcc_isr()     
{
   int8 time_count;
   set_timer0(125);
   if(++time_count==25)   {time_count=0;omega=get_timer1();set_timer1(0);} 
}

void main()
{
   set_tris_a(0x04);output_a(0x00);
   set_tris_b(0xFF);port_b_pullups(0xFF);
   lcd_init();
   
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_RTCC);
   setup_timer_0(T0_INTERNAL|T0_DIV_128);
   set_timer0(125);
   
   setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1);
   set_timer1(0);
   
   while(true)
   {             
      output_a(0x02);
      pwm_set_duty_percent(PWM1,1000);
     
      disable_interrupts(GLOBAL);
      temp = omega;
      enable_interrupts(GLOBAL);
      lcd_gotoxy(1,1);printf(lcd_putc,"%ldRPM",temp);//if i use this command. lcd will show 700
     
      //lcd_gotoxy(1,1);printf(lcd_putc,"Speed=%ldRPM",temp); if i use this command. lcd will show 900
      //lcd_gotoxy(1,2);printf(lcd_putc,"Direction:"); add line 2 in lcd and line 1 .lcd will show 1097
      //.
      //.
      //.
      //.
      //what happened if i write so much command in here. pulse in lcd seem increase and wrong
   }
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Nov 15, 2015 10:12 am     Reply with quote

Post your CCS compiler version. We need to see if it has the bug
with interrupts disabled during printf.

The compiler version is given at the start of the .LST file. The .LST file
will be in your project directory after a successful compilation. The
compiler version is a 4-digit number such as 4.141, 5.049, etc.
garen



Joined: 30 Aug 2015
Posts: 17

View user's profile Send private message

PostPosted: Sun Nov 15, 2015 10:41 am     Reply with quote

i use ccs v5.011.


i have just used printf to send to terminal and i alway receive 541 ,even though i change duty 500,700,800, terminal still show 541. perhaps interrupts did not run.
This is code i rewrite to send data to terminal with pin_c4 (tx) and pin_c5(rx),baud 9600
Code:

#include <16f887.h>
#fuses hs,nowdt,nolvp,noprotect,put
#use delay(clock=16M)
#define LCD_RS_PIN      PIN_E0                                 
#define LCD_RW_PIN      PIN_E1
#define LCD_ENABLE_PIN  PIN_E2                                                           
#define LCD_DATA4       PIN_D4                                 
#define LCD_DATA5       PIN_D5                               
#define LCD_DATA6       PIN_D6                               
#define LCD_DATA7       PIN_D7
#include <lcd.c>
#use pwm(OUTPUT=PIN_C2, TIMER=2, FREQUENCY=1000,stream=PWM1)
#use rs232(baud=9600, xmit=PIN_C4,rcv=PIN_C5)

int16 omega,temp,duty;

#int_rtcc
void rtcc_isr()     
{
   int8 time_count;
   set_timer0(125);
   if(++time_count==25)   {time_count=0;omega=get_timer1();set_timer1(0);} 
}

void main()
{
   set_tris_a(0x04);output_a(0x00);
   set_tris_b(0xFF);port_b_pullups(0xFF);
   lcd_init();
   
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_RTCC);
   setup_timer_0(T0_INTERNAL|T0_DIV_128);
   set_timer0(125);
   
   setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1);
   set_timer1(0);
   
   while(true)
   {   
      output_a(0x02);
      pwm_set_duty_percent(PWM1,1000);// when i replace duty =1000 with 700,800,900 i always receive 541 pulse in terminal. 541 is wrong , the number must about 742 for duty=1000
      printf("Speed=%ldRPM\r\n",omega);
     
      //lcd_gotoxy(1,1);printf(lcd_putc,"Speed=%ldRPM",omega);
      //lcd_gotoxy(1,2);printf(lcd_putc,"Direction:");
   }
}


PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Nov 15, 2015 10:47 am     Reply with quote

Quote:
i use ccs v5.011.

From the CCS versions page:
Quote:
5.013 A problem with printf disabling interrupts on some parts is fixed

http://www.ccsinfo.com/devices.php?page=versioninfo
garen



Joined: 30 Aug 2015
Posts: 17

View user's profile Send private message

PostPosted: Sun Nov 15, 2015 10:54 am     Reply with quote

that so terrible. Sad So what should i do now, come back to older version or use latest version. because in ccs5 have #use pwm which easy to use pwm.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Nov 15, 2015 11:16 am     Reply with quote

There might be a workaround. You could break up the printf statement
into smaller statements that put out a few characters each time, and
add enable_interrupts(GLOBAL); after each statement. Another way
would be to do the int16 to ASCII decimal conversion with your own
routine, instead of using printf. Then output the characters by using putc.
Or upgrade the compiler.

But I noticed something here in your latest code:
Quote:
while(true)
{
output_a(0x02);
pwm_set_duty_percent(PWM1,1000);// when i replace duty =1000 with 700,800,900 i always receive 541 pulse in terminal. 541 is wrong , the number must about 742 for duty=1000
printf("Speed=%ldRPM\r\n",omega);

//lcd_gotoxy(1,1);printf(lcd_putc,"Speed=%ldRPM",omega);
//lcd_gotoxy(1,2);printf(lcd_putc,"Direction:");
}

You took out the disable/enable interrupts around the reading of 'omega'.
Why did you do that ? Because it didn't fix your problem ? Your code
likely has multiple problems. Don't remove a known, good, working fix
for one problem, just because it doesn't solve all problems. Leave each
fix in there.
garen



Joined: 30 Aug 2015
Posts: 17

View user's profile Send private message

PostPosted: Sun Nov 15, 2015 12:21 pm     Reply with quote

That so amazing. finally it have done when i use ccs 5.048, everything is ok with this version. and with this version,i recognize that no need to add more enable interrupts and disable interrupts,it still run exactly.
However,Thank you so much for your help.i appreciate it. My problem was solved with version 5.048.
And finally, this is all of code which succeed and is tested in real board
Code:

#include <16f887.h>
#fuses hs,nowdt,nolvp,noprotect,put
#use delay(clock=16M)
#define LCD_RS_PIN      PIN_E0                                 
#define LCD_RW_PIN      PIN_E1
#define LCD_ENABLE_PIN  PIN_E2                                                           
#define LCD_DATA4       PIN_D4                                 
#define LCD_DATA5       PIN_D5                               
#define LCD_DATA6       PIN_D6                               
#define LCD_DATA7       PIN_D7
#include <lcd.c>
#use pwm(OUTPUT=PIN_C2, TIMER=2, FREQUENCY=1000,stream=PWM1)
//channel A connect to Pin_C0
//Direction of l298 connect to Pin_a0 and Pin_a1
//
int16 omega;

#int_rtcc
void rtcc_isr()     
{
   int8 time_count;
   set_timer0(125);
   if(++time_count==25)   {time_count=0;omega=get_timer1()*1.8;set_timer1(0);} 
}

void main()
{
   set_tris_a(0x04);output_a(0x00);
   set_tris_b(0xFF);port_b_pullups(0xFF);
   lcd_init();
   
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_RTCC);
   setup_timer_0(T0_INTERNAL|T0_DIV_128);
   set_timer0(125);
   
   setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1);
   set_timer1(0);
   while(true)
   {   
      output_a(0x02);
      pwm_set_duty_percent(PWM1,1000);
      lcd_gotoxy(1,1);printf(lcd_putc,"Speed=%ldRPM ",omega);
 
   }
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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