TODOPIC
Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: Rodricity en 29 de Noviembre de 2007, 14:35:17
-
Queria basicamente saber si estoy dentro de una funcion, y se podre una interrupcion, poder saltar de la
funcion inicial a una funcion que maneje las interrupciones?
Es decir, estoy haciendo x, y se produce una interrupcion, x ejemplo un pulso en RA4 (creo que produce
una interrupcion) por lo tanto deje pendiente a "x", haga lo que tenga que hacer cuando se produce la
interrupcion y vuelva al proceso de "x"
eso, creo haber estadi viendo unos ejemplos, era algo asi:
interrupt void interr()
{
if(flag de interrupcion) //o un switch en su defecto para saber "que" interrumpio.
{
manejo de interrupcion...
}
}
-
Una rutina de interrupción lo que hace es ejecutarse cuando ocurre un evento que eleve el flag de interrupción, guardando previamente la dirección donde se encontraba en la función principal.
Una vez procesada la rutina de interrupción, el programa vuelve a su función principal donde lo dejó ya que como hemos dicho guardó la dirección donde lo había dejado.
No sé si esto resuelve tu duda.
Un saludote.
-
Lo que hace cualquier sistema cuando se produce una interrupción es básicamente lo que quires hacer.
cuando se produce una IT, esta queda señalizada, de modo que una vez ejecutada la instrucción actual, lo primero que hace la unidad de control del procesador es un pooling a las interrupciones para ver si alguna está activa (pooling = encuestar las banderas de IT), si esto es así y dependiendo de cuantas IT, si hay prioridades y otros factores, la unidad de control, guarda en la pila la instrucción que debe ejecutarse a continuación y.... SALTA a la subrutina de interrupción que debe atender a la interrupción (valga la redundancia).
Una vez que se termina de atender la interrupción (para ello hay una instrucción especial, por ejemplo "RETI") la unidad de control saca de la pila el contador de programs y comienza a ajecutar la instrucción que le seguía al lugar donde te quedaste anteriormente. Y así es el proceso.
Donde está el problema, que cuando saltas a una subrrutina de IT, debes guadrar el contexto de la tarea que estabas ejecutando, y justao antes de retornar de ella, debes reestablecer el contexto Esto puede ser batante complejo y depende del procesador y otros factores, para ello los lenguajes de alto nivel suelen resolver el problema de manejar eficiente.
Veamos tu código:
interrupt void inter() es la declaración de una función para que esta se ejecute ante una IT, es decir aquí saltará tu PIC cuando se produzca una IT, como los PIC suelen tener un solo vector de IT para todas solo puede haber una subrrutina de atención de IT.
Luego haces un pooling de IT (para saber cual está activa), para ello tienes
if(flag de IT)
y si es así, puedes lógicamente llamar funciones y demás, el compilador debe generar código para que esto pueda hecerse, pero no debe haber problemas, excepto si llamas a funciones que no son reentrantes como printf, (estudia este concepto para que lo entiendas).
Al fina del interrupt void interr() el compilador mete código para reestablecer el contexto y vuelvas a X sin mucho problema.
Saludos
reinier
-
Eso era lo que queria saber, gracias reiniertl
A ver si de ahí subo el proyecto para que le echeis un ojo...
-
Solo un breve comentario sobre:
Luego haces un pooling de IT (para saber cual está activa), para ello tienes
if(flag de IT)
En CCS no es necesario preguntarle cual está activa (como sí ocurre en ensamblador), solo hace falta activar las interrupciones que se desea que se disparen en el main, con los Enables correspondientes, y luego añadir fuera del main las directivas del preprocesador de las interrupciones deseadas seguidas por las funciones de atención a la interrupción.
Cuando ocurra una interrupción el programa irá a buscar la directiva del preprocesador correspondiente y ejecutará la función asociada.
Un saludo
-
En algunas interrupciones debes hacer un reset al flag asociado a dicha interrupción ya que no se hace por hardware.
Suerte!!! ;)
-
aprovecho este post para mi pregunta que no se que pasa , se que cuando me den la respuesta me voy a dar decabezazos,pero en fin aqui pongo mi programa:
#FUSES HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=12000000)
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
#use fixed_io(a_outputs=PIN_A0)
#define led PIN_A0
char dato;
int1 flag;
#int_EXT
interrupcion_isr(){
flag=1;
}
#int_rda
secuencia(){
dato=0x00;
if(kbhit()){
dato=getc();
}
}
enter(){
printf("%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X",0x1E,0x00,0x1C,0xD1,0x00,0x07,0x00,0x01,0x00,0x03,0x00,0x01,0x60,0x00,0x72,0xD7);
}
void main()
{
enable_interrupts(global);
enable_interrupts(int_rda);
enable_interrupts(int_ext);
ext_int_edge(H_TO_L);
// TODO: USER CODE!!
set_tris_a(0xFF);
output_bit(led,0);
while(1){
if (flag==1){
flag=0;
enter();
delay_ms(1);
llamar();
}
if(dato!=0x00){ // Si es distinto de \0 ...
output_bit(led,1);
}
}
}
lo que supone que quiero que haga es que cuando detecte que hay caracteres recibiendo,se encienda el led,pero se queda enganchado (prendido), aun y cuando no le estoy enviando caracteres, con la interrupcion externa no hay problema,funciona muy bien,de hecho no creo tener ningun conflitcto entre las dos,que podria ser?,P.D. ya he intentado con else en el if de dato!=0x00, :(
-
Cuando por interrupción recibes un dato haces dato=0x00; pero luego haces dato=getc(); con lo que dato no va a ser nunca 0 y el LED se quedará siempre encendido:
if(dato!=0x00){ // Si es distinto de \0 ...
output_bit(led,1);
Un saludo
-
ok ,entendido,gracias maestros, jejeje, entendido, volvere a hacer el programa, gracias
-
aqui siguiendo dando lata,jejeje
bueno una pregunta con lo de las interrupciones rb4-7,aqui pego mi programa:
#int_rb
interrup_isr_b(){
byte change;
output_high(PIN_C0);
change=last_b^portb;
last_b=portb;
if (bit_test(change,4 )&& !bit_test(last_b,4)){
flag_rb4=1;
}
if (bit_test(change,5 )&& !bit_test(last_b,5)){
flag_rb5=1;
}
if (bit_test(change,6 )&& !bit_test(last_b,6)){
flag_rb6=1;
}
if (bit_test(change,7 )&& !bit_test(last_b,7)){
flag_rb7=1;
}
}
void main(){
enable_interrupts(int_rb);
enable_interrupts(global); // Habilito Interrupciones
enable_interrupts(int_RTCC); // habilitacion de interupcion externa
set_tris_b(0xFF);
set_tris_a(0x00);
do {
if (flag_rb4==1){
flag_rb4=0;
output_high(pin_a0);
printf("rb4");
}else{
output_low(pin_a0);
}
if (flag_rb5==1){
flag_rb5=0;
output_high(pin_a1);
printf("rb5");
}else{
output_low(pin_a1);
}
if (flag_rb6==1){
flag_rb6=0;
output_high(pin_a2);
printf("rb6");
}else{
output_low(pin_a2);
}
if (flag_rb7==1){
flag_rb7=0;
output_high(pin_a3);
printf("rb7");
}else{
output_low(pin_a3);
}
} while (TRUE);
}
cuando lo pruebo en la virtual terminal me sale los printf correctamente cada vez que realizo la interrupciones,pero nada con los leds de pruebba del puerto A,alguien me podria ayudar a decirme por que?
-
Que raro. El puerto a lo tienes bien configurado como salida con el set_tris correspondiente y luego si te hace el printf necesariamente antes te tiene que hacer el output_high.
Pón el programa completo y te lo pruebo.
Un saludo
-
#FUSES HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=12000000)
#use rs232(baud=9600,xmit=PIN_c6,rcv=PIN_c7)
#use standard_io(a)
#use standard_io(c)
#include <input.c>
#rom 0x2100={9,7,6,0x1E,0x3F}
#byte portb=6
int contRTCC=0x00;
int flag=0;
int1 enter;
int1 up;
int1 down;
int1 flag_rb4;
int1 flag_rb5;
int1 flag_rb6;
int1 flag_rb7;
int val=0;
char caracter;
char caracter1;
char dato;
int last_b;
////////////////////////
#int_rb
interrup_isr_b(){
byte change;
output_high(PIN_C0);
change=last_b^portb;
last_b=portb;
if (bit_test(change,4 )&& !bit_test(last_b,4)){
flag_rb4=1;
}else{
flag_rb4=0;
}
if (bit_test(change,5 )&& !bit_test(last_b,5)){
flag_rb5=1;
}else{
flag_rb5=0;
}
if (bit_test(change,6 )&& !bit_test(last_b,6)){
flag_rb6=1;
}else{
flag_rb6=0;
}
if (bit_test(change,7 )&& !bit_test(last_b,7)){
flag_rb7=1;
}else{
flag_rb7=0;
}
}
void main() {
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_128);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
enable_interrupts(int_rb);
enable_interrupts(global); // Habilito Interrupciones
enable_interrupts(int_RTCC); //
set_tris_b(0xFF);
set_tris_a(0x00);
set_tris_c(0xFE);
printf("probando el programa Scientist");
do {
if (flag_rb4==1){
flag_rb4=0;
output_high(pin_a0);
printf("rb4");
}else{
output_low(pin_a0);
}
if (flag_rb5==1){
flag_rb5=0;
output_high(pin_a1);
printf("rb5");
}else{
output_low(pin_a1);
}
if (flag_rb6==1){
flag_rb6=0;
output_high(pin_a2);
printf("rb6");
}else{
output_low(pin_a2);
}
if (flag_rb7==1){
flag_rb7=0;
output_high(pin_a3);
printf("rb7");
}else{
output_low(pin_a3);
}
} while (TRUE);
}
por favor no hacer caso de la rom,solo experimentaba las funciones,aqui esta el programa amigo pocher,ahora que aprendo interrupciones se me complica bastante,jejeje
-
Vale ya no es necesario, creo que lo tengo.
La primera vez que haces flag_rb4==1 sí que activas output_high(pin_a0); pero como como también haces flag_rb4==0 en la siguiente vuelta del while te va a hacer el else con lo que va a apagar a pin_a0 y lo vas a ver siempre apagado.
Un saludo
-
ok,lo checo y posteo mis resultados, quitare los flags =0 de el ciclo while
gracias pocher
-
pues no se que es amigo pocher,hice lo que me dijiste,primero quite los flags_rbx=0; de el ciclo while,y al correrlo,pues me hacian en el printf una especie de ciclo infinito hasta que activaba otra y salia esa printf, los leds si prendian pero parecian muy erraticos, despues cambie de lugar hasta lo ultimo de las operaciones if del ciclo while, ya por ultimo quite el else de la funcion de la interrupcion,no se que es :(
-
Para que no te haga el ciclo infinito en los printf mételos en la interrupción y solo los hará una vez.
Un saludo
-
Para diferenciar las entradas de interrupción RB4..RB7 yo lo haria más fácil así:
#INT_RB
interrupcionRB4_RB7()
{
if(input(PIN_B4))
flag_rb4=1;
if(input(PIN_B5))
flag_rb5=1;
etc
-
Y puestos a simplificar, incluso así:
flag_rb4=input(PIN_B4);
flag_rb5=input(PIN_B5);
...
-
bueno,perdon por responder tan tarde,pero tenia bastantes cosas que hacer; ya resolvi el problema como me lo habian planteado, quedo asi:
////////////////////////
#int_rb
interrup_isr_b(){
output_high(PIN_C0);
if(input(PIN_B4)){
flag_rb4=1;
printf("rb4");
}else{
flag_rb4=0;
}
if(input(PIN_B5)){
flag_rb5=1;
printf("rb5");
}else{
flag_rb5=0;
}
if(input(PIN_B6)){
flag_rb6=1;
printf("rb6");
}else{
flag_rb6=0;
}
if(input(PIN_B7)){
flag_rb7=1;
printf("rb7");
}else{
flag_rb7=0;
}
}
/////////////////
void main() {
enable_interrupts(int_rb);
enable_interrupts(global);
set_tris_b(0xFF);
set_tris_a(0x00);
set_tris_c(0xFE);
printf("probando el programa Scientist");
do {
if (flag_rb4==1){
output_high(pin_a0);
}else{
output_low(pin_a0);
}
if (flag_rb5==1){
output_high(pin_a1);
}else{
output_low(pin_a1);
}
if (flag_rb6==1){
output_high(pin_a2);
}else{
output_low(pin_a2);
}
if (flag_rb7==1){
output_high(pin_a3);
}else{
output_low(pin_a3);
}
} while (TRUE);
}
la verdad bastante mas facil,a como lo venia haciendo, bueno,gracias amigos,una pregunta,como es mas eficiente,asi,o como en el ejemplo que habia puesto anteriormente con la operacion xor?
-
Habría que ver cual de las dos soluciones dá lugar a un menor número de instrucciones en ensamblador. Eso se hace revisando el fichero .lst
Un saludo