View previous topic :: View next topic |
Author |
Message |
ftrax
Joined: 24 Sep 2013 Posts: 22 Location: España
|
problem int_rda with PIC 16F688 |
Posted: Fri Nov 22, 2013 7:20 am |
|
|
Hi everyone,
I'm using CCS 5.010 and I have a problem, my program doesn't work correctly, the PIC doesn't enter into the while(true).
When the code arrives at "enable_interrupt(int_rda);" , the program executes the interrupt but they never come out from there, program execution stays into the interrupt forever.
I try to solve this problem but I'm not able to find a solution.
Anyone knows what I'm doing wrong??
Well, hope someone could help me.
Here goes the code:
Code: |
#include <16F688.h>
//#device adc=10
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOPUT //Power Up Timer
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES NOPROTECT
#FUSES NOCPD
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOIESO
#FUSES NOFCMEN
//////////////////////////////////////////////
//////****CONFIGURACIÓN CLOCK y RS232****/////
//////////////////////////////////////////////
#use delay(internal=4000000)
#use rs232(baud=9600,xmit=PIN_C4,rcv=PIN_C5,parity=N)
//////////////////////////////////////////////
///////////****CONFIGURACIÓN I/O****//////////
//////////////////////////////////////////////
#use fast_io(A)
#use fast_io(C)
#define configa 0b00000110
#define configc 0b00100000
#bit buzzer = 0x7.0 //Es el pin C0
#bit stolva = 0x5.1 //Es el pin A1
//////////////////////////////////////////////
////////***** FICHEROS INCLUIDOS *****////////
//////////////////////////////////////////////
#include <stdlib.h>
#include <input_mod.c>
#include <string.h>
#include <stdio.h>
#include <lcdindif.c>
//////////////////////////////////////////////
////////******** DEFINICIONES ********////////
//////////////////////////////////////////////
#define ms1 83
#define ms10 820
#define ms100 8320
//#byte alarmas = 0x85
//#bit alarmRPM = 0x85.0
//#bit alarmCAR = 0x85.1
///////////////////////////////////////////
//////////***VARIABLES GLOBALS***//////////
///////////////////////////////////////////
short refresca=0;
short alarmRPM=0,alarmCAR=0;
int hectarees[9];
long counter=0;
long t1r=28036;
long delay=0;
float proba=0;
///////////////////////////////////////////
////////***** INTERRUPCIONES *****/////////
///////////////////////////////////////////
#int_rda
void rda_isr(void){
//if(input(pin_c5)==1){
//get_string(hectarees,9);
//}
output_toggle(pin_a0);
delay_ms(100);
}
//*************** INT TIMER1*********************
#int_TIMER1
void TIMER1_isr(void) {
static int cont=0;
static int auxbuzzer;
set_timer1(t1r); // Recarga a 0.3s
cont++;
if((alarmRPM==1)||((alarmCAR==1)&&(auxbuzzer<4))){
auxbuzzer++;
buzzer=~buzzer;
}
if((alarmCAR==0)||(auxbuzzer>=4)){
auxbuzzer=0;
}
if(cont==2)
{
cont=0;
counter=get_timer0(); //Lectura contador TMR0
set_timer0(0); //Reinicia cuenta
//counter*=(100/2); //Conversión a rpm
//hi ha dos polos per volta
counter*=50;
refresca=1;
}
}
////////////////////////////////////////////
//////////***PROGRAMA PRINCIPAL***//////////
////////////////////////////////////////////
void main()
{
setup_adc(ADC_OFF);
setup_adc_ports(no_analogs);
setup_comparator(NC_NC_NC_NC);
setup_counters( T0_EXT_L_TO_H | T0_DIV_1, T0_8_BIT );
setup_oscillator(OSC_INTRC|OSC_4MHZ);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
setup_vref( VREF_HIGH );
setup_wdt(WDT_OFF);
enable_interrupts(int_timer1);
set_timer1(t1r);
set_timer0(0);
set_tris_a(configa);
set_tris_c(configc);
output_a(0);
output_c(0);
enable_interrupts(int_rda);
enable_interrupts(global);
for(delay=0;delay<ms100;delay++);
lcd_init();
lcd_clear();
while(true){
if(refresca==1){
refresca=0;
lcd_erase_line(1);
lcd_gotoxy(1,1);
//proba=strtof(hectarees,9);
//printf(lcd_putc, "Hect: %9.3f" ,proba);
printf(lcd_putc," %6lu rpm",counter);
if(counter<3500)
{
alarmRPM=1;
}
else
{
alarmRPM=0;
buzzer=0;
}
if(stolva==0){
alarmCAR=1;
lcd_gotoxy(1,2);
printf(lcd_putc," NIVEL MINIMO ");
}
else
{
alarmCAR=0;
lcd_erase_line(2);
lcd_gotoxy(1,2);
proba=strtof(hectarees,9);
printf(lcd_putc, "Hect: %9.3f" ,proba);
}
}
}
}
|
|
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1934 Location: Norman, OK
|
|
Posted: Fri Nov 22, 2013 7:30 am |
|
|
You have to get the received character signaled by the interrupt for the
interrupt to be cleared. Using getc() in the interrupt routine will do that for you.
Code: | #int_rda
void rda_isr(void){
int x;
x=getc();
//if(input(pin_c5)==1){
//get_string(hectarees,9);
//}
output_toggle(pin_a0);
delay_ms(100);
} |
_________________ Google and Forum Search are some of your best tools!!!! |
|
|
ftrax
Joined: 24 Sep 2013 Posts: 22 Location: España
|
|
Posted: Sun Nov 24, 2013 4:28 am |
|
|
Hi dyeatman,
I haven't try solution yet, but tomorrow I try this, the idea is not using getc() if not input in pin_c5.
There are any method to clear the interrupt without using getc().?
Thanks for all. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Sun Nov 24, 2013 5:23 am |
|
|
Simple answer. No.
INT_RDA, occurs, when the hardware UART has a character waiting to be read. Once this happens, there is always a 'character waiting to be read', until it is read....
There are several hardware interrupts that reflect events like this (INT_RB for example), where the hardware event _must_ be cleared, or the interrupt will trigger for ever.
Best Wishes |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9228 Location: Greensville,Ontario
|
|
Posted: Sun Nov 24, 2013 6:15 am |
|
|
also..
never put delays inside any ISR !
and..
always add 'errors' to use rs232(...) when using the hardware UART.
hth
jay |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sun Nov 24, 2013 7:41 am |
|
|
So, to clear the RDA interrupt you always have to do a getc() call. But, it is up to you what to do with the read data. If you want to throw the data away because PIN_A5 is high, then do so.
Then just a few minor comments on your coding style to make you an even better programmer.
1) In your whole program I never see you using spaces in a line, this makes it more difficult to read and has no advantages that I can think of. For example this line:
Code: | if((alarmRPM==1)||((alarmCAR==1)&&(auxbuzzer<4))){ | Itisdifficulttoreadwhatiswrittenherewithoutspaces.
Another possible way to write the same line: Code: |
if ( (alarmRPM == 1)
|| ((alarmCAR == 1) && (auxbuzzer < 4))
)
{ |
2) Good practice is to write all constants and #defined values in full capital names. This way you immediately see the difference between variables and constant values.
For example:
'configa' --> 'CONFIGA'
'pin_a5' --> 'PIN_A5'
3) The CCS compiler defines a 1-bit variable with the type 'short'. In other compilers the short type has a different size, for example 8 or even 16-bit. To make your program more portable it is good practice to always use types that hard code a desired bit size, that is types like: int1, int8, int16 and int32
4) When using boolean variables it is good practice to give them a name expressing an action. For example starting with the word 'is' or 'has' included.
In your original code it is not clear when the buzzer is on. Is the buzzer active when 0 or when 1?
Change the name to 'isBuzzerOn'
In code this becomes: Code: | if (isBuzzerOn) { do something } | Now the code has become self documenting. |
|
|
ftrax
Joined: 24 Sep 2013 Posts: 22 Location: España
|
|
Posted: Sun Nov 24, 2013 9:18 am |
|
|
Hi Ttelmah,
the problem is that the PIC executes the interrupt when I enabled with "enable_interrupts(int_rda), enable_interrupts(global)", but its impossible that the int_rda occurs because in these pin isn't connecting anything. |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1934 Location: Norman, OK
|
|
Posted: Sun Nov 24, 2013 9:27 am |
|
|
It is NOT impossible. The pin is floating and picking up noise.
If you want to get an interrupt but not receive a character disable the USART and use a different interrupt, not int_rda.
Look at page 2 of the datasheet to see what is available. Maybe you want RA2? _________________ Google and Forum Search are some of your best tools!!!!
Last edited by dyeatman on Sun Nov 24, 2013 9:34 am; edited 2 times in total |
|
|
ftrax
Joined: 24 Sep 2013 Posts: 22 Location: España
|
|
Posted: Sun Nov 24, 2013 9:32 am |
|
|
Hi temtronic,
I never put delays inside ISR in a "real" source code, but in this case I needed know if the PIC entry in the ISR, and the only way I could think was put delay inside.
Thanks for the tip to add 'errors' in the directive to #use rs232. |
|
|
ftrax
Joined: 24 Sep 2013 Posts: 22 Location: España
|
|
Posted: Sun Nov 24, 2013 9:41 am |
|
|
Hi ckielstra
Thanks for all of your comments.
I'm a novice programmer and I think your comments are good to help me correct my bad habits. |
|
|
ftrax
Joined: 24 Sep 2013 Posts: 22 Location: España
|
|
Posted: Sun Nov 24, 2013 9:44 am |
|
|
Sorry dyeatman,
I'm forget comment that this pin is not floating, I connect them to GND with 47k resistance.
thanks for all. |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1934 Location: Norman, OK
|
|
Posted: Sun Nov 24, 2013 9:49 am |
|
|
It needs to be pulled high, not low. High is inactive and low is the active
state so it is being seen as a start bit. _________________ Google and Forum Search are some of your best tools!!!! |
|
|
ftrax
Joined: 24 Sep 2013 Posts: 22 Location: España
|
|
Posted: Sun Nov 24, 2013 10:25 am |
|
|
Thanks dyeatman
tomorrow I try all solutions, and then I explain the results. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Sun Nov 24, 2013 12:05 pm |
|
|
As a general comment, the data sheet is your friend.
If you look at fig 10-5, the very top line shows the RX pin. Idling high, and a 'low' being the start bit.
Best Wishes |
|
|
ftrax
Joined: 24 Sep 2013 Posts: 22 Location: España
|
|
Posted: Mon Nov 25, 2013 4:20 am |
|
|
Hi guys,
finally thanks to your assistance I have succeeded to fix the problem.
The final source code is this:
Code: |
#include <16F688.h>
//#device adc=10
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOPUT //Power Up Timer
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES NOPROTECT
#FUSES NOCPD
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOIESO
#FUSES NOFCMEN
//////////////////////////////////////////////
//////****CLOCK & RS232 CONFIGURATION****/////
//////////////////////////////////////////////
#use delay(internal=4000000)
#use rs232(baud=9600,xmit=PIN_C4,rcv=PIN_C5,parity=N,errors)
//////////////////////////////////////////////
/////////****** FILES INCLUDED ******/////////
//////////////////////////////////////////////
#include <stdlib.h>
#include <input_mod.c>
#include <string.h>
#include <stdio.h>
#include <lcdindif.c>
//////////////////////////////////////////////
///////////****I/O CONFIGURATION****//////////
//////////////////////////////////////////////
#use fast_io(ALL)
#define CONFIGA 0b00000110
#define CONFIGC 0b00100000
#bit BUZZER = 0x7.0 //Is pin C0
#bit STOLVA = 0x5.1 //Is pin A1
//////////////////////////////////////////////
/////////******** DEFINITIONS ********////////
//////////////////////////////////////////////
#define MS1 83
#define MS10 820
#define MS100 8320
//////////////////////////////////////////////
////////////***GLOBAL VARIABLES***///////////
//////////////////////////////////////////////
int1 refresca=0;
int1 alarmRPM=0,alarmCAR=0;
int8 hectarees[9];
int16 counter=0;
int16 t1r=28036;
int16 delay=0;
float proba=0;
//////////////////////////////////////////////
//////////***** INTERRUPTIONS *****///////////
//////////////////////////////////////////////
//**************** INT RDA *****************//
#int_rda
void rda_isr(void){
int8 x=0;
if(input(PIN_C5))
get_string(hectarees,9); //Save the string received
else
x=getc(); //Clear the interrupt if hasn't a character waiting to be read
}
//****************INT TIMER1****************//
#int_TIMER1
void TIMER1_isr(void) {
static int8 cont=0;
static int8 auxbuzzer;
set_timer1(t1r); //Timer reloaded every 0.3s
cont++;
if((alarmRPM==1) || ((alarmCAR==1) && (auxbuzzer<4))){
auxbuzzer++;
BUZZER=~BUZZER;
}
if((alarmCAR==0) || (auxbuzzer>=4)){
auxbuzzer=0;
}
if(cont==2){
cont=0;
counter=get_timer0(); //Read counter TMR0
set_timer0(0); //reset timer0
//counter*=(100/2); //Convert to RPM
//there are to pulses for round
counter*=50; //simplify -- to pulses for round
refresca=1;
}
}
//////////////////////////////////////////////
///////////***** MAIN PROGRAM *****///////////
//////////////////////////////////////////////
void main()
{
setup_adc(ADC_OFF);
setup_adc_ports(no_analogs);
setup_comparator(NC_NC_NC_NC);
setup_counters( T0_EXT_L_TO_H | T0_DIV_1, T0_8_BIT );
setup_oscillator(OSC_INTRC|OSC_4MHZ);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
setup_vref( VREF_HIGH );
setup_wdt(WDT_OFF);
enable_interrupts(int_timer1);
enable_interrupts(int_rda);
enable_interrupts(global);
set_timer1(t1r);
set_timer0(0);
set_tris_a(CONFIGA);
set_tris_c(CONFIGC);
output_a(0);
output_c(0);
for(delay=0;delay<MS100;delay++);
lcd_init();
lcd_clear();
while(true){
if(refresca==1){
refresca=0;
lcd_erase_line(1);
lcd_gotoxy(1,1);
printf(lcd_putc," %6lu rpm",counter);
enable_interrupts(global);
if(counter<3500)
{
alarmRPM=1;
}
else
{
alarmRPM=0;
BUZZER=0;
}
if(STOLVA==0){
alarmCAR=1;
lcd_gotoxy(1,2);
printf(lcd_putc," NIVEL MINIMO ");
enable_interrupts(global);
}
else {
alarmCAR=0;
lcd_erase_line(2);
lcd_gotoxy(1,2);
proba=strtof(hectarees,9);
printf(lcd_putc, "Hect: %9.3f" ,proba);
enable_interrupts(global);
}
}
}
}
|
Thanks for your comments and tips. |
|
|
|