TODOPIC
Microcontroladores PIC => dsPIC => Mensaje iniciado por: Nocturno en 17 de Diciembre de 2006, 04:46:57
-
Tras una nueva semana de pelea en plena arena, he conseguido implementar funciones para hacer retardos de microsegundos y milisegundos que son independientes de la velocidad con la que trabaja el micro.
Las funciones son las siguientes:
#define MIPS 50
/*********************************************/
/** Función para hacer un retardo de 1 ms **/
/** www.elrebujito.es **/
/** Nocturno - 2006 **/
/** Válida para MIPS >= 0.002 (4KHz) **/
/*********************************************/
#define delay_1ms() asm("REPEAT #%0\n NOP\n REPEAT #%0\n NOP\n REPEAT #%0\n NOP\n REPEAT #%0\n NOP" :: "i" (MIPS*250-2))
/*********************************************/
/** Función para hacer un retardo de 10 us **/
/** www.elrebujito.es **/
/** Nocturno - 2006 **/
/** Válida para MIPS >= 0.2 (400KHz) **/
/*********************************************/
#define delay_10us() asm("REPEAT #%0\n NOP" :: "i" (MIPS*10-2))
/*********************************************/
/** Función para hacer un retardo de 1 us **/
/** www.elrebujito.es **/
/** Nocturno - 2006 **/
/** Válida para MIPS>=2 (>4MHz) **/
/*********************************************/
#define delay_1us() asm("REPEAT #%0\n NOP" :: "i" (MIPS-2))
/*********************************************/
/** Función para hacer un retardo de x us **/
/** www.elrebujito.es **/
/** Nocturno - 2006 **/
/** Válida para MIPS>=16 (>32MHz) **/
/** Valores de x: de 0 a 65535 **/
/*********************************************/
void delay_us(unsigned int x) {
asm ("REPEAT #%0\n NOP" :: "i" (MIPS-16));
while ((x--)!=1) {
asm ("REPEAT #%0\n NOP" :: "i" (MIPS-7));
};
};
/*********************************************/
/** Función para hacer un retardo de x ms **/
/** www.elrebujito.es **/
/** Nocturno - 2006 **/
/** Válida para MIPS>=0.24 (>48KHz) **/
/** Valores de x: de 0 a 65535 **/
/*********************************************/
void delay_ms(unsigned int x)
{
asm ("REPEAT #%0\n NOP" :: "i" (MIPS*250-5));
asm ("REPEAT #%0\n NOP" :: "i" (MIPS*250-5));
asm ("REPEAT #%0\n NOP" :: "i" (MIPS*250-6));
asm ("REPEAT #%0\n NOP" :: "i" (MIPS*250-6));
while ((x--)!=1) {
asm ("REPEAT #%0\n NOP" :: "i" (MIPS*250-4));
asm ("REPEAT #%0\n NOP" :: "i" (MIPS*250-3));
asm ("REPEAT #%0\n NOP" :: "i" (MIPS*250-3));
asm ("REPEAT #%0\n NOP" :: "i" (MIPS*250-3));
};
}
Como véis, al final he tenido que pasar por la piedra del ASM y pese a que he refunfuñado todo lo que podía, la precisión de los delays es sorprendente; sólo se ejecutan los ciclos que tienen que ejecutarse: ni uno más y por supuesto ni uno menos.
Otra cosa que podréis observar es que hay mucho código con #define, por lo que al compilar se realizan las sustituciones correspondientes y queda un código extremadamente pequeño y compacto.
En función de la velocidad de proceso de nuestro dsPIC33F, que como sabéis puede ir a muchas frecuencias distintas hasta un máximo de 50MIPS, podréis usar algunas funciones u otras. Esto es debido a que si trabajamos a frecuencias lentas, los ciclos de instrucción necesarios para hacer los cálculos van comiéndose el tiempo del delay, hasta que llegamos a un punto que nos hemos pasado. No obstante, he dejado delante de cada función una recomendación de la velocidad mínima a emplear y los límites del parámetro x.
La principal ventaja de estos retardos es su precisión y lo poco que ocupan, pero tienen un gran inconveniente: si durante un retardo salta una interrupción y el flujo de programa se va a ejecutarla, cuando vuelva seguirá por donde iba por lo que nuestro retardo habrá aumentado todo el tiempo que duró la interrupción.
Tengo casi acabadas y espero publicarlas en breve unas rutinas para generar retardos con el Timer, lo que nos permite generar retardos que no se vean afectados por dicho efecto.
Quedo a vuestra disposición para cualquier comentario.
-
Bien, ya he probado y asegurado el código para la generación de retardos con el Timer.
Aquí os lo dejo para vuestro uso y disfrute:
#define MIPS 20
/*********************************************/
/** Función para hacer un retardo de x us **/
/** utilizando el Timer e interrumpible **/
/** generada automáticamente por asistente **/
/** www.elrebujito.es **/
/** Nocturno - 2006 **/
/** Válida para MIPS>=1 (>2MHz) **/
/** Valores de x: x*MIPS-30>0 **/
/*********************************************/
void Tdelay_us(unsigned int x) {
TMR9=-(x*MIPS-30);
T9CON = 0x8080;
while (IFS3bits.T9IF==0);
IFS3bits.T9IF=0;
};
/*********************************************/
/** Función para hacer un retardo de x ms **/
/** utilizando el Timer e interrumpible **/
/** generada automáticamente por asistente **/
/** www.elrebujito.es **/
/** Nocturno - 2006 **/
/** Válida para MIPS>=1 (>2MHz) **/
/** Valores de x: >1 **/
/*********************************************/
void Tdelay_ms(unsigned long x) {
unsigned long Limite;
Limite = x*MIPS*1000-48;
TMR8=-(Limite);
TMR9=(-Limite)>>16;
T8CON = 0x8008;
while (IFS3bits.T9IF==0);
IFS3bits.T9IF=0;
};
He aprovechado para diseñar un nuevo asistente (http://elrebujito.es/modules.php?name=Content&pa=list_pages_categories&cid=2) en El Rebujito (http://www.elrebujito.es) al que sólo hay que meter los MIPS, el método a utilizar (ciclos o Timer) y elegir el nº del timer para que nos entregue el código más adecuado a cada configuración.
Podéis ver el asistente aquí:
33F - Asistente para la generación automática de retardos (http://elrebujito.es/modules.php?name=Content&pa=showpage&pid=8)
-
Des pues de ver el resultado de su trabajo, solo queda decir. ¡Buen trabajo! Felicitaciones y gracias por compartirlo.
-
Ademas hacia falta ... se acabó contar cada vez con los dedos los nops para cada clock . :-)
-
Buenas!!!
En el mismo C30 hay una funcion " __delay32(unsigned long ciclos) " escrita en ensamblador donde tienes un delay exacto tambien....
saludos
-
Pues qué guay. De haberlo sabido antes ni toco el asm :D
-
jejejeje, no hay nada como empaparse de los foros de microchip ;)
por si a alguien le interesa y no lo encuentra esta en:
..\Microchip\MPLAB C30\src\pic30
es el archivo "delay32.s" lo incluis en el proyecto y a funcionar. Yo luego, en mi ".h" principal me creo los siguientes defines:
// External oscillator frequency with PLL enable
#define SYSCLK 8000000
#define FCY SYSCLK*4/2
// Defines para calcular los ciclos para determinados tiempos
// Se suma uno al final para asegurarnos que tenemos el tiempo minimo deseado
// en caso de que la division no fuese exacta
#define US_10 (1*FCY/100000)+1
#define US_25 (25*FCY/1000000)+1
#define US_50 (5*FCY/100000)+1
#define US_100 (1*FCY/10000)+1
#define US_250 (25*FCY/100000)+1
#define US_500 (5*FCY/10000)+1
#define MS_10 (1*FCY/100)+1
#define MS_25 (25*FCY/1000)+1
#define MS_50 (5*FCY/100)+1
#define MS_100 (1*FCY/10)+1
#define MS_250 (25*FCY/100)+1
#define MS_500 (5*FCY/10)+1
luego ya solamente hay que hacer:
__delay32( MS_500 );
-
Amigos, tras la migración de mi web se jodieron los scripts que ejecutan el asistente.
Acabo de repararlos y ya está otra vez operativo:
Asistente para la generación automática de retardos (http://www.micropic.es/index.php?option=com_content&view=article&id=33:33f-asistente-para-la-generacion-automatica-de-retardos&catid=36:asistentes&Itemid=63)