Hola altofalantes, solo decirte que no conteste antes por que realmente pienso que necesitaria explicarte desde 0 dsPIC y eso implica que sean hojas y hojas sobre algo que podrias conocer leyendo de donde ya esta escrito.
Los dsPIC y PIC24 son realmente un MUNDO aparte, ni siquiera el ASM es parecido, ya que se parece mucho mas a lo que es GCC en ASM que lo que tenias en 8 bits con MPASM.
Por otra parte sus modulos dejan de ser "sencillos" con 2 registros como maximo, pasan a ser mucho mas complejos esto lleva a que cada modulo posea un PDF explicandolo en detalle, lo bueno es que es un PDF que vale para todos los PIC24/dsPIC.
Estos se encuentra abajo en donde dice Documentacion (Reference Manual):
http://www.microchip.com/wwwproducts/en/dsPIC33EP512MU810Un lugar donde podes llegar a buscar codigos es tambien aca, vo ya suponer que es directo con XC16:
Sub-Foro dsPIC:
http://www.todopic.com.ar/foros/index.php?board=6.0En si la estructura del programa es identica a como estabas acosutmbrado en XC8, por ejemplo este codigo sobre el Timer1:
#include "xc.h"
int main(void) {
TRISB = 0x0000; // Bit B13 como salida.
T1CONbits.TON =0;
T1CONbits.TCS =0;
T1CONbits.TGATE =0;
T1CONbits.TCKPS =0b11; // Pre escaler 1:256
TMR1=0x00;
PR1=781; // Valor en el registro ( Retardo 20ms)
IPC0bits.T1IP =0x01;
IFS0bits.T1IF=0; // Borra el Flag de Interrup Timer1
IEC0bits.T1IE =1; // Habilita interrupcion Timer1
T1CONbits.TON =1; // Start Timer
while(1);
return 0;
}
void __attribute__((__interrupt__, __auto_psv__)) _T1Interrupt(void)
{
IFS0bits.T1IF = 0;
_LATB13 = ~_LATB13;
}
Unas cuantas cosas a notar aca, observaras que use _LATB13 y no LATBbits.LATB13, esto es por que aveces el MPLAB X a pesar de estar definidos no te los toma y luego te tira error, necesitando agregar el .h del dsPIC, lo cual deberia agregarse por si solo con el xc.h como lo haces en XC8.
Otra es como se definen las interrupciones, algo mas parecido a lo que se hace con GCC es decir usando el __atribute__ , el nombre de la funcion (_T1Interrupt) no es al azar, sino como cada modulo posee un vector especifico el nombre debe cumplirse, no recuerdo si esto esta en la seccion de interrupciones o en el manual de usuario de XC16.
Tambien podes usar las plib ( libreria de perifericos )
Otro ejemplo, con cambio de reloj tambien
#include "xc.h"
#include <stdint.h>
#include <stdbool.h>
#include <uart.h>
#define FCY 16000000UL
void Configuracion_Oscilador(void);
void Configuracion_Pines(void);
void Configuracion_UARTs(void);
char * utoa(char * buf, unsigned val, int base);
uint32_t contador1 = 0;
uint32_t contador2 = 0;
extern uint8_t algo;
char resultado[10];
int main(void)
{
Configuracion_Pines();
Configuracion_Oscilador();
Configuracion_UARTs();
// Deshabilito las interrupcion nesteadas
_NSTDIS = 1;
// 4 escrituras. Ya que la interrupcion se realiza cuando 3/4 lleno el buffer
WriteUART1(++contador1);
WriteUART2(++contador2);
WriteUART1(++contador1);
WriteUART2(++contador2);
WriteUART1(++contador1);
WriteUART2(++contador2);
WriteUART1(++contador1);
WriteUART2(++contador2);
while(1)
{
_LATB0 = ~ _LATB0;
__delay32(8000000);
if(algo != 0)
{
if(contador1>contador2)
{
utoa(resultado,(contador1-contador2),10);
}
else
{
utoa(resultado,(contador2-contador1),10);
}
putsUART1((unsigned int *)"Diferencia contadores:");
putsUART1((unsigned int *)resultado);
putsUART1((unsigned int *)"\n\r");
}
}
return 0;
}
void Configuracion_Oscilador(void)
{
/*
* 8Mhz cristal externo , entrada de frecuencia se cumple 0.8Mhz 8.0Mhz
* Fin * M/N1 = Fvco = 128Mhz tambien se cumple , 120 a 340 Mhz
* Fosc = Fvco / N2 = 32Mhz cumple con lo establecido, 15 a 120Mhz
* Fp = Fosc / 2 = 16Mhz
*/
PLLFBD = 30; // M = 32
_PLLPOST = 0; // N1 = 2 (default)
_PLLPRE = 1; // N2 = 4 (default)
__builtin_write_OSCCONH(0x03); // Nuevo oscilador en Oscilador Principal con PLL
__builtin_write_OSCCONL(OSCCON | 0x01); // Activo el bit para el cambio de oscilador
// Esperamos el cambio de clock, es decir cuando el oscilador actual pase a ser PRIOSC + PLL
while (_COSC != 0b011);
// Esperamos al PLL que se enganche
while (_LOCK != 1);
// No se si es necesario para hacer que la CPU realmente funcione a 1:1 con Fp
_ROI = 1;
}
void Configuracion_Pines(void)
{
_TRISB0 = 0;
_LATB0 = 0;
}
void Configuracion_UARTs(void)
{
uint16_t baudvalue;
uint16_t UMODEvalue;
uint16_t USTAvalue;
CloseUART1(); // Solo por si acaso fue un reset
CloseUART2();
/*
* Configuracion de las interrupciones, habilitadas/deshabilitadas
* y prioridades de las mismas
*/
ConfigIntUART1(UART_RX_INT_EN & UART_RX_INT_PR6 &
UART_TX_INT_DIS);
ConfigIntUART2(UART_RX_INT_EN & UART_RX_INT_PR6 &
UART_TX_INT_DIS);
/*
* Configuracion de la UART,
*
* UxMODE Register:
* UART_EN : UART habilitada
* UART_IDLE_CON : Modo de operacion continua en Idle
* UART_DIS_WAKE : Deshabilitado el Wake-Up por medio de la UART
* UART_EN_LOOPBACK: habilito el Loopback
* UART_DIS_ABAUD : Deshabilitado el Auto-Baud
* UART_NO_PAR_8bit : Sin paridad y 8 bits
* UART_1STOPBIT : 1 bit de stop
* UART_IrDA_DISABLE: Desativa la codificacion IrDA
* UART_UEN_00 : Pines RX y TX usados por el modulo, los demas ( CTS,RTS por el usuario )
* UART_BRGH_SIXTEEN : High Baud Rate Generator desactivado
* UART_MODE_SIMPLEX : Modo Simple sin control de Flujo
*
* UxSTA Register:
* UART_INT_TX_BUF_EMPTY : Interrupcion generado cuando se vacia el buffer
* UART_IrDA_POL_INV_ZERO : Idle state la salida esta en 0 (al no estar habilitado IrDA se refiere a UxTX )
* UART_TX_ENABLE : Activamos el Transmisor
* UART_INT_RX_3_4_FULL : Definimos que el flag se ponga a 1 a los 3/4 del buffer
* UART_ADR_DETECT_DIS: Deshabilitamos la deteccion de direccion ( aunque con 8 bits no funciona )
* UART_RX_OVERRUN_CLEAR : Limpiamos el bit de Overrun por si las dudas
*/
UMODEvalue = UART_EN & UART_IDLE_CON &
UART_DIS_WAKE & UART_EN_LOOPBACK &
UART_DIS_ABAUD & UART_NO_PAR_8BIT &
UART_1STOPBIT & UART_IrDA_DISABLE &
UART_UEN_00 & UART_BRGH_SIXTEEN &
UART_MODE_SIMPLEX;
USTAvalue = UART_INT_TX_BUF_EMPTY & UART_IrDA_POL_INV_ZERO &
UART_TX_ENABLE & UART_INT_RX_3_4_FUL &
UART_ADR_DETECT_DIS & UART_RX_OVERRUN_CLEAR;
/*
* Baud = 16Mhz / ( 16 * (baudvalue + 1) ) = 58523
* Error % = (58523 - 57600) / 57600 = 0.2124 %
*/
baudvalue = 16;
OpenUART1(UMODEvalue,USTAvalue,baudvalue);
OpenUART2(UMODEvalue,USTAvalue,baudvalue);
}
char * utoa(char * buf, unsigned val, int base)
{
unsigned v;
char c;
v = val;
do {
v /= base;
buf++;
} while(v != 0);
*buf-- = 0;
do {
c = val % base;
val /= base;
if(c >= 10)
c += 'A'-'0'-10;
c += '0';
*buf-- = c;
} while(val != 0);
return ++buf;
}
Aca las interrupciones y Traps:
#include "xc.h"
#include <stdint.h>
#include <stdbool.h>
#include <uart.h>
uint8_t basura;
extern uint32_t contador1;
extern uint32_t contador2;
uint8_t algo = 0;
void __attribute__((interrupt,auto_psv)) _U1RXInterrupt(void)
{
IFS0bits.U1RXIF = 0;
/* Read the receive buffer till atleast one or more character can be read */
while( DataRdyUART1())
{
basura = ReadUART1();
}
if(contador1>30000)
{
// Detenemos laSSSS UARTs y revisamos los contadores
DisableIntU1RX;
DisableIntU2RX;
algo = 1;
}
else
{
WriteUART1(++contador1);
WriteUART1(++contador1);
WriteUART1(++contador1);
}
}
void __attribute__((interrupt,auto_psv)) _U2RXInterrupt(void)
{
IFS1bits.U2RXIF = 0;
/* Read the receive buffer till atleast one or more character can be read */
while( DataRdyUART2())
{
basura = ReadUART2();
}
if(contador2>30000)
{
// Detenemos laSSSS UARTs y revisamos los contadores
DisableIntU1RX;
DisableIntU2RX;
algo = 1;
}
else
{
WriteUART2(++contador2);
WriteUART2(++contador2);
WriteUART2(++contador2);
}
}
/*
* Defaul de algunos traps del micro, por si las dudas
*/
void __attribute__((interrupt,auto_psv)) _OscillatorFail(void)
{
while(1);
}
void __attribute__((interrupt,auto_psv)) _AddressError(void)
{
while(1);
}
void __attribute__((interrupt,auto_psv)) _StackError(void)
{
while(1);
}
void __attribute__((interrupt,auto_psv)) _MathError(void)
{
while(1);
}
void __attribute__((interrupt,auto_psv)) _DMACError(void)
{
while(1);
}
En resumen hay bastante, pero aca tenes las plibs que deberian facilitarte el codigo, sino podes ir registro por registro como hacias antes.
me estoy volviendo loco para arrancar.
Tal ves la estas SOBRE pensando, comenza por lo mas basico, comenza con oscilador interno, con un programa que solo configure el TRIS de algun puerto e intenta encender un LED,
Solo necesitas:
Fuses y
#include "xc.h"
#define FCY 7370000UL
int main(void) {
TRISB = 0x0000; // Bit B13 como salida.
while(1)
{
__delay32(4000000);
_LATB0 = ~_LATB0;
}
return 0;
}
Listo tu primer programa. Es volver a aprender sobre cada modulo.
Una cosa mas, en los PIC24 / dsPIC el reloj se divide por 2 , y no por 4, eso lo vas a ver en el PDF del oscilador.
PD: No es facil, ahora no son mas 2 hojas por cada modulo, sino que son VARIAS por cada uno. Lo bueno es que te podes centrar en una cosa por ves.