|
|
View previous topic :: View next topic |
Author |
Message |
Gabriel Caffese
Joined: 09 Oct 2003 Posts: 39 Location: LA PLATA, ARGENTINA
|
Problems with 16F88 and int_rda |
Posted: Wed Jun 23, 2004 6:56 am |
|
|
Hi everyone,
Previous data, before telling wich is the problem.
I´m using CCS 3.187
The example EX_STISR.C works ok with 16F88 (it buffers up outgoing serial data). Outgoing data is sent OK, and incoming data is received OK.
The only problem with this example, is that it does not use INT_RDA.
The program I compiled, works OK a 16F628, and it does this:
Waits until INT_RBO is activated, and sends the character "?".
Then waits 200ms, and hopes to receive ANY character.
If it receives one, then blinks an led 3 times.
Well, first time you activate INT_RB0, it works fine, but NEVER AGAIN.
Is there anything wrong in my code, that I can not see ???
I think it´s OK
Well, hope someone could help me.
Here goes the code:
#include <16F88.H>
#device *=16
#fuses XT,NOWDT,NOBROWNOUT,NOPROTECT,PUT,NOLVP,MCLR,NODEBUG
#use delay(clock=7327280)
#use rs232(baud=38400, xmit=PIN_B5,rcv=PIN_B2, ERRORS)
static char Rx[10];
static boolean rda;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////// DEFINO FUNCIONES //////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Encendido intermitente del led //
void blink_green(int veces, int duracion)
{ int i;
for (i=0;i<veces;i++)
{
output_bit(PIN_A3,1);
delay_ms(duracion);
output_bit(PIN_A3,0);
delay_ms(duracion);
}
}
// Encendido intermitente del led //
void blink_red(int veces, int duracion)
{ int i;
for (i=0;i<veces;i++)
{
output_bit(PIN_A2,1);
delay_ms(duracion);
output_bit(PIN_A2,0);
delay_ms(duracion);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////// RUTINAS DE INTERRUPCION ///////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#int_ext
void ext_isr()
{
}
#int_rda
void serial_isr()
{
rda=TRUE;
Rx[0]=getc();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////// ///////////////////////////////////////////////////
///////////////////////////////////////////////// PROGRAMA PRINCIPAL ///////////////////////////////////////////////////
///////////////////////////////////////////////// ///////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void main()
{
#ZERO_RAM
// Configuro periféricos para bajo consumo //
setup_timer_2(T2_DISABLED,0,2);
setup_ccp1(CCP_OFF);
setup_adc(ADC_OFF);
setup_vref(FALSE);
// Configuro puertos para bajo consumo //
port_b_pullups(TRUE);
// Habilito interrupciones //
ext_int_edge(H_to_L);
enable_interrupts(INT_EXT);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
// Fin de configuración //
blink_red(3,50);
blink_green(3,50);
// Habilito RS232 //
output_bit(PIN_A1,0);
output_bit(PIN_A0,1);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////// RUTINA QUE DETERMINA LA TAREA QUE DEBE REALIZARSE ////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Loop:
sleep();
///////////////////////////////////////////////////////////
if (input(PIN_B0) == FALSE)
{
do {} While (input(PIN_B0) == FALSE);
delay_ms(200);
putc('?');
delay_ms(200);
}
if (rda==TRUE) blink_green(3,10);
rda = FALSE;
///////////////////////////////////////////////////////////
goto Loop;
} |
|
|
Ttelmah Guest
|
Re: Problems with 16F88 and int_rda |
Posted: Wed Jun 23, 2004 9:37 am |
|
|
Gabriel Caffese wrote: | Hi everyone,
Previous data, before telling wich is the problem.
I´m using CCS 3.187
The example EX_STISR.C works ok with 16F88 (it buffers up outgoing serial data). Outgoing data is sent OK, and incoming data is received OK.
The only problem with this example, is that it does not use INT_RDA.
The program I compiled, works OK a 16F628, and it does this:
Waits until INT_RBO is activated, and sends the character "?".
Then waits 200ms, and hopes to receive ANY character.
If it receives one, then blinks an led 3 times.
Well, first time you activate INT_RB0, it works fine, but NEVER AGAIN.
Is there anything wrong in my code, that I can not see ???
I think it´s OK
Well, hope someone could help me.
Here goes the code:
#include <16F88.H>
#device *=16
#fuses XT,NOWDT,NOBROWNOUT,NOPROTECT,PUT,NOLVP,MCLR,NODEBUG
#use delay(clock=7327280)
#use rs232(baud=38400, xmit=PIN_B5,rcv=PIN_B2, ERRORS)
static char Rx[10];
static boolean rda;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////// DEFINO FUNCIONES //////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Encendido intermitente del led //
void blink_green(int veces, int duracion)
{ int i;
for (i=0;i<veces;i++)
{
output_bit(PIN_A3,1);
delay_ms(duracion);
output_bit(PIN_A3,0);
delay_ms(duracion);
}
}
// Encendido intermitente del led //
void blink_red(int veces, int duracion)
{ int i;
for (i=0;i<veces;i++)
{
output_bit(PIN_A2,1);
delay_ms(duracion);
output_bit(PIN_A2,0);
delay_ms(duracion);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////// RUTINAS DE INTERRUPCION ///////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#int_ext
void ext_isr()
{
}
#int_rda
void serial_isr()
{
rda=TRUE;
Rx[0]=getc();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////// ///////////////////////////////////////////////////
///////////////////////////////////////////////// PROGRAMA PRINCIPAL ///////////////////////////////////////////////////
///////////////////////////////////////////////// ///////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void main()
{
#ZERO_RAM
// Configuro periféricos para bajo consumo //
setup_timer_2(T2_DISABLED,0,2);
setup_ccp1(CCP_OFF);
setup_adc(ADC_OFF);
setup_vref(FALSE);
// Configuro puertos para bajo consumo //
port_b_pullups(TRUE);
// Habilito interrupciones //
ext_int_edge(H_to_L);
enable_interrupts(INT_EXT);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
// Fin de configuración //
blink_red(3,50);
blink_green(3,50);
// Habilito RS232 //
output_bit(PIN_A1,0);
output_bit(PIN_A0,1);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////// RUTINA QUE DETERMINA LA TAREA QUE DEBE REALIZARSE ////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Loop:
sleep();
///////////////////////////////////////////////////////////
if (input(PIN_B0) == FALSE)
{
do {} While (input(PIN_B0) == FALSE);
delay_ms(200);
putc('?');
delay_ms(200);
}
if (rda==TRUE) blink_green(3,10);
rda = FALSE;
///////////////////////////////////////////////////////////
goto Loop;
} |
What you post here, should not work.
The problem is that the processor clock stops when you enter sleep mode, so the UART, cannot wake the chip up. It _can_ wake the chip if you are running as a USART in synchronous mode (using an external clock), but not when running in async mode as a UART.
One thought, would be to join the incoming serial data line, to the INT interrupt pin. This signal can then be used to wake the chip, and the data will then follow. However even this is dangerous, because the 'start time' of the crystal oscillator will probably be enough to prevent the data being properly received. Unless you need the low power associated with sleep, or can work out a way of waking the chip in advance of the data coming (using a RS232 status line for example), I would not put the chip to sleep for this application.
Best Wishes |
|
|
Gabriel Caffese
Joined: 09 Oct 2003 Posts: 39 Location: LA PLATA, ARGENTINA
|
|
Posted: Wed Jun 23, 2004 10:21 am |
|
|
Ttelmah,
First, thanks for replying.
The process is this way. INT_RB0 (int.ext.) and INT_RDA are enabled.
When an external interrupt is generated, the PIC gets out of sleep mode, then the UART sends a character, to which the PC has to reply to (it certainly does so).
The thing is that first time the PIC receives an external interrupt, everything works fine. But next time you generate an external interrupt, the character is sent to the PC (and the PC replies with another), but 16F88 doesn't seem to detect it, cause the led doesn?t blink at all.
Any clue ?
Gabriel.- |
|
|
Joan
Joined: 29 May 2004 Posts: 41 Location: Barcelona, Spain
|
|
Posted: Wed Jun 23, 2004 4:04 pm |
|
|
Gabriel Caffese wrote: | Ttelmah,
First, thanks for replying.
The process is this way. INT_RB0 (int.ext.) and INT_RDA are enabled.
When an external interrupt is generated, the PIC gets out of sleep mode, then the UART sends a character, to wich the PC has to reply to (it certainly does so).
The thing is that first time the PIC receives an external interrupt, everything works fine. But next time you generate an external interrupt, the character is sent to the PC (and the PC replies whith another), but 16F88 doesn´t seem to detect it, cause the led doesn´t blink at all.
Any clue ?
Gabriel.- |
Hola:
has probado con rearmar la interrupción dentro de la isr correspondiente ?
( Algo así como INTF=0;)
Saludos Cordiales;
Joan _________________ I Came. I Saw. I Won. |
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Wed Jun 23, 2004 5:07 pm |
|
|
Hi Gabriel,
I will try in this way.
Code: |
#int_rda
void serial_isr()
{
rda=TRUE;
Rx[0] = 0x00;
if(kbhit) // Not to "hang" in getc()
{
Rx[0]=getc();
}
}
while(1)
{
sleep();
do
{} while(input(PIN_B0)); // Do nothing while B0 == HIGH
// The going down Start Bit must trigger the wake-up, break
// this while and hopfully catch the incoming char, not sure if
// the rigth one but in your example it doesn´t matter.
delay_ms(10); // To catch the char in background in your
// interrupt routine
if(Rx[0] != 0x00)
{
putc('?');
}
delay_ms(200);
if (rda)
{
blink_green(3,10);
rda = FALSE;
}
}
|
No time to compile and test, just the idea. HTH
Best regards,
Humberto
PD: Me voy ya a ver el partido de Boca Juniors !!!
. |
|
|
Joan
Joined: 29 May 2004 Posts: 41 Location: Barcelona, Spain
|
|
Posted: Thu Jun 24, 2004 3:42 am |
|
|
Hi:
If you have a look at the 16F88/87 Datasheet it says something like ...
Microchip wrote: | 5.2 PORTB and the TRISB Register
RB0/INT is an external interrupt input pin and is configured using the INTEDG bit (OPTION<6>).
REGISTER 2-2: OPTION REGISTER (ADDRESS 81h, 181h)
bit 6 INTEDG: Interrupt Edge Select bit
1 = Interrupt on rising edge of RB0/INT pin
0 = Interrupt on falling edge of RB0/INT pin
2.2.2.3 INTCON Register
bit 1 INTF: RB0/INT External Interrupt Flag bit
1 = The RB0/INT external interrupt occurred (must be cleared in software)
0 = The RB0/INT external interrupt did not occur
|
Best Regadrs;
Joan _________________ I Came. I Saw. I Won. |
|
|
Gabriel Caffese
Joined: 09 Oct 2003 Posts: 39 Location: LA PLATA, ARGENTINA
|
|
Posted: Thu Jun 24, 2004 8:43 am |
|
|
Humberto y Joan,
Gracias a ambos por responder. Sigo en inglés, para que el resto entienda.
The RB0 ISR, automatically clears that flags when exiting.
Now, I have found the problem -but don´t know how to solve it-
For lowering power consumption to 4uA, I have to turn off every peripheral. RS232 transmision is being done using pairs of IR Led and phototransistor on both sides.
So, I stop "feeding" both IR, and am on 100uA, then, disabling RS232 on 16F88, get those 4uA. The only thing that keeps working (and consuming) is T1, with an 32,768Khz crystal.
Then, when receiving an external interrupt, I turn on RS232 module. TX works OK, but RX does NEVER work again.
It works OK before turning off RS232, but if I disable it, and then re-enable, it will never ever work until reset.
Up to now, have no clues. Any help ??
Gabriel.- |
|
|
Ttelmah Guest
|
|
Posted: Thu Jun 24, 2004 9:52 am |
|
|
Gabriel Caffese wrote: | Humberto y Joan,
Gracias a ambos por responder. Sigo en inglés, para que el resto entienda.
The RB0 ISR, automatically clears that flags when exiting.
Now, I have found the problem -but don´t know how to solve it-
For lowering power consumption to 4uA, I have to turn off every peripheral. RS232 transmision is being done using pairs of IR Led and phototransistor on both sides.
So, I stop "feeding" both IR, and am on 100uA, then, disabling RS232 on 16F88, get those 4uA. The only thing that keeps working (and consuming) is T1, with an 32,768Khz crystal.
Then, when receiving an external interrupt, I turn on RS232 module. TX works OK, but RX does NEVER work again.
It works OK before turning off RS232, but if I disable it, and then re-enable, it will never ever work until reset.
Up to now, have no clues. Any help ??
Gabriel.- |
How are you 'turning off the RS232'?.
You should only need to toggle bit 7 of RCSTA.
I'd do something like:
#bit SPEN=0x18.7
#bit FERR=0x18.2
#bit OERR=0x18.1
#define serial_off() disable_interrupts(INT_RDA);\
disable_interrupts(INT_TDA);\
SPEN=0
#define serial_on() clear_interrupts(INT_RDA);\
clear_interrupts(INT_TDA);\
SPEN=1;\
FERR=0;\
if (OERR) getchar();\
enable_interrupts(INT_RDA);\
enable_interrupts(INT_TDA)
Remember that if you take control of the port bits to minimise power consumption, you must also set them back to the correct state.
This should be a pretty reliable way of switching the port off/on.
Best Wishes |
|
|
Gabriel Caffese
Joined: 09 Oct 2003 Posts: 39 Location: LA PLATA, ARGENTINA
|
|
Posted: Thu Jun 24, 2004 9:59 am |
|
|
Ttelmah,
I´m going out to work. I will check this tonight and
post what happened. Thank´s for this information.
Gabriel.- |
|
|
|
|
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
|