Ejecución de varias rutinas a la vez en un PIC

Sí. Realmente por eso empecé a utilizar el 16F877
De todos los proyectos que traté, vi que era el que tenía mayor número de pines, pero a llegado un momento que no es suficiente.
Parece que la solución es aprender a tratar con varios micros a la vez.
Esto soluciona, tanto el desbordamiento, cómo la limitación de pines.
Es lo que he empezado a hacer.

Ahora tengo este problema:
Código:
///////////////////////MASTER///////////////////////
........................
set_tris_c(16);    // 0001 0110       // Configuración del puerto C para trabajar el spi
  setup_spi(spi_master | spi_l_to_h | spi_clk_div_16);
............................
lcd_putc("\f"); cu=1;
for (co=0;5>co;co++){
spi_write(fclee[co]); delay_ms(2000);
 lcd_gotoxy(cu,1); lcd_gotoxy(cu,1); printf(lcd_putc,"fl[%d]=%d ",co,fclee[co]);  cu+=8; 
}
   delay_ms(1000);
...................
///////////////////////ESCLAVO/////////////////////////
......................................
set_tris_c(223);///1101 1111 B3_E B4_E B5_S
setup_spi(spi_slave | spi_l_to_h | spi_clk_div_16| SPI_XMIT_L_TO_H); //);// | SPI_XMIT_L_TO_H);
...................................................
if(spi_data_is_in()){

lcd_putc("\f"); cu=1;
for (co=0;5>co;co++){//for

fclee[co]=spi_read(); 
lcd_gotoxy(cu,1); printf(lcd_putc,"fl[%d]=%d ",co,fclee[co]);  cu+=8;
}//for
delay_ms(1000);
}
Funciona, pero el problema es que tiene que ser al instante, de hecho hay más arrays y variables que el "slave" debe saber del "master".
Si quito delays no sincronizan cada LCD de su respectivo micro, muestran algo distinto.
No es fiable con delays-cortos (y a mi me convienen que ni siquiera existan)

El spi_i_data_is_in() no es suficiente o no sé utilizarlo.
He pensado utilizar un par de pines de cada micro, tipo -enviar-recibido para sincronizar bien al instante.
Pero antes buscaré y haré lo que menos me gusta, leer sobre éste protocolo.

Quizás pueda ahorrarme algo.
 
Última edición por un moderador:
Yo opino que estás haciendo las cosas mal por no conocer bien el lenguaje C.

Lo que dices de meter delays, es atorar al micro y por obvias razones no va hacer varias cosas al mismo tiempo
Es decir, el delay ejecutará sólo delay el tiempo que esté atorando, digamos, 1 segundo perdido sin hacer absolutamente NADA.

Lo ideal es que no metas delay y en modo maestro debes mandar un byte que ayude al esclavo cuando refresca la pantalla.

También, si dices que se te acaban los pines, hay maneras baratas de ampliar el bus, digamos, con un registro de corrimiento, ya sea paralelo a serie para varias entradas o un serie paralelo para varias salidas.

Esos son:
CD4021 Paralelo a serie.
74HC595 Serie a paralelo.

Obviamente se pueden manejar en cascada y obtener un bus más expandido.
 
Última edición por un moderador:
Los delays son una plaga. Siempre absolutamente siempre hay algo que hacer. Si el sistema es 'multitarea' más aún.
En su día hice un sistema con dos puertos serie, display y teclado, 26 salidas, 32 entradas todo a la vez con un micro de 1mip y no había problemas, sobraba micro. Eso si, 'delays' creo que habían cuatro o cinco de 10us no mas.
Todo lo demás se gestionaba por interrupciones; los cuatro buffers fifo de los puestos serie, el control de salidas para que fueran sincronizadas, en el bucle principal se leía el teclado tu las entradas constantemente.
El LCD que yo recuerde sólo había que esperar un poco al inicializar, después ya no, y si hay que esperar para algo se aprovecha ese tiempo para adelantar otra cosa.
 
Cierto. Un micro corriendo 32 PWM, leer un control infrarrojo, un puerto serie y leer pulsos, todo eso en un PIC16F886.

Digo, se debe tener muy buen conocimiento de programación en C.
Alguien que no sabe programar bien, hace mal uso de los recursos del CPU. En este caso, un micro.
 
Última edición por un moderador:
Si, interrupciones, eso es lo que he hecho al final lo que se me ocurrió al principio
A pesar de lo largo que es el código y no parece poder evitar los delay (lo he visto en otros proyectos)
Este código pasa valores de una forma significativa y creo que puede mejorar cuando quite los "rand() print_LCD y demás" porque sólo están para comprobar que funciona, lo único importante es que "slave lo sepa todo".
Como siempre, como no hay un problema, la lectura de una "long mony" es erronea spi_write(mony); mony=spi_read(); fallan

//Estas variables deben ser globales para los dos
//int peti,cliente,salir;
//int1 tarje;
//long mony;//////Hay un problema con "long" no se puede enviar con spi_write(mony);
//int1 fclee[5];
//int1 fcpos[5];

MASTER

PHP:
main(){
while(true){//whil

refresco();//Es importante que sea funcion porque mi proyecto debe embiar las variables actualizadas
           //para que "slave" las trabaje bastantes veces


}//whil
}


void refresco(){

nt co,cu;
output_low(PIN_c6);//S.envio incial 0
lcd_putc("\f"); cu=1;
for (co=0;5>co;co++){  //for int1
valor=rand();
if (valor>20000) { fclee[co]=1; } else { fclee[co]=0; }
lcd_gotoxy(cu,1); lcd_gotoxy(cu,1); printf(lcd_putc,"fl[%d]=%d ",co,fclee[co]);  cu+=8; //printf(lcd_putc,"fl[%d]=%d ",co,valor);
spi_write(fclee[co]); 
protMaster(); /// protocolo de envio vajo SPI MAESTRO.........*
}  //for int1
cu=1;
for (co=0;5>co;co++){ // for int1_2
valor=rand();
if (valor>20000) { fcpos[co]=1; } else { fcpos[co]=0; }
lcd_gotoxy(cu,2); printf(lcd_putc,"ps[%d]=%d ",co,fcpos[co]);  cu+=8; //printf(lcd_putc,"fl[%d]=%d ",co,valor);  
spi_write(fcpos[co]); 
protMaster(); /// protocolo de envio vajo SPI MAESTRO.........*
} //  for int1_2
    delay_ms(4000);//para mostrar principales boolean master & savle
peti=rand();
spi_write(peti); /// int peti 
protMaster();
cliente=rand();    
spi_write(cliente); /// int cliente
protMaster();
salir=rand();   
spi_write(salir); /// int salir
protMaster(); 
valor=rand();
if (valor>20000) { tarje=1; } else { tarje=0; }
spi_write(tarje); /// int1 tarje
protMaster();
mony=rand();   
spi_write(mony); /// long mony
protMaster();/// protocolo de envio vajo SPI MAESTRO.........*
lcd_putc("\f");
lcd_gotoxy(1,1); printf(lcd_putc,"INT...peti=%d cliente=%d salir=%d",peti,cliente,salir);
lcd_gotoxy(1,2); printf(lcd_putc,"int1 tarje=%d    LONG mony=%lu",tarje,mony);   
  delay_ms(4000);
 
lcd_putc("\f  envio completo");  delay_ms(500);
}
void protMaster(){/// protocolo de envio vajo SPI MAESTRO
output_high(PIN_c6); // s.envio=true afecta PIN_B7_SLAVE/E.envio
delay_ms(5);
while (Input(PIN_c0)==0) { delay_ms(5); } //Impide + envios asta SLAVE lo diga con su S.pin_a1_(S.recivido) -----> E.pin_c0_MASTER(E.recivido)
output_low(PIN_c6); // s.envio=false afecta PIN_B7_SLAVE/E.envio
delay_ms(5);
}
Esclavo/SLAVE
PHP:
main(){

while(true){//whil

if(Input(PIN_b7)) { //pin_b7=E.envio=true afectado por pin_c6_MASTER/S.envio=true 
lcd_putc("\f"); cu=1;
for (co=0;5>co;co++) {//for nt1_1
fclee[co]=spi_read();
lcd_gotoxy(cu,1); printf(lcd_putc,"fl[%d]=%d ",co,fclee[co]);  cu+=8;
protSlave();///protocolo de recivo vajo SPI SLAVE...........*
}//for nt1_1
cu=1;
for (co=0;5>co;co++){//for int1_2
fcpos[co]=spi_read();
lcd_gotoxy(cu,2); printf(lcd_putc,"fp[%d]=%d ",co,fcpos[co]);  cu+=8;     
protSlave();///protocolo de recivo vajo SPI SLAVE...........*
}//for it1_2*/

peti=spi_read();// int* peti
protSlave();///protocolo de recivo vajo SPI SLAVE
cliente=spi_read();// *cliente
protSlave();
salir=spi_read();// *salir
protSlave();
tarje=spi_read();// int1 targe 
protSlave();
mony=spi_read();// long mony lectura erronea******
protSlave();///protocolo de recivo vajo SPI SLAVE...........*
lcd_putc("\f");
lcd_gotoxy(1,1); printf(lcd_putc,"int...peti=%d cliente=%d salir=%d",peti,cliente,salir);
lcd_gotoxy(1,2); printf(lcd_putc,"int1 tarje=%d long mony=%lu",tarje,mony);///long mony siempre falla******
delay_ms(1000);
lcd_putc("\f  nuevo recivo"); 

}//whil
}
void protSlave(){///protocolo de recivo vajo SPI SLAVE
output_high(PIN_a1);//S.recivido=true -----> pin_c0_MASTER/E.recivido 
delay_ms(2);
output_low(PIN_a1); //S.recivido=false----->  pin_c0_MASTER/E.recivido
while (Input(PIN_b7)==0) { delay_ms(2); } //Se queda esperando asta qu b7=true (E.envio) afectado por pin_c6_MASTER/S.envio=true

delay_ms(2);
}
No me ha servido de mucho leer. Es cierto que no sé aprovechar los recursos ni entiendo cosas.

Por ejemplo:
setup_spi(spi_slave | spi_l_to_h | spi_clk_div_16);//| SPI_XMIT_L_TO_H);

No tengo ni idea de que significa "spi_l_to_h" Sólo sé que es una parte esencial para que todo funcione.
Si busco en google: maestro esclavo definicion-o-significado spi_l_to_h, no consigo nada concreto que me diga que funcion cumple.
Me pasa con muchas cosas, aunque tampoco tengo mucha paciencia buscando



Hay una cosa que no me gusta; "slave" siempre se retrasa, tarda más con los delays.
Me gustaría saber si esto es normal o puede ser porque empecé el proyecto eligiendo un solo micro o algo así.
Esto en esclavo me parece raro:
Código:
output_high(PIN_a1);//S.recivido=true -----> pin_c0_MASTER/E.recivido
delay_ms(2);
output_low(PIN_a1);
Funciona, pero es demasiado corto cuando master utiliza delay_ms(5)
Parece que para sincronizar el que escribe, debe ser más lento.
Aún así, noto con los mensajes y todo que slave se retrasa utilizando la misma cantidad de delays.
master/slave tienen por igual #use delay(clock=4M)
 
Última edición por un moderador:
aun sigo sin entender para que meter delays para hacer sincronia, si SPI trae su CLOCK para cada DATA

mi no ENTENDER!!!

H TO L me imagino que el clock es un flanco alto a uno de bajada y L to H es un clock bajo a uno alto

nunca he manejado SPI del CCS pero mas o menos asi es como funciona.
 
Sobrarian si los dos micros actuasen en serie. El problema es que son programas paralelos. Si pic1 uno se detiene, pic2 sigue adelante (independiente) a menos k pic1 le diga lo contrario. E visto casos similares asta con delay(10). Yo tampoco os entiendo. Darme una manera de pasar tantas variables sin delays.
 
La verdad es que de C se lo justo. En ensamblador nunca he hecho delays de más de 20 o 30us y en pocas muy pocas ocasiones.
Si el spi funciona como debe no se que pintan los delays salvo que haya montado un protocolo asíncrono sobre un bus síncrono y para eso se espere "una eternidad" porque 10ms es eso en tiempo de máquina.
Es que tenía la mala costumbre de no usar librerías de terceros, todo lo programaba desde cero.
Me parece que hace tiempo que te estoy mareando con mis teorías puristas.

En mi opinión, sea spi o sea lo que sea.
O se usa longitud de paquete fijo y entonces no se espera, cada seis bytes o los que sean es una nueva instrucción. O se usa un empaquetado variable y a cambio caracteres de control, uno de inició, uno de final, un checksum...
Lo de los delays no me gusta. Pero bueno...
 
Si, interrupciones, eso es lo que he hecho al final lo que se me ocurrió al principio

Sobrarian si los dos micros actuasen en serie. El problema es que son programas paralelos. Si pic1 uno se detiene, pic2 sigue adelante (independiente) a menos k pic1 le diga lo contrario. E visto casos similares asta con delay(10). Yo tampoco os entiendo. Darme una manera de pasar tantas variables sin delays.

Hola, he estado leyendo el tema y decido meter mi cuchara: No debería de haber problema con esto si es que usas las interrupciones que acompañan al SPI pero no las veo escritas en tu código. Vamos, sugiero que entrenes con la función SPI de C, sus interrupciones y algún simulador. Ya después encaras el proyecto con el "arma adecuada". Saludos
 
Si es cierto, puede que extrañes que no tenga if(spi_data_is_in())
Pero con mi "if(Input(PIN_b7)) { //pin_b7=E.envio"
Es similar y no tengo porque hacerle perder el tiempo preguntándolo 2 veces.

Me he salido del proyecto principal para tratar sólo SPI en un subproyecto.
Manda un montón de variables y me he dado cuenta que no necesito siempre todas, las mando en grupos y aunque le haga leer todas, muchas superior a int16, te aseguro que lo hace todo muy rápido comparado a otros proyectos que he visto.

Lo que más me interesa ahora, son los float.
Esta parece por defecto "float32", pero no me sirve el "make8" y luego hacer la conversión (master-->slave) (slave-->master), porque a mi me conviene que cualquiera de los microcontroladores pueda leer al otro en un momento dado.

Saludos.
 
Última edición por un moderador:
Si es cierto, puede que extrañes que no tenga if(spi_data_is_in())
Pero con mi "if(Input(PIN_b7)) { //pin_b7=E.envio"
Es similar y no tengo porque hacerle perder el tiempo preguntándolo 2 veces.


Saludos.

No compañero, me refiero a la interrupción del periférico por hardware, no por "polling". Será eficiente el código si es que haces uso de ella. En la hoja de datos del micro en la sección de UART vienen los registros y el procedimiento para implementar la interrupción.
Así como lo tienes malgastas tiempo de ejecución del CPU esperando a que se reciban los datos.
 
yo opino que si al compañero le funciona que ya no le mueva es como cuando uno rompe algo le hecha kolaloca y aunque todo mundo diga que es una marranada

pues ya que lo deje asi , ya cuando vea que su programa es una marranada aprendera a corregirlo
 
No encuentro en mis dataset Sea lo que sea UART Es algo que devi tratar antes En algunos casos hay un 4º pin que sincroniza todos los "clok-internos" a los demas micros Lo que acavo de ver no mustra el sectris ni el puerto. Crei que SPI era estandar de b3 a b5 pero hay graficos que muestran Utilizar c6 y c7 O pines ya ocupados Tendria que cambiar muchas cosas La marranada continua Intentare hacerlo mejor la prosimavec Aunque de momento esta hace lo que le pido
 
Universal Asynchronous Receiver-Transmitter, el micro viene preparado para sincronizar el spi por hardware y es mas facil que por software, para manejarlo por hardware ya vienen pines predefinidos y en tu caso cambiarias el diagrama cosa que es lo correcto mas en tu caso solo te queda optimizar el codigo y para la proxima como dices.
 
Es que tener spi hardware y no usarlo es tan absurdo como tener uart, interrupciones etc y no usarlos.
Se limita la aplicación y la usabilidad en un porcentaje aberrante.
Desde el principio pensé que se usaba el hard.

Hacer un máster spi por soft es fácil y no consume mucho. Hacer un esclavo puede significar que se tumbe el sistema casi por completo.
Veo mucha afición al atajo últimamente.
 
Creo que necesitas leer la AN585 A Real-Time Operating System for PICmicro™ Microcontrollers
la puedes bajar de la web. Uahuu ... 10 tareas corriendo con prioridades dadas y coperativo y en un PIC16F54 .... solo 512F y 25 de RAM con 12-io, solo TMR0 y WDT. ..... un chip de solo $0.10 US.
Clato viene en Assembler pero ...lo puedes estudiar y ver como lo implemtaron
 
Otra fuente de información es la viejita pero aun buena AN # 9: Managing Multiple Tasks
de Parallax. Ellos desarroyaron su Basic-Stamp con un PIC.


Código:
; PROGRAM: TASK.SRC
; Taken from Parallax Application Note #9: Managing Multiple Tasks
; Written     July 26, 1993
; Revised February 24, 1996 (to accomodate SPASM v4.2)
;
;Introduction. This application note presents a program in Parallax
;assembly language that demonstrates a technique for organizing a
;program into multiple tasks.
;
;Background. Like most computers, the PIC executes its instructions
;one at a time. People tend to write programs that work the same way;
;they perform one task at a time.
;It’s often useful to have the controller do more than one thing at a time,
;or at least seem to. The first step in this direction is often to exploit the
;dead time from one task—the time it would normally spend in a delay
;loop, for instance—to handle a second task. The PIC’s speed makes this
;quite practical in many cases.
;
;When several tasks must be handled at once, this approach can quickly
;become unworkable. What we need is a framework around which to
;organize the tasks. We need an operating system.
;
;The program in the listing illustrates an extremely simple operating
;system that runs each of eight small subprograms in turn. When the
;subprograms finish their work, they jump back to the system. Notice
;that this method does not require the call instruction, so it leaves the
;two-level stack free for the use of the subprograms.
;
;How it works. The circuit and program comprise an eight-LED flasher.
;Each of the LED’s flashes at a different rate. While this could be
;accomplished differently, the program is easier to understand and
;maintain because the code that controls each LED is a separate task.
;The “system” portion of the program acts like a spinning rotary switch.
;Each time it executes, it increments the task number and switches to the
;next task. It does this by taking advantage of the PIC’s ability to modify
;the program counter. Once the task number is loaded into the working
;register, the program executes the instruction jmp pc+w. The destinations
;of these jumps contain jmp instructions themselves, and send the
;program to one of the eight tasks. Not surprisingly, a list of jmp
;instructions arranged like this is called a “jump table.”
;
;Modifications. For the sake of simplicity, this task-switching program
;lacks one important attribute: fixed timing. The individual tasks are
;permitted to take as much or as little time as they require. In some real
;applications, this wouldn’t be acceptable. If the system maintains a
;master timer (like the variable ticks in this program) it should increment
;at a consistent rate.
;
;With many possible paths through the code for each task, this may seem
;like another problem. A straightforward solution is to use the PIC’s
;RTCC to time how long a particular task took, then use that number to
;set a delay to use up all of the task’s remaining time. All you need to
;know is the worst-case timing for a given task.

	include 'C:\pictools\16c54.inc'
	FUSES _XT_OSC
	FUSES _WDT_OFF
	FUSES _CP_OFF
	reset	start

LEDs		=	rb

                org     8       ;Start of available RAM

task		ds	1	; The task number used by the system.
ticks		ds	1	; Master time clock, increments once for each system cycle.
time0		ds	1	; Timer for task 0. 
time1		ds	1	; Timer for task 1. 
time2		ds	1	; Timer for task 2. 
time3		ds	1	; Timer for task 3. 
time4		ds	1	; Timer for task 4. 
time5		ds	1	; Timer for task 5. 
time6		ds	1	; Timer for task 6. 
time7		ds	1	; Timer for task 7. 

                org     0       ; Start of code space (ROM)

start		mov	!rb,#00000000b	; Set port rb to output. 
		mov	task, #7	; Set task number. 
		clr	ticks	; Clear system clock. 
		clr	LEDs	; Clear LEDs

system		inc	task	; Next task number. 
		cjne	task, #8, :cont	; No rollover? Continue. 
		clr	task	; Rollover: reset task and 
		inc	ticks	; increment the clock. 
:cont		mov	w, task	; Prepare to jump. 
		jmp	pc+w	; Jump into table, and from there
		jmp	task0	; to task #. 
		jmp	task1
		jmp	task2
		jmp	task3
		jmp	task4
		jmp	task5
		jmp	task6
		jmp	task7

task0		cjne	ticks, #255,:cont	; Every 255 ticks of system clock
		inc	time0	; increment task timer. Every 3 ticks
		cjne	time0, #3, :cont	; of task timer, toggle LED, and 
		clr	time0	; reset task timer. 
		xor	LEDs, #00000001b
:cont		jmp	system

task1		cjne	ticks, #255,:cont
		inc	time1
		cjne	time1, #8, :cont
		clr	time1
		xor	LEDs, #00000010b
:cont		jmp	system

task2		cjne	ticks, #255,:cont
		inc	time2
		cjne	time2, #6,:cont
		clr	time2
		xor	LEDs, #00000100b
:cont		jmp	system

task3		cjne	ticks, #255,:cont
		inc	time3
		cjne	time3, #11,:cont
		clr	time3
		xor	LEDs, #00001000b
:cont		jmp	system

task4		cjne	ticks, #255,:cont
		inc	time4
		cjne	time4, #12, :cont
		clr	time4
		xor	LEDs, #00010000b
:cont		jmp	system

task5		cjne	ticks, #255,:cont
		inc	time5
		cjne	time5, #4, :cont
		clr	time5
		xor	LEDs, #00100000b
:cont		jmp	system

task6		cjne	ticks, #255,:cont
		inc	time6
		cjne	time6, #23,:cont
		clr	time6
		xor	LEDs, #01000000b
:cont		jmp	system

task7		cjne	ticks, #255,:cont
		inc	time7
		cjne	time7, #9,:cont
		clr	time7
		xor	LEDs, #10000000b
:cont		jmp	system
 
Estimados:

Soy nuevo en programación de microcontroladores y estoy estudiando en una carrera relacionada

Mi consulta es, ¿se pueden generar instrucciones "Paralelas" en el código?

Les explico mi problemática:
Al programar dentro de la función principal (Main) pongo un While para verificar constantemente las entradas.
La cosa es que quiero que al apretar un pulsador se prenda un ciclo en el cual un LED parpadee y con el otro se apaga.
Aplicando mi código, funciona, pero queda en una especie de "serie" de programación.

¿Existe alguna manera de llamar una función que se ejecute en paralelo?
Ya que con el código que hice, mientras se ejecuta la secuencia de parpadeo, no le es capaz al programa leer el pulsador, una vez terminada la secuencia de parpadeo, la lee.

** PIC16f84a ó PIC16f877a **
PHP:
void main(){

   int id = 0;
   while(true){

   if(id ==1){
   output_high(pin_b1);
   delay_ms(200);
   output_low(pin_b1);
   delay_ms(200);
   }

   if (input(pin_b7)==0)
   id = 1;
   
   if (input(pin_b6)==0)
   id = 0;

   }
}
Muchas gracias, de antemano. :D
 
Atrás
Arriba