Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
23Me Gusta
Pgina 1 de 6
1 2 3 4 5 > ltima
Herramientas
Calificar Tema
17/04/20
13
cosmef
ulanito
#1
[Aporte] Tutorial ARM Cortex-M3 - LPC1768
04
Fecha de
Ingreso:
octubre2009
Ubicaci
n: Bs.
As.
Mensaje
s: 2.508
- One serial interface, use CP2102 (USB to RS232 interface, support ISP
download).
- RJ45-10/100M Ethernet network interface (Ethernet PHY: LAN8720A).
- 2.8 inch TFT color LCD interface (SPI interface or 16Bit parallel interface).
- USB 2.0 interface, USB host and USB Device interface.
- TF SD / MMC card (SPI) interface.
- Two user button, One Reset button and ISP button , one INT0 button, two userprogrammable LED lights.
- Serial ISP download, Standard 20-pin JTAG download simulation debugging
interface.
- Can be choose external 5V power supply or USB 5V supply.
- Board size: 95mm * 78mm.
- Expansion all IO.
Realmente por las cosas que tiene, ms que nada los puertos Usb y
Ethernet (que todava no llegu a verlos), y el costo del mismo (casi $200
argentinos o u$d 32) creo que vale la pena para explorar estos bichos que
cada vez son ms utilizados por su bajo costo y su alta prestacin.
Yo vena de conocer los ARM7 y el cambio a esta familia realmente ni se
nota, en casi todas las cosas es muy similar y solo cambian pequeos
detalles haciendolos an ms sencillo a la hora de programar.
Esquemtico:
con lo cual voy a dejarla en este post para que puedan descargarla.
En el prximo mensaje subo el equemtico completo.
Archivos Adjuntos
UM10360 - LPC1768.pdf (4,94 MB (Megabytes), 55 visitas)
Me Gusta
Mensaje inapropiado?
Citar
17/04/2013
cosmeful
anito04
#2
Primera parte - GPIO
Fecha de
Ingreso:
octubre2009
Ubicacin:
Bs. As.
Mensajes:
2.508
Cdigo PHP:
#include <LPC17xx.H>
#define LED_1 (1<<25)
//Puerto 3.25
//Puerto 3.26
int main()
{
unsigned int cont,cont2;
LPC_PINCON->PINSEL7=0;
//Declaro al puerto 3 c
o salida
LPC_GPIO3->FIOSET=LED_1;
apagado
LPC_GPIO3->FIOCLR=LED_2;
encendido
while(1)
{
if(LPC_GPIO3->FIOPIN&LED_1)
{LPC_GPIO3->FIOCLR|=LED_1; LPC_GPIO3->FIOSET|
=LED_2;}
else
{LPC_GPIO3->FIOSET|=LED_1; LPC_GPIO3->FIOCLR|
=LED_2;}
for(cont=0;cont<1524;cont++)
for(cont2=0;cont2<65536;cont2++); //Rutina de ret
ardo bastante precaria
}
}
Registros utilizados:
Mensaje inapropiado?
21/04/201
3
cosmeful
anito04
Citar
#3
Clases de clocks
En esta familia de uC podemos encontrarnos con varios clocks distintos,
los cuales pueden ser:
- Cclk: core clock, el reloj que utilizar el ncleo del uC para ejecutar las
Fecha de
Ingreso:
octubre2009
Ubicacin:
Bs. As.
distintas instrucciones.
- Pclk: peripheral clock, el reloj que utilizarn los distintos perifricos, ej.
uart, timer, SPI, ADC, etc. Dicho reloj puede ser distinto en c/perifrico.
- Wd_clk: el reloj que utilizar el watch dog.
- Usb_clk: el reloj que utilizar el puerto USB.
Mensajes:
2.508
(100MHz/25MHz=4).
PLL0
Diagrama en bloques:
(fuera de
rango)
(fuera de
rango)
(dentro del
rango)
Llegamos a la conclusin que con un "CPU CLOCK DIVIDER" igual 3 se
consigue un FCCO dentro del rango del PLL. Por ej. un "CPU CLOCK
DIVIDER" igual 4 tambin sera vlido, pero la configuracin no sera la
ptima (como puse arriba, menor FCCO, mejor).
Resumiendo de "1-", hasta ahora sabemos que:
- CCLK=100MHz.
- "CPU CLOCK DIVIDER" igual 3.
- FCCO=300MHz.
- Frecuencia de entrada del PLL=12MHz (la frecuencia del cristal
externo).
2- Sabiendo el valor de FCCO y frecuencia de entrada, averiguamos el
valor de "M" imponiendo distintos valores de "N" hasta que el valor de
"M" sea un entero, segn la frmula que brinda la hoja de datos:
(valor no
entero, por lo tanto no es vlido)
(valor entero!)
Mensaje inapropiado?
22/04/20
13
Citar
#4
cosmef
ulanito
04
Antes de meternos con los timers, es necesario ver como funcionan las
interrupciones y como funciona el control de consumo que tiene el uC.
Interrupciones
Para el que viene de ARM7, notar que en la arquitectura Cortex el vector
Fecha de
Ingreso:
octubre-
donde uno tena que hacer una definicin del handler algo similar a C
2009
Ubicaci
n: Bs.
As.
Mensajes
: 2.508
aplicado en PC.
Si nos metemos en el captulo 6 (pg. 72), podremos ver el vector de
interrupcin y obtener ms informacin de como funciona en esta
arquitectura, por ej. configurar el nivel de prioridad que tendrn las
distintas interrupcin (0-31, siendo 0 el nivel de mayor prioridad).
Resumiendo, a nosotros lo que nos va interesar es como se crea un
handler y como habilitar las interrupciones de c/perifrico (algunos
poseen habilitacin global y propia).
Habilitacin de la interrupcin de Timer0:
Cdigo PHP:
Consumo
El uC tiene varios modos de bajo consumo:
- Sleep mode: el Cclk se detiene. Requiere de una interrupcin o Reset
para salir de ese modo.
- Deep Sleep mode: el oscilador principal se detiene al igual que el resto
de los clocks que dependen del mismo, la memoria flash entra en standby. Solo el RTC y el oscilador interno funcionan. Requiere una interrupcin
del RTC o del watch-dog (manejado por el oscilador interno) para salir de
ese modo.
- Power-down mode: funciona al igual que el Deep Sleep mode, pero
adems apaga la memoria flash y el oscilador interno. Requiere una
interrupcin del RTC para salir de ese modo.
- Deep Power-down mode: todo el integrado queda apagado salvo el RTC.
Requiere una interrupcin del RTC para salir de ese modo.
Nosotros en particular vamos a usar el Sleep mode cuando entremos en
un loop de polling, de esta forma evitamos exigir al mximo al uC y
reducimos su consumo.
Para poder entrar en este modo es necesario llamar la instruccin
assembler WFI (wait for interrupt), para lo cual usamos nuevamente una
funcin de Keil que nos permite llamar a dicha instruccin desde C:
Cdigo PHP:
__wfi();
//Sleep-Mode
Una vez que llamamos a la funcin, solo podremos salir de ella cuando se
produzca una interrupcin, de lo contrario el uC seguir en Sleep mode.
Para ms informacin de como entrar en los otros modos de bajo
Timers
Diagrama en bloques de los Timers
Modo de uso
- Base de tiempo (timer convencional que se suele usar): usando como
patrn el reloj de perifrico previamente configurado, ir contando hasta
que haya un "matcheo" establecido (en espaol sera una igualacin) y se
produzca una seal de interrupcin.
- Captura: mediante una seal conectada a un puerto capture se realiza
un conteo cuando en la seal hay una presencia de un flanco
ascendente/descendente hasta que haya un matcheo establecido y se
produzca una seal de interrupcin.
La idea es dar una breve explicacin del timer como base de tiempo por
lo que les recomiendo que luego de esta prctica y usando la hoja de
Cuenta_final_pre-escaler=25000=> mS
Para luego usar el contador como ajuste fino del tiempo en la escala
deseada.
Tengan en cuenta que incluso se pueden usar mltiples matcheos, es
decir supongamos que en 100mSeg deseamos que salte una interrupcin
a los 10mSeg, 45mSeg y 100mSeg, simplemente usando varios registros
de match que los timers poseen, podemos fijar esos tiempos y recin
resetear la cuenta cuando se alcanza los 100mSeg.
Tambin permite generar una seal fsica en los puertos match del uC
cuando se alcanza un matcheo.
Como vern la cantidad de opciones que nos permiten los timers resulta
interesante y vasta.
Registros que usaremos en cdigo:
- TCR
- TC
- PR
- PC
- MR0/1..etc (puede ser cualquiera)
- MCR
Recomiendo leer la hojas de datos en la pgina 490.
Me Gusta
Mensaje inapropiado?
24/04/
2013
Citar
#5
cosm
efula
nito0
Fecha
de
Ingre
so:
octub
re-
- defines.c
- configuracion_PLL.c
- perifericos.c
- interrupciones.c
- main.c (voy a presentar dos posibles soluciones)
- delay.c (solo utilizado en una solucin)
2009
Ubica
cin:
defines.c
Bs.
Cdigo PHP:
As.
typedef
Mensa
typedef
typedef
jes:
2.508
//Puerto 3.25
//Puerto 3.26
#define TIEMPO_CAMBIO_DE_ESTADO
10
CLK_RC_INTERNAL
#define
CLK_XTAL
#define
CLK_XTAL_RTC
0
1
2
ra el PLL0
/*
Ejemplo de Configuracin del PLL:
XTAL => PLL => FCCO => DIV1 => CCLK================> Nc
leo
|=> DIV2 => FPCLK => Per
ifricos
FCCO = (2 M FIN) / N
M = (FCCO N) / (2 FIN)
N = (2 M FIN) / FCCO
M y N se configuran en el registro PLLCFG, bits:
.0 - 14 : M (Valores posibles: 6 a 512 -> Para Cristales
de alta frecuencia)
.23 - 16 : N (Valores posibles: 1 a 32)
Se configura DIV1 mediante el registro CCLKCFG:
.0 - 255: 1 a 256
Se configura con 2 bits c/perifrico el DIV2 mediante los re
gistros PCLKSEL0/1:
.00: FCLK/4
.01: FCLK
.10: FCLK/2
.11: FCLK/8
A tener en cuenta:
- Core-Clock mxima segn la especificacin del modelo
=> M=(300MHz*2)/
(2*12MHz)=600/12=25
En el PLLCFG se debe ingresar como M-1=24 y N-1=1
*/
// Se desactiva el PLL
LPC_SC->PLL0CON=0;
LPC_SC->PLL0FEED=0xAA;
LPC_SC->PLL0FEED=0x55;
LPC_SC->PLL0CFG=((valor_n-1)<<16)+((valor_m&0x7fff)-1);
/Defino N y M
LPC_SC->PLL0FEED=0xAA;
LPC_SC->PLL0FEED=0x55;
// Se habilita el PLL
LPC_SC->PLL0CON=0x1;
LPC_SC->PLL0FEED=0xAA;
LPC_SC->PLL0FEED=0x55;
// Espera hasta que el PLL enganche a la frecuencia deseada
while(!(LPC_SC->PLL0STAT & PLOCK)) ;
// divisor CPU-Clock
#define MR0I
#define MR0R
#define MR0S
#define COUNTER_EN
#define COUNTER_R
0
1
{
LPC_SC->PCONP|=(1<<PCTIM0); //Habilito el timer0 en el contr
ol de consumo de los perifricos
/* Los timers tienen 2 contadores, 1 es el prescaler y el ot
ro es el contador en si mismo, ambos tienen registros son de 32
bits
por lo tanto por c/u puedo contar 2^32, osea como mximo
podria contar hasta 2^64*Base de tiempo ---> muchoooos das :)
El timer sera una cosa as:
Contador (Nota: Fcristal --> PLL --> Core-clock --> Divisor -->
Port-clock)
- Prescaler -> 2 registros
. TxPR: Es el valor de la cuenta final del prescale
r.
. TxPC: la cuenta del prescaler, tambin permite fi
jar desde donde comienza a contar el prescaler, cuando sea igual
a TxPR, desborda y empieza de nuevo, mandandole una cuenta al ot
ro contador
- Contador -> 4 registros
. TxTCR: Es un registro de control, si vale:
-0: el contador no cuenta.
-1: el contador cuenta.
-2: reseteo el contador.
. TxTC: la cuenta del contador, tambin permite fijar
el valor de inicio del contador.
. TxMRx: Son varios registros (segun el timer pueden s
er 4 o 3), ac se pondr el valor de la cuenta q se desea alcanz
ar con el contador, cuando TxTC sea igual se produce un evento.
Son varios porq se lo puede configurar para q envie
un evento en cuentas distintas, ej:
- TxMR0 = 34; Al llegar ac se produce un evento, pe
ro el contador sigue
- TxMR1 = 45; Al llegar ac se produce otro evento
. TxMCR: Sirve para configurar q accin tomar cuando s
e produce un evento, es de 32 bits y c/3bits se configura un MRx
distinto:
S se produce un evento en MRx y TxMCR vale:
- 001: lanza una interrupcion
- 010: se resetea el contador
- 100: se para el contador
Las 3 acciones se pueden combinar, osea interrumpir
y resetear al mismo tiempo.
*/
//------------------ Configuracin del Timer ----------------------------------------------//
LPC_TIM0->TCR=0;
//
el contador no cuenta
LPC_TIM0->TC=0;
//
el contador comienza de 0
LPC_TIM0->PR=preescaler;
// configur
//
el prescaler comienza de 0
LPC_TIM0->MR0=matcheo;
// config
uro la cuenta del MR0 tal q cuente 1000 mSeg osea 1 seg
LPC_TIM0->MCR=(1<<MR0R)|(1<<MR0I);
// configuro q al prod
// el contador em
pieza a contar
}
//--------------------------------------- TIMERS ----------------------------------------------------------------//
Vean los pasos de configuracin:
1- Habilito la alimentacin del Timer0.
2- Paro el contador.
3- Hago 0 la cuenta inicial del contador.
void habilitar_interrupciones()
{
NVIC_EnableIRQ(TIMER0_IRQn);
//Timer 0
}
//--------- Rutina de la interrupcion timer0 --------------------//
void TIMER0_IRQHandler (void)
{
flag_timer0=1;
LPC_TIM0->IR=1; // Limpio la interrupcin por match0 --> Pag
. 493
}
//--------- Rutina de la interrupcion timer0 --------------------//
Rutina de interrupcin del timer 0, fijense que es muy importante limpiar el
flag de su interrupcin. Adems una funcin de habilitacin de las
interrupciones que ahora no tiene mucho sentido, pero que a medida que
vayamos agregando perifricos se irn agregando a esa funcin.
delay.c (usado solo para la primera variante de main)
Cdigo PHP:
flag_timer0=0;
while(!flag_timer0)
__wfi();
//Sleep-Mode
//Pre-escaler 250000=>
//Sleep-Mode
#include <LPC17xx.H>
#include "defines.c"
//------- Variables globales para las interrupciones ------------//
u8 flag_timer0=0;
//------- Variables globales para las interrupciones ------------//
#include "interrupciones.c"
#include "configuracion_PLL.c"
#include "perifericos.c"
#include "delay.c"
int main()
{
configurar_pll(CLK_XTAL,25,2,3,0,0);
// Cristal de 12MHz
//Decl
//Defino al p
d apagado
LPC_GPIO3->FIOCLR=LED_2;
d encendido
habilitar_interrupciones();
while(1)
{
if(LPC_GPIO3->FIOPIN&LED_1)
{LPC_GPIO3->FIOCLR|=LED_1; LPC_GPIO3->FIOSET|
=LED_2;}
else
{LPC_GPIO3->FIOSET|=LED_1; LPC_GPIO3->FIOCLR|
=LED_2;}
delay_s(TIEMPO_CAMBIO_DE_ESTADO);
}
}
Como vern el cdigo es bastante sencillo:
1- Configuro PLL para que use un cristal externo, M=25, N=2, divisor del
Cclk=3, divisor de todos los perifricos =4.
2- Inicializo los puertos como GPIO.
3- Habilito interrupciones.
4- Entro en el While principal donde cambiar el estado de los leds, esperar
con un delay de 10 seg y repetir el proceso una y otra vez.
Que desventaja tiene este cdigo?
Durante los 10 Seg del delay el uC no puede hacer absolutamente nada, es
decir que esa funcin delay es totamente bloqueante. Para este ejercicio,
realmente mucho no importa esto, pero si por ej. tuvieramos que estar
pendientes de otro proceso, no podramos hacer absolutamente nada, recin
una vez que pasen los 10 Seg podramos hacer algo, por lo tanto esta
solucin es muy precaria.
main.c (segunda variante)
Cdigo PHP:
#include <LPC17xx.H>
#include "defines.c"
//------- Variables globales para las interrupciones ------------//
u8 flag_timer0=0;
//------- Variables globales para las interrupciones ------------//
#include "interrupciones.c"
#include "configuracion_PLL.c"
#include "perifericos.c"
int main()
{
u8 cont=TIEMPO_CAMBIO_DE_ESTADO;
configurar_pll(CLK_XTAL,25,2,3,0,0);
// Cristal de 12MHz
GPIO
LPC_GPIO3->FIODIR|=LED_2|LED_1;
//Defino al puerto co
mo salida
LPC_GPIO3->FIOSET=LED_1;
d apagado
LPC_GPIO3->FIOCLR=LED_2;
d encendido
configura_timer0(25000,1000);
__wfi();
//Sleep-Mode
if(flag_timer0)
{
flag_timer0=0;
cont--;
}
}
}
Pasos similares, pero ahora inicializo el timer0 para que genere una
interrupcin c/1 Seg.
Cuando entra al While principal pregunta si la variable "cuenta" es igual a 0,
de ser 0 cambia el estado del los leds y vuelve a la variable "cuenta" a 10,
de lo contrario sigue. Luego pregunta se se produjo o no una interrupcin
mediante el "flag_timer0", en caso afirmativo vuelve a 0 el "flag_timer0" y
resta a la variable "cuenta", de lo contrario el uC queda en sleep-mode
hasta que aparezca una nueva interrupcin.
Como vern, en esta variante, el uC esta disponible en la mayora del
tiempo y solo se necesita una interrupcin para sacarlo del sleep-mode, esto
en el prximo ejercicio resulta en una ventaja.
Para el prximo mensaje vamos a ver la interrupcin externa, pero ya
pudiendo manejar el PLL, el resto les va a resultar medianamente sencillo.
Me Gusta
Mensaje inapropiado?
30/04/2
013
cosme
Citar
#6
Si pudieron entender como configurar el PLL y los timers ya creo que estn
fulanit
o04
Fecha
de
- Averiguar como se debe configurar el PIN para que trabaje como EXT"x",
registros PINSEL"x".
Ingreso
:
octubre
-2009
Ubicaci
n: Bs.
As.
Mensaj
es:
2.508
#define TIEMPO_TOGGLE_INICIAL
// el contador comienza de 0
// el prescaler comienza de 0
por match0
LPC_TIM1->TCR=(1<<COUNTER_EN); // el contador empieza a
contar
}
#define EXT1_MODO_FLANCO
(1<<1)
#define EXT1_POL_NEG
#define EXT1_POL_POS
(1<<1)
(1<<22)
(1<<11)
#define EXT2_MODO_FLANCO
(1<<2)
#define EXT2_POL_NEG
#define EXT2_POL_POS
(1<<2)
(1<<24)
(1<<12)
//Timer0
NVIC_EnableIRQ(TIMER1_IRQn);
//Timer1
NVIC_EnableIRQ(EINT1_IRQn);
//Externa 1
NVIC_EnableIRQ(EINT2_IRQn);
//Externa 2
}
//Rutina Timer0 => ver mensaje anterior
a 1
}
//--------- Rutina de la interrupcion externa 1 --------------------//
//--------- Rutina de la interrupcion externa 2 --------------------//
void EINT2_IRQHandler (void)
{
flag_ext2=1;
LPC_SC->EXTINT|=(1<<2);
a 2
}
//--------- Rutina de la interrupcion externa 2 --------------------//
main.c (solucin usando delays)
Cdigo PHP:
#include <LPC17xx.H>
#include "defines.c"
//------- Variables globales para las interrupciones ------------//
u8 flag_timer0=0,flag_timer1=0,flag_ext1=0,flag_ext2=0;
//------- Variables globales para las interrupciones ------------//
#include "interrupciones.c"
#include "configuracion_PLL.c"
#include "perifericos.c"
int main()
{
u16 cont=TIEMPO_TOGGLE_INICIAL;
u8 tiempo_inicial_variable=1;
configurar_pll();// Cristal de 12MHz => CPU-CLK=100MHz y PCLK=25MHz
LPC_PINCON->PINSEL7=0;
//Declaro al puerto 3 como GPIO
LPC_GPIO3->FIODIR|=LED_2|LED_1;
//Defino al puerto como salida
LPC_GPIO3->FIOSET=LED_1;
pagado
LPC_GPIO3->FIOCLR=LED_2;
ncendido
configura_timer0(25000,1000);
//E
configurar_externa_2(EXT2_MODO_FLANCO,EXT2_POL_NEG);
//Ext
if(LPC_GPIO3->FIOPIN&LED_1)
{LPC_GPIO3->FIOCLR|=LED_1; LPC_GPIO3->FIOSET|
=LED_2;}
else
{LPC_GPIO3->FIOSET|=LED_1; LPC_GPIO3->FIOCLR|
=LED_2;}
}
__wfi();
//Sleep-Mode
if(flag_timer0)
{
flag_timer0=0;
cont--;
}
if(flag_ext1)
{
flag_ext1=0;
configura_timer1(25000,200);
//Pre-escaler 25000
flag_timer1=0;
LPC_TIM1->TCR=0; // paro el contador
if(tiempo_inicial_variable>1)
tiempo_inicial_variable--;
}
if(flag_ext2)
{
flag_ext2=0;
configura_timer1(25000,200);
//Pre-escaler 25000
flag_timer1=0;
LPC_TIM1->TCR=0; // paro el contador
tiempo_inicial_variable++;
}
}
}
Inconvenientes de esta solucin:
- Durante 200mSeg tenemos al uC bloqueado en sleep-mode.
- No hay verificacin alguna de que el pulsador realmente se presion y de
que no hubo ruido de por medio.
Para plantear la 2da solucin hay que entender que un rebote tiene esta
forma:
// el contador comienza de 0
// el prescaler comienza de 0
0
1
#define ANTI_REB_5MSEG
#define ANTI_REB_10MSEG
#define ANTI_REB_300MSEG
3
4
{
configura_timer1(25000,5);
//Pre-escaler
//
//Habilito EXT1
flag_ext1=0;
//Rebote detectado
}
break;
}
case ANTI_REB_10MSEG:
{
if(flag_timer1)
{
//
Vuelv
flag_timer1=0;
if(!(LPC_GPIO2->FIOPIN&PIN_EXT1))
//
ado
return 1;
//Pulsacin confirmada
}
else
{
LPC_TIM1->TCR=0; // Paro el con
tador
*variable_estado=ANTI_REB_IDLE;
// Vuelvo al 1er estado
LPC_PINCON->PINSEL4|
=PINSEL_EXT1;
//Habilito EXT1
flag_ext1=0;
//
Vuelv
//Rebote detectado
}
break;
}
case ANTI_REB_300MSEG:
{
if(flag_timer1)
{
flag_timer1=0;
if(!(LPC_GPIO2->FIOPIN&PIN_EXT1))
//
r botn apretado
else
{
LPC_TIM1->TCR=0; // Paro el con
tador
*variable_estado=ANTI_REB_IDLE;
// Vuelvo al 1er estado
LPC_PINCON->PINSEL4|
=PINSEL_EXT1;
//Habilito EXT1
flag_ext1=0;
//
Vuelv
//Pulsador liberado
}
break;
}
}
return -1;
}
int anti_rebote_ext2(u8* variable_estado)
endente
{
switch(*variable_estado)
{
case ANTI_REB_IDLE:
{
configura_timer2(25000,5);
//Pre-escaler
if(flag_timer2)
{
flag_timer2=0;
if(!(LPC_GPIO2->FIOPIN&PIN_EXT2))
//
// Habilito EXT2
flag_ext2=0;
//
Vuelv
//Rebote detectado
}
break;
}
case ANTI_REB_10MSEG:
{
if(flag_timer2)
{
flag_timer2=0;
if(!(LPC_GPIO2->FIOPIN&PIN_EXT2))
//
ado
return 1;
//Pulsacin confirmada
}
else
{
LPC_TIM2->TCR=0; // Paro el con
tador
*variable_estado=ANTI_REB_IDLE;
// Vuelvo al 1er estado
LPC_PINCON->PINSEL4|
=PINSEL_EXT2;
// Habilito EXT2
flag_ext2=0;
//
Vuelv
//Rebote detectado
}
break;
}
case ANTI_REB_300MSEG:
{
if(flag_timer2)
{
flag_timer2=0;
if(!(LPC_GPIO2->FIOPIN&PIN_EXT2))
//
// Habilito EXT2
flag_ext2=0;
//
pcin
}
//Pulsador liberado
}
break;
}
}
return -1;
}
//--------------------------------------- EXTERNAS ----------------------------------------------------------------//
Estas rutinas irn efectuando el proceso de anti-rebote descrito
anteriormente y cuando se confirme una pulsacin devolver 1. Es
importante ver tres cosas:
- Necesita usar una variable por referencia (el que no sabe que es esto, le
recomiendo leer algo de C y sobre ese tema, pero bsicamente sirve para
evitar el uso de variables globales).
- No es bloqueante, como ya lo veremos en el main, es una funcin que
devuelve de inmediato el estado en el que est la rutina de anti-rebote.
- Una vez que el botn deja de ser presionado, se vuelve a configurar el
puerto como EXT"x" (en la rutina de interrupcin veremos que se
deshabilita).
Este tipo de funciones est realizado en base a una mquina de estado
bastante simple, ya que se adapta perfecto al procedimiento de antirebote.
interrupciones.c (se agrega y modifica a lo anterior)
Cdigo PHP:
void habilitar_interrupciones()
{
NVIC_EnableIRQ(TIMER0_IRQn);
//Timer0
NVIC_EnableIRQ(TIMER1_IRQn);
//Timer1
NVIC_EnableIRQ(TIMER2_IRQn);
//Timer1
NVIC_EnableIRQ(EINT1_IRQn);
//Externa 1
NVIC_EnableIRQ(EINT2_IRQn);
//Externa 2
}
//Rutinas de Timer0/1 ya vistas
//--------- Rutina de la interrupcion timer2 --------------------//
void TIMER2_IRQHandler (void)
{
flag_timer2=1;
LPC_TIM2->IR=1; // Limpio la interrupcin por match0 --> Pa
g. 493
}
//--------- Rutina de la interrupcion timer2 --------------------//
//--------- Rutina de la interrupcion externa 1 --------------------//
void EINT1_IRQHandler (void)
{
flag_ext1=1;
LPC_PINCON->PINSEL4&=~((3<<22));
//Vuelvo a configurar c
a 1
}
//--------- Rutina de la interrupcion externa 1 --------------------//
//--------- Rutina de la interrupcion externa 2 --------------------//
void EINT2_IRQHandler (void)
{
flag_ext2=1;
LPC_PINCON->PINSEL4&=~((3<<24));
//Vuelvo a configurar c
a 2
}
//--------- Rutina de la interrupcion externa 2 --------------------//
Dentro de lo ms destacado, vean que en la rutina EXT1/2 se deshabilita
dicho puerto para que trabaje como EXT y que lo haga como GPIO.
Por qu esto? debido a que es necesario saber el estado del PIN durante
la rutina de anti-rebote y para eso utilizaremos el registro FIOPIN que
pertenece a los GPIO, esto ltimo por ej. lo pueden ver en la linea de la
rutina "if(!(LPC_GPIO2->FIOPIN&PIN_EXT1))".
main.c (solucin usando rutina anti-rebote)
Cdigo PHP:
#include <LPC17xx.H>
#include "defines.c"
//------- Variables globales para las interrupciones ------------//
u8 flag_timer0=0,flag_timer1=0,flag_timer2=0,flag_ext1=0,flag_e
xt2=0;
//------- Variables globales para las interrupciones ------------//
#include "interrupciones.c"
#include "configuracion_PLL.c"
#include "perifericos.c"
int main()
{
u16 cont=TIEMPO_TOGGLE_INICIAL;
u8 tiempo_inicial_variable=1,estado_anti_reb_ext1=ANTI_REB_
IDLE,estado_anti_reb_ext2=ANTI_REB_IDLE;
configurar_pll();// Cristal de 12MHz => CPU-CLK=100MHz y PCLK=25MHz
LPC_PINCON->PINSEL7=0;
//Declaro al puerto 3 como GPIO
LPC_GPIO3->FIODIR|=LED_2|LED_1;
//Defino al puerto como salida
LPC_GPIO3->FIOSET=LED_1;
pagado
LPC_GPIO3->FIOCLR=LED_2;
ncendido
configura_timer0(25000,1000);
//E
//Ext
if(LPC_GPIO3->FIOPIN&LED_1)
{LPC_GPIO3->FIOCLR|=LED_1; LPC_GPIO3->FIOSET|
=LED_2;}
else
{LPC_GPIO3->FIOSET|=LED_1; LPC_GPIO3->FIOCLR|
=LED_2;}
}
__wfi();
//Sleep-Mode
if(flag_timer0)
{
flag_timer0=0;
cont--;
}
if(flag_ext1)
{
if(anti_rebote_ext1(&estado_anti_reb_ext1)>0)
{
if(tiempo_inicial_variable>1)
tiempo_inicial_variable--;
}
}
if(flag_ext2)
{
if(anti_rebote_ext2(&estado_anti_reb_ext2)>0)
tiempo_inicial_variable++;
}
}
}
Como pueden ver las grandes ventajas de esta solucin son:
- No es bloqueante (no tengo que esperar 200mSeg para recuperar el
control del uC).
- Posee doble verificacin en 5mSeg y 10mSeg.
- Se puede mantener apretado el pulsador y c/300mSeg se tomar como
vlida una nueva pulsacin (el tiempo puede modificarse, en vez de
300mSeg podran ser 1Seg).
Mensaje inapropiado?
06/05/201
3
cosmefu
lanito04
Citar
#7
Diagrama en bloques:
Fecha de
Ingreso:
octubre2009
Ubicacin:
Bs. As.
Mensajes:
2.508
Procedimiento de inicializacin:
1- Habilitar alimentacin de la Uartx (registro PCONP).
2- Configurar el pre-escaler de la Uartx (registro PCLKSEL0/1).
3- Configurar el baud rate mediante el Divisor Latch (registros DLL/M).
Para modificar el valor del Divisor Latch es necesario que el bit Dlab
del registro LCR se encuentre en 1.
4- Luego de configurar el baud rate, dejar en 0 el bit Dlab.
5- Habilitar o no el FIFO para utilizar DMA (opcional).
6- Configurar los Pines para que funcionen como Uartx (registro
PINSELx) y que funcionen como Pull-up (registro PINMODEx).
7- Habilitar la interrupcin por Rx y Tx (registro IER).
8- Configurar el DMA (opcional).
Baud Rate:
23
{
LPC_SC->PCONP|=(1<<PCTIM3); //Habilito el timer3 en el co
ntrol de consumo de los perifricos
//------------------ Configuracin del Timer ----------------------------------------------//
LPC_TIM3->TCR=0; // el contador no cuenta
LPC_TIM3->TC=0;
// el contador comienza de 0
// el prescaler comienza de 0
3
(1<<7)
(1<<1)
#define UART_RXI
(1<<0)
#define UART_RLSI
(1<<2)
14
#define UART_57600
27
#define UART_38400
41
#define UART_19200
81
#define UART_9600
163
#define UART_4800
325
#define UART_2400
651
#define UART_1200
1302
(1<<4)
(1<<6)
//Velocid
ad (baudios)=PCLK/[16*256*DivisorLatch*(1+DivAddVal/MulVal)]
{
LPC_SC->PCONP|=(1<<3); //Habilito la uart0 en el control
de consumo de los perifricos
LPC_PINCON->PINSEL0&=~((3<<6)|(3<<4));
LPC_PINCON->PINSEL0|=PINSEL_RX_UART0|PINSEL_TX_UART0;
//Pines del puerto serie funcionando como tal
LPC_PINCON->PINMODE0&=~((3<<6)|(3<<4));
//Pines con Pull-up interno
LPC_UART0->LCR=UART_DLAB_1|UART_DATA_8_BIT;
//8bit
/Parte baja
LPC_UART0->DLM=(divisor_latch>>8)&0xff;
//Par
te alta
LPC_UART0->LCR=UART_DATA_8_BIT;
//8bits de datos, 1 bit de stop, sin paridad, DLAB=0.
LPC_UART0->IER=UART_THREI|UART_RXI;
//Habilito interrupcin por Rx y Tx
}
int recibe_dato_uart0()
{
configura_timer3(25000,33);
//Espera a ten
//Sleep-Mode
if(flag_uart0_rx)
{
flag_uart0_rx=0;
LPC_TIM3->TCR=0; // paro el contador
flag_timer3=0;
return 1;
}
LPC_TIM3->TCR=0; // paro el contador
flag_timer3=0;
return -1;
}
int envia_dato_uart0(u8 dato)
{
configura_timer3(25000,33);
//Espera a ten
//Sleep-Mode
if(flag_uart0_tx)
{
LPC_UART0->THR=dato;
flag_uart0_tx=0;
LPC_TIM3->TCR=0; // paro el contador
flag_timer3=0;
return 1;
}
LPC_TIM3->TCR=0; // paro el contador
flag_timer3=0;
return -1;
}
//--------------------------------------- UARTS -------------------------------------------------------------------//
Se agreg:
- Inicializacin del Timer 3, usado como time-out para la funciones de
envo y recepcin.
- Inicializacin de la Uart0.
- Funcin bloqueante envia_dato_uart0 con un time-out de 33mSeg.
Espera hasta 33mSeg que el puerto serie est disponible para enviar
datos.
- Funcin bloqueante recibe_dato_uart0() con un time-out de 33mSeg.
Espera hasta 33mSeg que el puerto serie reciba un dato (esta ltima
funcin no ser utilizada).
interrupciones.c (se agrega a lo anterior)
Cdigo PHP:
void habilitar_interrupciones()
{
NVIC_EnableIRQ(TIMER0_IRQn);
//Timer0
NVIC_EnableIRQ(TIMER1_IRQn);
//Timer1
NVIC_EnableIRQ(TIMER2_IRQn);
//Timer2
NVIC_EnableIRQ(TIMER3_IRQn);
//Timer3
NVIC_EnableIRQ(EINT1_IRQn);
//Externa 1
NVIC_EnableIRQ(EINT2_IRQn);
//Externa 2
NVIC_EnableIRQ(UART0_IRQn);
//UART 0
}
//... Rutinas ya vistas
//--------- Rutina de la interrupcion timer3 --------------------//
void TIMER3_IRQHandler (void)
{
flag_timer3=1;
LPC_TIM3->IR=1; // Limpio la interrupcin por match0 -->
Pag. 493
}
//--------- Rutina de la interrupcion timer3 --------------------//
//--------- Rutina de la interrupcion Uart 0 --------------------//
#define UART_INT_TX
(1<<6)
#define UART_INT_RX
(1<<0)
//Limpiez
a del la interrupcin
if((LPC_UART0->LSR)&(UART_INT_RX))
//Pregunto la fuent
e de interrupcin => Rx o Tx
{
flag_uart0_rx=1;
dato_uart0=(u8)(LPC_UART0->RBR);
//Recibo el dato
}
else
{
flag_uart0_tx=1;
}
}
//--------- Rutina de la interrupcion Uart 0 ----------------
-----//
Lo ms destacado de la rutina de la uart es:
- La necesidad de limpiar el flag de interrupcin mediante una lectura
falsa al registro IIR.
- Averiguar la fuente de interrupcin, si es debido a que el Tx se
encuentra vaco o que se recibi un dato. Para lo cual se utiliza el
registro de estado LSR.
funciones_uart.c
Cdigo PHP:
digitos[0]=dato+0x30;
}
void enviar_string_uart0(u8 string[])
{
u8 cont=0;
do{
envia_dato_uart0(string[cont]);
cont++;
if(cont==0xff)
break;
}while(string[cont-1]!=fin_de_linea);
}
u8 envia_u8_string_uart0(u8 dato)
do en un string de 3 bytes
envia_dato_uart0(digitos[1]);
envia_dato_uart0(digitos[2]);
return (digitos[2]+digitos[1]+digitos[0]);
}
u8 envia_u16_string_uart0(u16 dato)
envia_dato_uart0(digitos[0]);
o en un string de 5 bytes
envia_dato_uart0(digitos[1]);
envia_dato_uart0(digitos[2]);
envia_dato_uart0(digitos[3]);
envia_dato_uart0(digitos[4]);
return (digitos[4]+digitos[3]+digitos[2]+digitos[1]+digit
os[0]);
}
Para poder trabajar con facilidad el puerto serie, se propone las
siguientes funciones:
- enviar_string_uart0: simplemente manda un string por puerto serie,
requiere el fin de linea '\n'.
- envia_u8_string_uart0: convierte un dato unsigned char en un string
(3 dgitos mx) y lo enva.
- envia_u16_string_uart0: convierte un dato unsigned int en un string (5
dgitos mx) y lo enva.
main.c
Cdigo PHP:
#include <LPC17xx.H>
#include "defines.c"
//------- Variables globales para las interrupciones ------------//
u8 flag_timer0=0,flag_timer1=0,flag_timer2=0,flag_timer3=0,fl
ag_ext1=0,flag_ext2=0,flag_uart0_rx=0,flag_uart0_tx=1,dato_ua
rt0;
//------- Variables globales para las interrupciones ------------//
#include "interrupciones.c"
#include "configuracion_PLL.c"
#include "perifericos.c"
#include "funciones_uart.c"
int main()
{
u16 cont=TIEMPO_TOGGLE_INICIAL;
u8 tiempo_inicial_variable=1,estado_anti_reb_ext1=ANTI_RE
B_IDLE,estado_anti_reb_ext2=ANTI_REB_IDLE,flag_ascendente=0;
configurar_pll(CLK_XTAL,25,2,3,0,0);
// Cristal de 12M
apagado
LPC_GPIO3->FIOCLR=LED_2;
encendido
configura_timer0(25000,1000);
//E
configurar_uart0(UART_9600); //9600bps
habilitar_interrupciones();
while(1)
{
if(!flag_ascendente)
{
if(cont==1)
{
cont=tiempo_inicial_variable*TIEMPO_TOGGLE_IN
ICIAL;
if(LPC_GPIO3->FIOPIN&LED_1)
{LPC_GPIO3->FIOCLR|=LED_1; LPC_GPIO3>FIOSET|=LED_2;}
else
{LPC_GPIO3->FIOSET|=LED_1; LPC_GPIO3>FIOCLR|=LED_2;}
}
}
else
{
if(cont==(tiempo_inicial_variable*TIEMPO_TOGGLE_I
NICIAL)-1)
{
cont=0;
if(LPC_GPIO3->FIOPIN&LED_1)
{LPC_GPIO3->FIOCLR|=LED_1; LPC_GPIO3>FIOSET|=LED_2;}
else
{LPC_GPIO3->FIOSET|=LED_1; LPC_GPIO3>FIOCLR|=LED_2;}
}
}
__wfi();
//Sleep-Mode
if(flag_timer0)
{
flag_timer0=0;
if(!flag_ascendente)
cont--;
else
cont++;
enviar_string_uart0("Contador= \n");
envia_u16_string_uart0(cont);
enviar_string_uart0(" \n");
}
if(flag_ext1)
{
if(anti_rebote_ext1(&estado_anti_reb_ext1)>0)
{
if(tiempo_inicial_variable>1)
tiempo_inicial_variable--;
}
}
if(flag_ext2)
{
if(anti_rebote_ext2(&estado_anti_reb_ext2)>0)
tiempo_inicial_variable++;
}
if(flag_uart0_rx)
{
flag_uart0_rx=0;
if(dato_uart0=='a')
flag_ascendente=1;
//Cuenta Ascendente
if(dato_uart0=='d')
flag_ascendente=0;
}
}
}
//Cuenta descendente
Me Gusta
Mensaje inapropiado?
12/05/2
013
cosme
fulanit
Citar
#8
Diagramas en bloques:
o04
- Alimentacin y oscilador
Fecha
de
Ingreso
:
octubre
-2009
Ubicaci
n: Bs.
As.
Mensaje
s:
2.508
configurada.
- Contadores y alarmas internas
Procedimiento de inicializacin:
1- Habilitar alimentacin del RTC (registro PCONP).
2- Resetear cuenta y deshabilitar conteo (registro CCR).
3- Configurar hora inicial (registros SEC, MIN, HOUR. etc).
4- Habilitar conteo (registro CCR).
5- Configurar hora de alarma (registros ALSEC, ALMIN,. etc) [Opcional].
6- Realizar ajuste de calibracin (registro CALIBRATION) y habilitar
calibracin (registro CCR) [Opcional].
7- Habilitar interrupcin por conteo (registro CIIR) o por alarma (registro
AMR).
Procedimiento de calibracin (Opcional):
Mediante el pin 1.27 configurado en CLKOUT (registro PINSELx), se mide
el desajuste del oscilador del RTC en 1 seg usando un osciloscopio. Se
utiliza dicho valor en los bits CALVAL (registro CALIBRATION).
Almacenamiento de informacin (Opcional):
El RTC nos da la opcin de almacenar en 5 registros de 32 bits
(GPREG0/1/4), cualquier informacin que nos pueda ser de utilidad, de
forma tal que si operamos sin fuente de alimentacin, dicha informacin
seguir estando presente gracias a la batera de litio que utiliza el RTC
para no perder la hora.
Luego de hacer un brevsimo resumen (se recomienda profundizar el tema
con la hoja de datos, Chapter 27: LPC17xx Real-Time Clock (RTC) and
backup registers), seguimos con el cdigo.
Ejercicio parte 1:
Del ejercicio realizado anteriormente con la UART, se pide generar la base
de tiempo de 1 seg mediante el uso del RTC (en ejercicios anteriores
usamos el timer0 como base de tiempo).
defines.c => no hay modificaciones.
configuracion_PLL.c => no hay modificaciones.
funciones_uart.c => no hay modificaciones.
perifericos.c (se agrega a lo anterior)
Cdigo PHP:
12
#define CLKEN
#define CTCRST
#define CCALEN
#define RTC_SEG
#define RTC_MIN
#define RTC_HOR
#define RTC_DIA_MES
#define RTC_DIA_SEMANA
#define RTC_DIA_ANIO
4
5
#define RTC_MES
#define RTC_ANIO
#define RTC_TAMANIO
{
LPC_RTC->ALSEC=vector_alarma[RTC_SEG];
//Car
go vector alarma
LPC_RTC->ALMIN=vector_alarma[RTC_MIN];
LPC_RTC->ALHOUR=vector_alarma[RTC_HOR];
LPC_RTC->ALDOM=vector_alarma[RTC_DIA_MES];
LPC_RTC->ALDOW=vector_alarma[RTC_DIA_SEMANA];
LPC_RTC->ALDOY=vector_alarma[RTC_DIA_ANIO];
LPC_RTC->ALMON=vector_alarma[RTC_MES];
LPC_RTC->ALYEAR=vector_alarma[RTC_ANIO];
}
void habilitar_interrupciones_rtc(u8 int_conteo,u8 int_alarma)
{
LPC_RTC->CIIR=int_conteo;
LPC_RTC->AMR=int_alarma;
}
void calibrar_rtc(u16 ajuste_conteo,u8 dir_correccion)
{
LPC_RTC->CALIBRATION=(1&(dir_correccion<<17))|
ajuste_conteo;
LPC_RTC->CCR&=~(1<<CCALEN);
//Habilito la calibracin y
datos_rtc[1]=LPC_RTC->GPREG1;
datos_rtc[2]=LPC_RTC->GPREG2;
datos_rtc[3]=LPC_RTC->GPREG3;
datos_rtc[4]=LPC_RTC->GPREG4;
}
void leer_hora_rtc(u16 vector_hora[])
{
vector_hora[RTC_SEG]=LPC_RTC->SEC;
vector_hora[RTC_MIN]=LPC_RTC->MIN;
vector_hora[RTC_HOR]=LPC_RTC->HOUR;
vector_hora[RTC_DIA_MES]=LPC_RTC->DOM;
vector_hora[RTC_DIA_SEMANA]=LPC_RTC->DOW;
vector_hora[RTC_DIA_ANIO]=LPC_RTC->DOY;
vector_hora[RTC_MES]=LPC_RTC->MONTH;
vector_hora[RTC_ANIO]=LPC_RTC->YEAR;
}
//--------------------------------------- RTC ---------------------------------------------------------------------//
Se pueden encontrar las siguientes funciones:
- Inicializacin y arranque del RTC.
- Configuracin de la hora de alarma.
- Habilitacin de interrupcin, por conteo o por alarma.
- Funcin de calibracin, agregar el offset medido, ya sea positivo o
negativo.
- Almacenamiento y lectura de los registros generales de almacenamiento
de informacin.
- Lectura de la hora actual del RTC.
Para la funciones se podra haber usado alguna estructura en vez de un
vector, el inconveniente que le encuentro a eso, es que en un futuro la
estructura no permitir una configuracin rpida como un vector con una
rutina FOR.
interrupciones.c (se agrega y modifica a lo anterior)
Cdigo PHP:
void habilitar_interrupciones()
{
NVIC_EnableIRQ(TIMER0_IRQn);
//Timer0
NVIC_EnableIRQ(TIMER1_IRQn);
//Timer1
NVIC_EnableIRQ(TIMER2_IRQn);
//Timer2
NVIC_EnableIRQ(TIMER3_IRQn);
//Timer3
NVIC_EnableIRQ(EINT1_IRQn);
//Externa 1
NVIC_EnableIRQ(EINT2_IRQn);
//Externa 2
NVIC_EnableIRQ(UART0_IRQn);
//UART 0
NVIC_EnableIRQ(RTC_IRQn);
//RTC
}
//... Todos los handlers vistos anteriormente
//--------- Rutina de la interrupcion RTC --------------------//
#define RTCCIF
#define RTCALF
//Limpio las
interrupciones
}
//--------- Rutina de la interrupcion RTC --------------------//
main.c
Cdigo PHP:
#include <LPC17xx.H>
#include "defines.c"
//------- Variables globales para las interrupciones ------------//
u8 flag_timer0=0,flag_timer1=0,flag_timer2=0,flag_timer3=0,flag
_ext1=0,flag_ext2=0,flag_uart0_rx=0,flag_uart0_tx=1,dato_uart0,
flag_rtc=0;
//------- Variables globales para las interrupciones ------------//
#include "interrupciones.c"
#include "configuracion_PLL.c"
#include "perifericos.c"
#include "funciones_uart.c"
int main()
{
u16 cont=TIEMPO_TOGGLE_INICIAL;
u8 tiempo_inicial_variable=1,estado_anti_reb_ext1=ANTI_REB_
IDLE,estado_anti_reb_ext2=ANTI_REB_IDLE,flag_ascendente=0;
//-------------- Vectores RTC -----------------//
u16 vector_hora_inicial_rtc[RTC_TAMANIO]={0,0,0,1,0,1,1,201
3};
//u16 vector_alarma_rtc[RTC_TAMANIO]={0,5,0,1,0,1,1,2013};
//-------------- Vectores RTC -----------------//
configurar_pll(CLK_XTAL,25,2,3,0,0);
// Cristal de 12MHz
pagado
LPC_GPIO3->FIOCLR=LED_2;
ncendido
configurar_hora_rtc(vector_hora_inicial_rtc);
habilitar_interrupciones_rtc((1<<RTC_SEG),0xff);
ito interrupcin por c/cuenta de 1 Seg del RCT.
//Habil
//configura_timer0(25000,1000);
//E
//Ext
>FIOSET|=LED_2;}
else
{LPC_GPIO3->FIOSET|=LED_1; LPC_GPIO3>FIOCLR|=LED_2;}
}
}
__wfi();
//Sleep-Mode
//if(flag_timer0)
if(flag_rtc)
}
if(flag_uart0_rx)
{
flag_uart0_rx=0;
if(dato_uart0=='a')
flag_ascendente=1;
//Cuenta Ascendente
if(dato_uart0=='d')
flag_ascendente=0;
//Cuenta descendente
}
}
}
El cambio ms destacado del anterior ejercicio, es que el timer0 no est
habilitado (comentado en el cdigo) y que ahora la base de tiempo de 1
Seg depende exclusivamente del RTC.
Ejercicio parte 2:
Del ejercicio realizado anteriormente con la UART, manteniendo al timer0
como base de tiempo de 1 seg, se pide:
- Configurar una alarma para que se enve por puerto serie un aviso
transcurrido los 5 minutos despus del reseteo.
- Si se enva por puerto serie el carcter r, enviar por puerto serie la
cuenta del RTC en el formato Da del mes/Mes/Ao Hora:Min:Seg c/1seg.
- Si se enva por puerto serie el carcter c, enviar por puerto serie la
cuenta implementada en los ejercicios anteriores para saber en qu
momento se dar cambio de estado de los leds.
defines.c => no hay modificaciones.
configuracion_PLL.c => no hay modificaciones.
perifericos.c => no hay modificaciones.
#include <LPC17xx.H>
#include "defines.c"
//------- Variables globales para las interrupciones ------------//
u8 flag_timer0=0,flag_timer1=0,flag_timer2=0,flag_timer3=0,flag
_ext1=0,flag_ext2=0,flag_uart0_rx=0,flag_uart0_tx=1,dato_uart0,
flag_rtc=0;
//------- Variables globales para las interrupciones ------------//
#include "interrupciones.c"
#include "configuracion_PLL.c"
#include "perifericos.c"
#include "funciones_uart.c"
int main()
{
u16 cont=TIEMPO_TOGGLE_INICIAL;
u8 tiempo_inicial_variable=1,estado_anti_reb_ext1=ANTI_REB_
IDLE,estado_anti_reb_ext2=ANTI_REB_IDLE,flag_ascendente=0,flag_
mostrar_hora=0;
//-------------- Vectores RTC -----------------//
u16 vector_hora_inicial_rtc[RTC_TAMANIO]={0,0,0,1,0,1,1,201
3};
u16 vector_alarma_rtc[RTC_TAMANIO]={0,5,0,1,0,1,1,2013};
//-------------- Vectores RTC -----------------//
configurar_pll(CLK_XTAL,25,2,3,0,0);
// Cristal de 12MHz
pagado
LPC_GPIO3->FIOCLR=LED_2;
ncendido
configurar_hora_rtc(vector_hora_inicial_rtc);
configurar_alarmas_rtc(vector_alarma_rtc);
//Al minuto 5
//E
//Ext
{LPC_GPIO3->FIOSET|=LED_1; LPC_GPIO3>FIOCLR|=LED_2;}
}
}
__wfi();
//Sleep-Mode
if(flag_timer0)
{
flag_timer0=0;
if(!flag_ascendente)
cont--;
else
cont++;
if(!flag_mostrar_hora)
{
enviar_string_uart0("Contador= \n");
envia_u16_string_uart0(cont);
enviar_string_uart0(" \n");
}
else
enviar_hora_rtc_uart0();
}
if(flag_ext1)
{
if(anti_rebote_ext1(&estado_anti_reb_ext1)>0)
{
if(tiempo_inicial_variable>1)
tiempo_inicial_variable--;
}
}
if(flag_ext2)
{
if(anti_rebote_ext2(&estado_anti_reb_ext2)>0)
tiempo_inicial_variable++;
}
if(flag_uart0_rx)
{
flag_uart0_rx=0;
if(dato_uart0=='a')
flag_ascendente=1;
//Cuenta Ascendente
if(dato_uart0=='d')
flag_ascendente=0;
//Cuenta descendente
if(dato_uart0=='r')
flag_mostrar_hora=1;
RTC c/1Seg.
if(dato_uart0=='c')
flag_mostrar_hora=0;
//Muestra el valor de
la cuenta c/1Seg.
}
if(flag_rtc)
{
flag_rtc=0;
enviar_string_uart0(" Alarma del RTC!!! - Pasaron
5 minutos desde el ltimo reseteo. \n");
}
}
}
En este cdigo, la base de tiempo de 1Seg sigue siendo el timer0, pero el
RTC se lo configura para que a los 5 minutos se enve un mensaje de
alarma.
Ac se puede ver en un "terminal", como se enva el valor que va tomando
el RTC c/1Seg, hasta que llega a los 5 minutos:
Si bien la hora del RTC no tiene los dgitos ajustados (todos los valores
tienen si o si 5 dgitos), para la prueba nos alcanza. Una forma de mejorar
la presentacin sera modificando la funcin "envia_u16_string_uart0" para
que enve una cierta cantidad de dgitos.
Les dejo el cdigo y para el prximo mensaje vamos a ver como funciona
el ADC.
Archivos Adjuntos
RTC - Parte 5.rar (412,7 KB (Kilobytes), 27 visitas)
Me Gusta
Mensaje inapropiado?
18/05/2
013
cosme
fulanit
#9
Sexta Parte - ADC
Caractersticas principales:
o04
Citar
de
Procedimiento de inicializacin:
Ingreso
:
octubre
-2009
Ubicaci
n: Bs.
As.
Mensaje
s:
2.508
//.... Lo anterior
#define MOSTRAR_CONTADOR
#define MOSTRAR_HORA_RTC
#define MOSTRAR_CONVERSION_ADC
12
#define CLKDIV
#define PDN
21
#define ADC_START
24
#define ADCOFFS
#define ADGINTEN
//Pin 0.23
//Pin 0.2
LPC_PINCON->PINSEL1&=~((3<<16));
LPC_PINCON->PINSEL1|=(1<<16);
//Pin 0.24
//Pin 0.2
//Pin 0.25
//Pin 0.2
//Pin 0.26
//Pin 0.2
//Pin 1.30
//Pin 1.3
break;
}
case 5:
{
LPC_PINCON->PINSEL3|=0xC0000000;
LPC_PINCON->PINMODE3|=0x80000000;
//Pin
//Pin 0.3 f
//Pin 0.3
//Pin 0.2 f
//Pin 0.2
LPC_ADC->ADTRM|=((offset&0x0f)<<ADCOFFS);
}
int convertir_adc(u8 canal,u8 pre_escaler_interno,u16 *valor_ad
c)
{
LPC_ADC->ADINTEN|=(1<<ADGINTEN);
//Habilito la interrupc
in
LPC_ADC->ADCR=(1<<ADC_START)|(1<<PDN)|
((pre_escaler_interno-1)<<CLKDIV)|(1<<canal);
//Elijo el can
//Sleep-Mode
//Pregunto si realmente termino la conversi
n en el canal deseado
{
LPC_TIM3->TCR=0; // paro el contador
flag_timer3=0;
*valor_adc=(u16)((LPC_ADC->ADGDR>>4)&0xfff);
return 1;
}
LPC_TIM3->TCR=0; // paro el contador
flag_timer3=0;
return -1;
}
//--------------------------------------- ADC ---------------------------------------//
void habilitar_interrupciones()
{
NVIC_EnableIRQ(TIMER0_IRQn);
//Timer0
NVIC_EnableIRQ(TIMER1_IRQn);
//Timer1
NVIC_EnableIRQ(TIMER2_IRQn);
//Timer2
NVIC_EnableIRQ(TIMER3_IRQn);
//Timer3
NVIC_EnableIRQ(EINT1_IRQn);
//Externa 1
NVIC_EnableIRQ(EINT2_IRQn);
//Externa 2
NVIC_EnableIRQ(UART0_IRQn);
//UART 0
NVIC_EnableIRQ(RTC_IRQn);
//RTC
NVIC_EnableIRQ(ADC_IRQn);
//ADC
}
//... Todo lo anterior
//--------- Rutina de la interrupcion ADC --------------------//
#define ADGINTEN
//Lectura fals
//Deshabilito interrup
}
//--------- Rutina de la interrupcion ADC --------------------//
Lo ms destacado:
- Requiere una lectura falsa del registro ADGDR para limpiar la
interrupcin.
- Al finalizar la rutina, la interrupcin queda deshabilitada.
main.c
Cdigo PHP:
#include <LPC17xx.H>
#include "defines.c"
//------- Variables globales para las interrupciones ------------//
u8 flag_timer0=0,flag_timer1=0,flag_timer2=0,flag_timer3=0,flag
_ext1=0,flag_ext2=0,flag_uart0_rx=0,flag_uart0_tx=1,dato_uart0,
flag_rtc=0,flag_adc=0;
//------- Variables globales para las interrupciones ------------//
#include "interrupciones.c"
#include "configuracion_PLL.c"
#include "perifericos.c"
#include "funciones_uart.c"
int main()
{
u16 cont=TIEMPO_TOGGLE_INICIAL,valor_adc;
u8 tiempo_inicial_variable=1,estado_anti_reb_ext1=ANTI_REB_
IDLE,estado_anti_reb_ext2=ANTI_REB_IDLE,flag_ascendente=0,flag_
mostrar=MOSTRAR_CONTADOR;
//-------------- Vectores RTC -----------------//
u16 vector_hora_inicial_rtc[RTC_TAMANIO]={0,0,0,1,0,1,1,201
3};
u16 vector_alarma_rtc[RTC_TAMANIO]={0,5,0,1,0,1,1,2013};
//-------------- Vectores RTC -----------------//
configurar_pll(CLK_XTAL,25,2,3,0,0);
// Cristal de 12MHz
pagado
LPC_GPIO3->FIOCLR=LED_2;
ncendido
configurar_hora_rtc(vector_hora_inicial_rtc);
configurar_alarmas_rtc(vector_alarma_rtc);
//Al minuto 5
//E
//Ext
et
habilitar_interrupciones();
while(1)
{
if(!flag_ascendente)
{
if(cont==1)
{
cont=tiempo_inicial_variable*TIEMPO_TOGGLE_INIC
IAL;
if(LPC_GPIO3->FIOPIN&LED_1)
{LPC_GPIO3->FIOCLR|=LED_1; LPC_GPIO3>FIOSET|=LED_2;}
else
{LPC_GPIO3->FIOSET|=LED_1; LPC_GPIO3>FIOCLR|=LED_2;}
}
}
else
{
if(cont==(tiempo_inicial_variable*TIEMPO_TOGGLE_INI
CIAL)-1)
{
cont=0;
if(LPC_GPIO3->FIOPIN&LED_1)
{LPC_GPIO3->FIOCLR|=LED_1; LPC_GPIO3>FIOSET|=LED_2;}
else
{LPC_GPIO3->FIOSET|=LED_1; LPC_GPIO3>FIOCLR|=LED_2;}
}
}
__wfi();
//Sleep-Mode
if(flag_timer0)
{
flag_timer0=0;
if(!flag_ascendente)
cont--;
else
cont++;
switch(flag_mostrar)
{
case MOSTRAR_CONTADOR:
{
enviar_string_uart0("Contador= \n");
envia_u16_string_uart0(cont);
enviar_string_uart0(" \n");
break;
}
case MOSTRAR_HORA_RTC:{enviar_hora_rtc_uart0();
break;}
case MOSTRAR_CONVERSION_ADC:
{
if(convertir_adc(0,250,&valor_adc)>0)
//Convierto en el canal 0, con un pre-escaler=250
{
enviar_string_uart0(" Conversion= \
n");
envia_u16_string_uart0(valor_adc);
}
}
}
}
if(flag_ext1)
{
if(anti_rebote_ext1(&estado_anti_reb_ext1)>0)
{
if(tiempo_inicial_variable>1)
tiempo_inicial_variable--;
}
}
if(flag_ext2)
{
if(anti_rebote_ext2(&estado_anti_reb_ext2)>0)
tiempo_inicial_variable++;
}
if(flag_uart0_rx)
{
flag_uart0_rx=0;
if(dato_uart0=='a')
flag_ascendente=1;
//Cuenta Ascendente
if(dato_uart0=='d')
flag_ascendente=0;
//Cuenta descendente
if(dato_uart0=='r')
flag_mostrar= MOSTRAR_HORA_RTC;
//Muestra el valor del RTC c/1Seg.
if(dato_uart0=='c')
flag_mostrar=MOSTRAR_CONTADOR;
//Muestra el valor de la cuenta c/1Seg.
if(dato_uart0=='q')
flag_mostrar=MOSTRAR_CONVERSION_ADC;
//Real
}
- Se configura el clock del ADC a la frecuencia mxima de 100kHz
(CCLK=100MHz => PCLK=1/4*CCLK=25MHz =>
ADC_CLK=1/250*PCLK=100kHz).
- El offset del ADC es 0 y se utiliza el canal 0 (P0.23) para realizar la
conversin.
- A diferencia del ejercicio anterior que se us la variable
"flag_mostrar_hora", en este se reemplaza dicha variable por
"flag_mostrar" y dependiendo de su valor mostrar el conteo, RTC o la
conversin del ADC.
- La alarma de 5 minutos del ejercicio anterior sigue estando habilitada.
Les dejo el cdigo y para el prximo mensaje vamos a ver como funciona
el DAC.
Archivos Adjuntos
ADC - Parte 6.rar (211,2 KB (Kilobytes), 32 visitas)
Me Gusta
Mensaje inapropiado?
18/05/201
3
Fogonaz
Citar
#10
o
Moderado
Me Gusta
r general
Fecha de
Ingreso:
enero2007
Ubicacin:
Mensaje inapropiado?
24/05/2
013
cosme
fulanit
o04
Citar
#11
Lo menos que uno puede hacer despus de todo lo que d este foro.
Sobre el ADC me falt agregar que su frecuencia mxima no puede
superar los 13MHz, as que ojo.
Fecha
de
DAC
Ingreso
:
Caractersticas principales:
octubre
-2009
10 bit de resolucin.
Ubicaci
Basado en red-2R.
n: Bs.
As.
Mensaj
es:
2.508
Procedimiento de inicializacin:
1- Su alimentacin no requiere ser habilitada, siempre lo esta.
2- Configurar el Pre-escaler del DAC (registro PCLKSEL0)
3- Configurar el pin 0.26 como DAC (registros PINSELx) y que funcione
como alta impedancia (registros PINMODEx).
4- Configurar el modo DMA[Opcional].
Solo se usar el registro DACR en el cual se especificar el nivel de tensin
deseado y la velocidad de conversin (estar relacionada con la corriente
//Todo lo anterior
//--------------------------------------- DAC ---------------------------------------//
#define PCLK_DAC
22
#define VALUE_DAC
#define BIAS_DAC
16
#define MAX_UPDATE_BIAS
on una actualizacin de
0
1
uS
#define MIN_UPDATE_BIAS
una actualizacin de 2,5
uS
void iniciar_dac()
{
//Su conexin a fuente siempre est habilitada => no es nec
esario modificar el registro PCONP
LPC_PINCON->PINSEL1&=~((3<<20));
LPC_PINCON->PINSEL1|=(2<<20);
como DAC
LPC_PINCON->PINMODE1&=~((3<<20));
LPC_PINCON->PINMODE1|=(2<<20);
o sin pull-up/down
LPC_SC->PCLKSEL0&=~((3<<PCLK_DAC));
LPC_SC->PCLKSEL0|=(3<<PCLK_DAC);
//PCLK_DAC 100MHZ/8
=12,5MHz
}
void asignar_valor_dac(u16 valor_dac,u8 bias)
{
LPC_DAC->DACR=((bias&0x1)<<BIAS_DAC)|
((valor_dac&0x3ff)<<VALUE_DAC);
}
//--------------------------------------- DAC ---------------------------------------//
La funcin de inicializacin es bastante simple, solo configura los pines y
reduce al mximo la frecuencia de clock que le llega al DAC.
Nota aparte: el fabricante declara que el DAC funciona a una frecuencia
mxima de 1MHz, pero no dice nada sobre el mximo clock (o por lo
menos yo no encontr nada al respecto), por lo tanto si trabajamos con el
CCLK=100MHz, como mximo vamos a poder reducir su frecuencia a
PCLK=CCLK/8=12,5MHz, durante las pruebas no tuve ningn
inconveniente trabajando con ese clock.
interrupciones.c => no hay modificaciones.
main.c
Cdigo PHP:
#include <LPC17xx.H>
#include "defines.c"
//------- Variables globales para las interrupciones ------------//
u8 flag_timer0=0,flag_timer1=0,flag_timer2=0,flag_timer3=0,flag
_ext1=0,flag_ext2=0,flag_uart0_rx=0,flag_uart0_tx=1,dato_uart0,
flag_rtc=0,flag_adc=0;
//------- Variables globales para las interrupciones ------------//
#include "interrupciones.c"
#include "configuracion_PLL.c"
#include "perifericos.c"
#include "funciones_uart.c"
int main()
{
u16 cont=TIEMPO_TOGGLE_INICIAL,valor_adc;
u8 tiempo_inicial_variable=1,estado_anti_reb_ext1=ANTI_REB_
IDLE,estado_anti_reb_ext2=ANTI_REB_IDLE,flag_ascendente=0,flag_
mostrar=MOSTRAR_CONTADOR;
//-------------- Vectores RTC -----------------//
u16 vector_hora_inicial_rtc[RTC_TAMANIO]={0,0,0,1,0,1,1,201
3};
u16 vector_alarma_rtc[RTC_TAMANIO]={0,5,0,1,0,1,1,2013};
//-------------- Vectores RTC -----------------//
configurar_pll(CLK_XTAL,25,2,3,0,0);
// Cristal de 12MHz
pagado
LPC_GPIO3->FIOCLR=LED_2;
ncendido
configurar_hora_rtc(vector_hora_inicial_rtc);
configurar_alarmas_rtc(vector_alarma_rtc);
//Al minuto 5
//E
//Ext
et
iniciar_dac();
asignar_valor_dac(620,MIN_UPDATE_BIAS);
//Vref=3,3V => S
}
}
else
{
if(cont==(tiempo_inicial_variable*TIEMPO_TOGGLE_INI
CIAL)-1)
{
cont=0;
if(LPC_GPIO3->FIOPIN&LED_1)
{LPC_GPIO3->FIOCLR|=LED_1; LPC_GPIO3>FIOSET|=LED_2;}
else
{LPC_GPIO3->FIOSET|=LED_1; LPC_GPIO3>FIOCLR|=LED_2;}
}
}
__wfi();
//Sleep-Mode
if(flag_timer0)
{
flag_timer0=0;
if(!flag_ascendente)
cont--;
else
cont++;
switch(flag_mostrar)
{
case MOSTRAR_CONTADOR:
{
enviar_string_uart0("Contador= \n");
envia_u16_string_uart0(cont);
enviar_string_uart0(" \n");
break;
}
case MOSTRAR_HORA_RTC:{enviar_hora_rtc_uart0();
break;}
case MOSTRAR_CONVERSION_ADC:
{
if(convertir_adc(0,250,&valor_adc)>0)
//Convierto en el canal 0, con un pre-escaler=250
{
enviar_string_uart0(" Conversion= \
n");
envia_u16_string_uart0(valor_adc);
}
}
}
}
if(flag_ext1)
{
if(anti_rebote_ext1(&estado_anti_reb_ext1)>0)
{
if(tiempo_inicial_variable>1)
tiempo_inicial_variable--;
}
}
if(flag_ext2)
{
if(anti_rebote_ext2(&estado_anti_reb_ext2)>0)
tiempo_inicial_variable++;
}
if(flag_uart0_rx)
{
flag_uart0_rx=0;
if(dato_uart0=='a')
flag_ascendente=1;
//Cuenta Ascendente
if(dato_uart0=='d')
flag_ascendente=0;
//Cuenta descendente
if(dato_uart0=='r')
flag_mostrar= MOSTRAR_HORA_RTC;
//Muestra el valor del RTC c/1Seg.
if(dato_uart0=='c')
flag_mostrar=MOSTRAR_CONTADOR;
//Muestra el valor de la cuenta c/1Seg.
if(dato_uart0=='q')
flag_mostrar=MOSTRAR_CONVERSION_ADC;
//Real
Archivos Adjuntos
DAC - Parte 7.rar (212,8 KB (Kilobytes), 20 visitas)
Me Gusta
Mensaje inapropiado?
Citar
24/0
5/20
13
cos
mef
#12
Sptima Parte - Bonus Track
Ejercicio propuesto:
ula
nito
04
Fech
a de
Ingr
eso:
octu
bre-
200
9
Ubic
aci
n:
Bs.
valores que tomarn las seales, para lo cual yo utilic el programa Matlab
As.
Men
saje
s:
2.50
8
Dicho vector fue creado para que almacenara 100 elementos posibles para
ser utilizadas en seales de bajas frecuencias. Una vez creado los vectores,
los transfer directamente al cdigo como si fueran variables u16
directamente en la memoria RAM como ya vern en el cdigo.
Adems puse a prueba la velocidad del DAC para comprobar si realmente
trabaja a 1uS, el resultado obtenido es sorprendente, el DAC trabaja incluso
por debajo del tiempo que declara el fabricante, consiguiendo una senoidal de
hasta 113kHz usando solo 16 puntos, dando una conversin cada 550nS
(luego subir el cdigo de prueba, en el cual se genera dicha senoidal).
Resumiendo la idea:
- Seal de 100Hz => usar el timer0 configurado en 100uS para muestrear el
vector (100 muestras).
- Seal de 1kHz => usar el timer0 configurado en 10uS para muestrear el
vector (100 muestras).
- Seal de 10kHz => usar directamente el mnimo tiempo que tarda DAC
como base de tiempo para generar la seal (no voy a tener un control de la
base de tiempo, por lo tanto la frecuencia resultante depender de la
cantidad de muestras, en un principio intent con 100, pero luego us
50) [Apunto a estar en el orden de la frecuencia].
- Seal de 100kHz => nuevamente usar directamente el mnimo tiempo que
tarda DAC como base de tiempo para generar la seal (no voy a tener un
control de la base de tiempo, solo se utilizarn 10 puntos de muestra)
[Apunto a estar en el orden de la frecuencia].
define.c (modificaciones realizadas)
Cdigo PHP:
typedef
typedef
typedef
#define CIEN_PTS
#define CINCUENTA_PTS
#define DIEZ_PTS
1
2
#define SENIAL_SENOIDAL
#define SENIAL_TRIANGULAR
#define SENIAL_DIENTE_DE_SIERRA
1
2
#define CIEN_HZ
#define MIL_HZ
#define DIEZ_MIL_HZ
#define CIEN_MIL_HZ
//Todo lo anterior
#define PCLK_TIMER0
#define DIVISOR_PERIFERICOS_1
#define DIVISOR_PERIFERICOS_2 2
#define DIVISOR_PERIFERICOS_4
#define DIVISOR_PERIFERICOS_6
#define DIVISOR_PERIFERICOS_8
//Solo CAN
/*
Tiempo mnimo de actualizacin del DAC => 1uS
100Hz
=> 10k
pts posibles
1kHz
=> 1k
10kHz
=> 100
pts posibles
100kHz
=> 10
pts posibles
pts posibles
*/
u16 vector_senoidal_100_pts[100]={512,544,577,609,641,672,702,732
,761,789,816,841,865,888,909,929,947,963,978,990,1001,1010,1016,1
021,1023,1023,1022,1019,1013,1005,996,984,971,955,938,919,899,877
,853,828,802,775,747,717,687,656,625,593,561,528,496,463,431,399,
368,337,307,277,249,222,196,171,147,125,105,86,69,53,40,28,19,11,
5,2,0,1,3,8,14,23,34,46,61,77,95,115,136,159,183,208,235,263,292,
322,352,383,415,447,480,512};
u16 vector_triangular_100_pts[100]={0,20,41,61,82,102,123,143,164
,184,205,225,246,266,287,307,328,348,369,389,410,430,451,471,492,
512,532,553,573,594,614,635,655,676,696,717,737,758,778,799,819,8
40,860,881,901,922,942,963,983,1004,1023,1004,983,963,942,922,901
,881,860,840,819,799,778,758,737,717,696,676,655,635,614,594,573,
553,532,512,492,471,451,430,410,389,369,348,328,307,287,266,246,2
25,205,184,164,143,123,102,82,61,41,20};
u16 vector_diente_sierra_100_pts[100]={0,10,20,31,41,51,61,72,82,
92,102,113,123,133,143,153,164,174,184,194,205,215,225,235,246,25
6,266,276,286,297,307,317,327,338,348,358,368,379,389,399,409,419
,430,440,450,460,471,481,491,501,512,522,532,542,552,563,573,583,
593,604,614,624,634,644,655,665,675,685,696,706,716,726,737,747,7
57,767,777,788,798,808,818,829,839,849,859,870,880,890,900,910,92
1,931,941,951,962,972,982,992,1003,1013};
void generar_senial(u8 *indice_dato,u8 senial,u8 flag_pts)
{
switch(senial)
{
case SENIAL_SENOIDAL:
{
asignar_valor_dac(vector_senoidal_100_pts[*indice
_dato],MAX_UPDATE_BIAS);
break;
}
case SENIAL_TRIANGULAR:
{
asignar_valor_dac(vector_triangular_100_pts[*indi
ce_dato],MAX_UPDATE_BIAS);
break;
}
case SENIAL_DIENTE_DE_SIERRA:
{
asignar_valor_dac(vector_diente_sierra_100_pts[*i
ndice_dato],MAX_UPDATE_BIAS);
break;
}
}
*indice_dato+=1;
if(*indice_dato>99)
*indice_dato=0;
}
void configurar_timer_por_frecuencia(char frecuencia,u8 *flag_pts
)
{
switch(frecuencia)
{
case CIEN_HZ:
{
configura_timer0(100,99);
//Pre-escaler 25 =>
//Pre-escaler 25 => 2
*flag_pts=CIEN_PTS;
break;
}
case DIEZ_MIL_HZ:
{
*flag_pts=CINCUENTA_PTS;
LPC_TIM0->TCR=0; // Paro el Timer0
break;
}
case CIEN_MIL_HZ:
{
*flag_pts=DIEZ_PTS;
LPC_TIM0->TCR=0; // Paro el Timer0
break;
}
}
}
Se puede ver:
- La creacin de 3 vectores de 100 elementos c/u que contendrn las
distintas seales.
- La funcin "generar_senial" solo utilizada en 100 y 1kHz (ya explicar el
porque).
- La funcin "configurar_timer_por_frecuencia" que se encargar de modificar
la base de tiempo segn la frecuencia, esta base de tiempo es solo utilizada
hasta seales de 1kHz.
main.c
Cdigo PHP:
#include <LPC17xx.H>
#include "defines.c"
//------- Variables globales para las interrupciones ------------//
u8 flag_timer0=0,flag_timer1=0,flag_timer2=0,flag_timer3=0,flag_e
xt1=0,flag_ext2=0,flag_uart0_rx=0,flag_uart0_tx=1,dato_uart0,flag
_rtc=0,flag_adc=0;
//------- Variables globales para las interrupciones ------------//
#include "interrupciones.c"
#include "configuracion_PLL.c"
#include "perifericos.c"
#include "funciones_de_senial.c"
int main()
{
u8 indice_senial=0,flag_pts=CIEN_PTS;
int tipo_senial=SENIAL_SENOIDAL,frecuencia=MIL_HZ;
u8 estado_anti_reb_ext1=ANTI_REB_IDLE,estado_anti_reb_ext2=AN
TI_REB_IDLE;
configurar_pll(CLK_XTAL,25,2,3,
(DIVISOR_PERIFERICOS_1<<PCLK_TIMER0),0);
// Cristal de 12MHz =
//Ext
//Sleep-Mode
else
{
switch(tipo_senial)
{
case SENIAL_SENOIDAL:
{
LPC_DAC-
//Exter
>DACR=((vector_senoidal_100_pts[indice_senial]&0x3ff)<<VALUE_DAC)
;
if(indice_senial>99)
indice_senial=0;
}
}//El DAC funciona a toda velocidad --> no necesito timer
if(flag_timer0)
{
flag_timer0=0;
generar_senial(&indice_senial,tipo_senial,flag_pts);
}
if(flag_ext1)
{
if(anti_rebote_ext1(&estado_anti_reb_ext1)>0)
{
frecuencia--;
if(frecuencia<0)
{
frecuencia=CIEN_MIL_HZ;
tipo_senial--;
if(tipo_senial<0)
tipo_senial=SENIAL_DIENTE_DE_SIERRA;
}
configurar_timer_por_frecuencia(frecuencia,&flag_
pts);
}
}
if(flag_ext2)
{
if(anti_rebote_ext2(&estado_anti_reb_ext2)>0)
{
frecuencia++;
if(frecuencia>CIEN_MIL_HZ)
{
frecuencia=CIEN_HZ;
tipo_senial++;
if(tipo_senial>SENIAL_DIENTE_DE_SIERRA)
tipo_senial=SENIAL_SENOIDAL;
}
configurar_timer_por_frecuencia(frecuencia,&flag_
pts);
}
}
}
}
Lo ms destacado:
- Para las frecuencias altas, trat de no llamar varias funciones y actuar
directamente sobre el
registro. En ests frecuencias el DAC est continuamente convirtiendo.
- Para las frecuencias bajas, us la funcin "generar_senial" y durante el
tiempo muerto el uC est en modo sleep.
Resultados obtenidos:
Senoidal de 100Hz
Me Gusta
Mensaje inapropiado?
01/06/201
3
cosmefu
lanito04
Citar
#13
Diagrama en bloques:
Fecha de
Ingreso:
octubre2009
Ubicacin
Me Gusta
: Bs. As.
Mensajes:
2.508
Mensaje inapropiado?
Citar
08/06/2
013
cosme
fulanit
#14
Novena Parte - SSP (como SPI)
Aclaracin:
o04
Caractersticas principales:
octubre
-2009
Ubicaci
Semiconductor Microwire).
n: Bs.
As.
Mensaj
es:
2.508
//Todo lo anterior
//--------------------------------------- SSP0 ---------------------------------------//
#define PCSSP0
21
#define PCSSP1
10
#define SSP_MODO_MAESTRO
#define SSP_MODO_ESCLAVO
#define SSP0_SCK0
#define SSP0_SSEL0
10
#define SSP0_MISO0
14
#define SSP0_MOSI0
16
#define SSP0_GPIO_SSEL0
//P1.20
//P1.21
//P1.23
//P1.24
21
#define DSS_4BIT
#define DSS_5BIT
#define DSS_6BIT
#define DSS_7BIT
#define DSS_8BIT
#define FRF_SPI
#define FRF_TI
#define FRF_MICROWIRE
0
(1<<4)
(2<<4)
#define
SSP0_CPOL0
#define
SSP0_CPOL1
(1<<6)
#define
SSP0_CPHA0
#define
SSP0_CPHA1
(1<<7)
#define LBM_OFF
#define LBM_ON
#define SSE_OFF
#define SSE_ON
(1<<1)
#define MS_MASTER
#define MS_SLAVE
(1<<2)
#define SLAVE_OUT_DISABLE
#define
(1<<3)
RTIM
(1<<1)
#define RXIM
(1<<2)
#define RNE
(1<<2)
#define RFF
(1<<3)
//8bit de datos
{
LPC_SC->PCONP|=(1<<PCSSP0);
//Habilito el SSP0 en el control de consumo de los
perifricos
LPC_SSP0->CR1=SSE_OFF;
//SSP deshabilitado
LPC_PINCON->PINSEL3&=~((3<<SSP0_SCK0));
LPC_PINCON->PINSEL3|=(3<<SSP0_SCK0);
//Pin 1.20 funcionando como SCK0 del SSP0
LPC_PINCON->PINMODE3&=~((3<<SSP0_SCK0));
//Pull-up
LPC_PINCON->PINSEL3&=~((3<<SSP0_SSEL0));
//OJO!! usado en modo GPIO
LPC_PINCON->PINMODE3&=~((3<<SSP0_SSEL0));
//Pull-up
LPC_GPIO1->FIODIR|=(1<<SSP0_GPIO_SSEL0);
//Como salida
LPC_GPIO1->FIOSET|=(1<<SSP0_GPIO_SSEL0);
//Paro el contador
if(!flag_timer3)
return LPC_SSP0->DR;
else
return -1;
}
que usar.
memoria_SD.c (librera obtenida en AVR-Freaks)
Cdigo PHP:
0xFE
#define SD_DAT_TOKEN_WRITE
0xFC
#define SD_DAT_TOKEN_STOP
0xFD
#define MMC_SEND_OP_COND
#define MMC_SEND_CSD
#define MMC_SEND_CID
10
#define MMC_SEND_STATUS
13
#define MMC_SET_BLOCKLEN
16
#define MMC_READ_SINGLE_BLOCK
17
#define MMC_WRITE_BLOCK
24
#define MMC_PROGRAM_CSD
27
#define MMC_SET_WRITE_PROT
28
#define MMC_CLR_WRITE_PROT
29
#define MMC_SEND_WRITE_PROT
30
#define MMC_TAG_SECTOR_START
32
#define MMC_TAG_SECTOR_END
33
#define MMC_UNTAG_SECTOR
34
#define MMC_TAG_ERASE_GROUP_START
35
#define MMC_TAG_ERARE_GROUP_END
36
#define MMC_UNTAG_ERASE_GROUP
37
#define MMC_ERASE
38
#define MMC_CRC_ON_OFF
59
/*##############################################
#
mmcCommand
##############################################*/
// Send a le
ading 0xFF
spiByteOut(cmd | 0x40);
// Send the
// Send the
// Send the
// Send the
// Send the
// Send the
initMMC
##############################################*/
u8 initMMC (void)
{
u8 i,result;
iniciar_ssp0(FRF_SPI,SSP_MODO_MAESTRO,254,SSP0_CPHA0,SSP0_CP
OL0); //8bit de datos, SPP clock=25MHz/254=98,4kHz ==> El prees
caler solo es numero PAR!
LPC_GPIO1->FIOSET|=(1<<SSP0_GPIO_SSEL0);
//Estado Idle => "1"
// Wait fo
r 80 SPI clockcycles
spiByteOut(0xFF);
// for the
SPI to initialise
}
LPC_GPIO1->FIOCLR|=(1<<SSP0_GPIO_SSEL0);
//Estado Idle => "0"
result = mmcCommand(MMC_GO_IDLE_STATE, 0);
// make mmc go
to SPI mode
if (result != 1) {
// if the
// stop in
// Wait unt
// return t
mmcReadBlock
just change
the 'unsigned
int' into #
##############################################*/
u8 mmcReadBlock (u16 adress, u8 *databuffer) {
// Send the read command
, and the start adress as param
u8 result = mmcCommand(MMC_READ_SINGLE_BLOCK, (unsigned long
)(adress<<9));
u16 i;
if (result != 0) {
// If the
// stop read
// If all is
well though...
while (spiByteOut(0xFF) != (u8)0xFE);
// Wait for th
// And loop
// Set an ele
// And increa
se the pointer
}
spiByteOut(0xFF);
// Recieve a
// Return al
l is well.
}
/*##############################################
#
mmcWriteBlock
##############################################*/
u8 mmcWriteBlock (u16 adress, u8 *databuffer) {
//Send the write command
, and the start adress as param
u8 result = mmcCommand(MMC_WRITE_BLOCK, (u32)(adress<<9));
u16 i;
if (result != 0) {
command returns an error code...
// If the
return result;
}
// return it
// If everyt
hings OK
spiByteOut(0xFF);
// Send a du
mmy checksum
spiByteOut(0xFF);
spiByteOut(0xFE);
// Send the
// Send all
512 bytes.
spiByteOut(databuffer[i]);
// Send the
byte
}
spiByteOut(0xFF);
// Recieve d
ummy checksum
spiByteOut(0xFF);
result = spiByteOut(0xFF) & 0x1F;
// Read the
// If someth
// Return th
e error
}
// If all is
well...
while (!spiByteOut(0xFF));
// Wait unti
// And retur
n succes!
}
Lo nico que me encargo yo, es de inicializar el bus SSP0 a una baja
velocidad durante la inicializacin de la memoria (100kHz). Luego de la
inicializacin, se podra llevar la velocidad hasta 25MHz.
Cdigo PHP:
iniciar_ssp0(FRF_SPI,SSP_MODO_MAESTRO,254,SSP0_CPHA0,SSP0_CPOL0
); //8bit de datos, SPP clock=25MHz/254=98,4kHz ==> El preescal
//E
#include <LPC17xx.H>
#include <stdlib.h>
#include "defines.c"
//------- Variables globales para las interrupciones ------------//
u8 flag_timer0=0,flag_timer1=0,flag_timer2=0,flag_timer3=0,flag
_ext1=0,flag_ext2=0,flag_uart0_rx=0,flag_uart0_tx=1,dato_uart0,
flag_rtc=0,flag_adc=0;
//------- Variables globales para las interrupciones ------------//
#include "interrupciones.c"
#include "configuracion_PLL.c"
#include "perifericos.c"
#include "funciones_uart.c"
#include "memoria_SD.c"
int main()
{
u16 cont=TIEMPO_TOGGLE_INICIAL,valor_adc;
u8 tiempo_inicial_variable=1,estado_anti_reb_ext1=ANTI_REB_
IDLE,estado_anti_reb_ext2=ANTI_REB_IDLE,flag_ascendente=0,flag_
mostrar=MOSTRAR_CONTADOR;
u8 *buffer_datos;
u16 indice_buffer;
//-------------- Vectores RTC -----------------//
u16 vector_hora_inicial_rtc[RTC_TAMANIO]={0,0,0,1,0,1,1,201
3};
u16 vector_alarma_rtc[RTC_TAMANIO]={0,5,0,1,0,1,1,2013};
//-------------- Vectores RTC -----------------//
configurar_pll(CLK_XTAL,25,2,3,0,0);
// Cristal de 12MHz
pagado
LPC_GPIO3->FIOCLR=LED_2;
ncendido
configurar_hora_rtc(vector_hora_inicial_rtc);
configurar_alarmas_rtc(vector_alarma_rtc);
//Al minuto 5
configurar_externa_1(EXT1_MODO_FLANCO,EXT1_POL_NEG);
//E
//Ext
et
iniciar_dac();
asignar_valor_dac(620,MIN_UPDATE_BIAS);
i quiero 2Volts => 2V/3,3V*1024=620,6 cuentas
//Vref=3,3V => S
habilitar_interrupciones();
while(1)
{
if(!flag_ascendente)
{
if(cont==1)
{
cont=tiempo_inicial_variable*TIEMPO_TOGGLE_INIC
IAL;
if(LPC_GPIO3->FIOPIN&LED_1)
{LPC_GPIO3->FIOCLR|=LED_1; LPC_GPIO3>FIOSET|=LED_2; asignar_valor_dac(620,MIN_UPDATE_BIAS); /*Vref=
3,3V => Si quiero 2Volts => 2V/3,3V*1024=620,6 cuentas*/}
else
{LPC_GPIO3->FIOSET|=LED_1; LPC_GPIO3>FIOCLR|=LED_2; asignar_valor_dac(310,MIN_UPDATE_BIAS); /*Vref=
3,3V => Si quiero 1Volt => 1V/3,3V*1024=310,3 cuentas*/}
}
}
else
{
if(cont==(tiempo_inicial_variable*TIEMPO_TOGGLE_INI
CIAL)-1)
{
cont=0;
if(LPC_GPIO3->FIOPIN&LED_1)
{LPC_GPIO3->FIOCLR|=LED_1; LPC_GPIO3>FIOSET|=LED_2;}
else
{LPC_GPIO3->FIOSET|=LED_1; LPC_GPIO3>FIOCLR|=LED_2;}
}
}
__wfi();
//Sleep-Mode
if(flag_timer0)
{
flag_timer0=0;
if(!flag_ascendente)
cont--;
else
cont++;
switch(flag_mostrar)
{
case MOSTRAR_CONTADOR:
{
enviar_string_uart0((u8 *)("Contador= \
r\n"));
envia_u16_string_uart0(cont);
enviar_string_uart0((u8 *)("\r\n"));
break;
}
case MOSTRAR_HORA_RTC:{enviar_hora_rtc_uart0();
break;}
case MOSTRAR_CONVERSION_ADC:
{
if(convertir_adc(0,250,&valor_adc)>0)
//Convierto en el canal 0, con un pre-escaler=250
{
enviar_string_uart0((u8 *)(" Conver
sion= \r\n"));
envia_u16_string_uart0(valor_adc);
}
}
}
}
if(flag_ext1)
{
if(anti_rebote_ext1(&estado_anti_reb_ext1)>0)
{
if(tiempo_inicial_variable>1)
tiempo_inicial_variable--;
}
}
if(flag_ext2)
{
if(anti_rebote_ext2(&estado_anti_reb_ext2)>0)
tiempo_inicial_variable++;
}
if(flag_uart0_rx)
{
flag_uart0_rx=0;
if(dato_uart0=='a')
flag_ascendente=1;
//Cuenta Ascendente
if(dato_uart0=='d')
flag_ascendente=0;
//Cuenta descendente
if(dato_uart0=='r')
flag_mostrar= MOSTRAR_HORA_RTC;
//Muestra el valor del RTC c/1Seg.
if(dato_uart0=='c')
flag_mostrar=MOSTRAR_CONTADOR;
//Muestra el valor de la cuenta c/1Seg.
if(dato_uart0=='q')
flag_mostrar=MOSTRAR_CONVERSION_ADC;
iza una conversin ADC y muestra su valor c/1Seg.
if(dato_uart0=='l')
//Real
{
buffer_datos=calloc(512,sizeof(u8));
//5
12 bytes
if(!buffer_datos)
{enviar_string_uart0((u8 *)("Memoria RA
M insuficiente.\r\n"));}
else
{
if(initMMC()!=0)
{enviar_string_uart0((u8 *)("Error
de inicio Memoria.\r\n"));}
else
{
if(mmcReadBlock (0,buffer_datos)==0
)
{
for(indice_buffer=0;indice_buff
er<511;indice_buffer++)
{
envia_dato_uart0(*(buff
er_datos+indice_buffer));
}
}
else
{enviar_string_uart0((u8 *)
("Error de lectura de Memoria.\r\n"));}
}
}
free(buffer_datos);
}
if(dato_uart0=='e')
{
buffer_datos=calloc(512,sizeof(u8));
12 bytes
//5
if(!buffer_datos)
{enviar_string_uart0((u8 *)("Memoria RA
M insuficiente.\r\n"));}
else
{
*buffer_datos='E';
*(buffer_datos+1)='s';
*(buffer_datos+2)='c';
*(buffer_datos+3)='r';
*(buffer_datos+4)='i';
*(buffer_datos+5)='b';
*(buffer_datos+6)='e';
*(buffer_datos+7)='\r';
*(buffer_datos+8)='\n';
if(initMMC()!=0)
{enviar_string_uart0((u8 *)("Error
de inicio Memoria.\r\n"));}
else
{
if(mmcWriteBlock (0,buffer_datos)!
=0)
{enviar_string_uart0((u8 *)
("Error de escritura de Memoria.\r\n"));}
}
}
free(buffer_datos);
}
if(dato_uart0=='v')
{
buffer_datos=calloc(512,sizeof(u8));
12 bytes
if(!buffer_datos)
//5
{enviar_string_uart0((u8 *)("Memoria RA
M insuficiente.\r\n"));}
else
{
*buffer_datos='P';
*(buffer_datos+1)='r';
*(buffer_datos+2)='u';
*(buffer_datos+3)='e';
*(buffer_datos+4)='b';
*(buffer_datos+5)='a';
*(buffer_datos+6)='\r';
*(buffer_datos+7)='\n';
if(initMMC()!=0)
{enviar_string_uart0((u8 *)("Error
de inicio Memoria.\r\n"));}
else
if(mmcWriteBlock (0,buffer_datos)!
=0)
{enviar_string_uart0((u8 *)
("Error de escritura de Memoria.\r\n"));}
}
free(buffer_datos);
}
}
if(flag_rtc)
{
flag_rtc=0;
enviar_string_uart0((u8 *)(" Alarma del RTC!!! - Pa
saron 5 minutos desde el ultimo reseteo. \r\n"));
}
}
}
Lo ms destacado:
Mensaje inapropiado?
14/08/2013
cosmefulanito04
Citar
#15
alexv8 dijo:
Gracias.
Fecha de Ingreso:
octubre-2009
Ubicacin: Bs. As.
Mensajes: 2.508
[Tutorial] FreeRTOS
Me Gusta
Mensaje inapropiado?
14/08/2013
Hellmut1956
Citar
#16
Fecha de Ingreso:
diciembre-2008
Ubicacin:
Mammendorf,
Alemania
Mensajes: 250
Mensaje inapropiado?
Citar
14/08/2013
cosmefulanito0
4
#17
Hellmut1956 dijo:
ARM exige de todos aquellos que toman una licencia para el desarollo de
una componente del tipo ARM Cortex Mx, que estas empresas deben
obligatoriamente poner a dispocicin del usuario una API para cada
funcin periferica de su componente, donde la APi es comun para todas
las componentes de todos los que licencian de ARM un Cortex Mx. Esto
tiene la gran ventaja para el que usa un ARM Cortex Mx, que si programa
usa estos API definidos por ARM, el esfuerzo para portar un programa de
Fecha de Ingreso:
octubre-2009
Ubicacin: Bs. As.
Mensajes: 2.508
Tambin quiero indicar que NXP, por ejemplo ofrece los LPCXpresso que
cuestan algo menos que el kit que presentan e incluyen una interfaz
JTAG, adicional a la interfaz USB, lo que es de gran utilidad para observar
un programa como es ejecutado en el sistema destino. Permite
prcticamente todas las funciones de Debug que en otras arquitecturas
requieren usar un simulador.
Mensaje inapropiado?
Citar
16/08/2013
Hellmut1956
#18
Fecha de
Ingreso:
diciembre-2008
Ubicacin:
Mammendorf,
Alemania
Mensajes: 250
Mensaje inapropiado?
31/08/2013
marcos0007
Fecha de Ingreso:
Citar
#19
Cosmefulanito,
Excelente tu post, te felicito. Te comento que compre la misma
agosto-2013
Mensajes: 32
Mensaje inapropiado?
Citar
01/09/2013
cosmefulanito04
#20
Fecha de Ingreso:
octubre-2009
Ubicacin: Bs. As.
Mensajes: 2.508
Archivos Adjuntos
NGX_PARALLEL_PORT_JTAG.pdf (44,0 KB (Kilobytes), 5 visitas)