Haz una pregunta
  Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos
Foros Registrarse ¿Olvidaste tu contraseña?

Temas similares

14/11/2013 #61

Avatar de ilcapo

muy buen tutorial cosme ! algun dia voy a continuar el de ARM7 lo abande un poco por falta de tiempo! :(
14/11/2013 #62

Avatar de cosmefulanito04

ilcapo dijo: Ver Mensaje
muy buen tutorial cosme ! algun dia voy a continuar el de ARM7 lo abande un poco por falta de tiempo! :(
Gracias.

Este tutorial te puede ser muy útil para ARM7, solo cambian pequeñas cosas como el nombre de los registros, pero básicamente es muy similar.

marcos0007 dijo: Ver Mensaje
A vos tu código te funciona perfectamente?
Si, por ej. colocando una batería entre masa y ADC0 (P0.23), usando el código "Sexta Parte - ADC", obtengo una conversión entre 1971 y 1977, con varias muestras (1,587v a 1,592v, menos de 4mV!).

¿Configuraste bien el PLL? ¿configuraste bien el pre-escaler del ADC?

En el ejemplo que subí, el PLL está configurado para trabjar con un CCLK=100MHz, PCLK=25MHz, pre-escaler del ADC 250 dando como resultado una frecuencia de muestreo de 100kHz para tener 12 bits de resolución.
14/11/2013 #63


Cosmefulanito, yo probé el código tal cual lo bajé de tu ejemplo. Las cosas que fui probando fue

Código PHP:
    configura_timer0(25000,1000);    //Pre-escaler 250000 => 25MHz/250000=1000Hz => 1000cuentas => 1000Hz/1000cuentas=1Hz=1Seg 

    
iniciar_adc(0,0);    //Inicio el ADC en el canal 0 sin offset 
cambiarle el 1000 por 500 para que haga la conversión más rápido, otra cosa que cabié fué probar iniciar el canal 2 en lugar del 0. Nada más

En realidad no necesito 12 bit de resolución con 8 alcanzaría. pero varía demasiado
GRacias
14/11/2013 #64

Avatar de cosmefulanito04

marcos0007 dijo: Ver Mensaje
Cosmefulanito, yo probé el código tal cual lo bajé de tu ejemplo. Las cosas que fui probando fue

Código PHP:
    configura_timer0(25000,1000);    //Pre-escaler 250000 => 25MHz/250000=1000Hz => 1000cuentas => 1000Hz/1000cuentas=1Hz=1Seg 

    
iniciar_adc(0,0);    //Inicio el ADC en el canal 0 sin offset 
cambiarle el 1000 por 500 para que haga la conversión más rápido, otra cosa que cabié fué probar iniciar el canal 2 en lugar del 0. Nada más
Cambiar el timer0 no hace ni más rápida ni más lenta la conversión del ADC, sino que generás interrupciones de timer en menor tiempo, es decir c/500mS.

La velocidad de conversión se fija cuando realizas una usando la función "convertir_adc", en mi ejemplo usé:

Código PHP:
if(convertir_adc(0,250,&valor_adc)>0)    //Convierto en el canal 0, con un pre-escaler=250 

  ....

En esa condición el pre-escaler está en 250 => PCLK=25MHz => Fsampling=100kHz.

¿Estás usando bien la variable que pasas por referencia? (en este caso "valor_adc")

marcos0007 dijo: Ver Mensaje
En realidad no necesito 12 bit de resolución con 8 alcanzaría. pero varía demasiado
Insisto, no es solo un tema de tener mayor o menor resolución, a mayor velocidad de conversión, mayor será el ruido que te entre en la lectura, por eso como primera medida te recomendé bajar la velocidad.
14/11/2013 #65


Aprovecho que veo que estáis con DAC para una duda sobre un trabajo que tenía (adjunto el pdf), y es en la actividad 7.2, que he de utilizar la función SYSTICK para que cada 1ms me saque las 64 muestras, y bueno, en general no se por donde empezar... ¿Alguna idea de como realizar el código?
Archivos Adjuntos
Tipo de Archivo: pdf Practica_7_Conversor_Digital_Analogico.pdf (270,4 KB (Kilobytes), 24 visitas)
14/11/2013 #66

Avatar de cosmefulanito04

Se me ocurre que podrías usar un timer c/15us para que vaya muestreando el vector y lo saques por el DAC hasta llegar al índice 65, luego c/1mS sincronizas de nuevo y reinicias el índice.

Para eso, yo configuraría el PCLK del timer en 100MHz, de esa forma aumentas la cuenta en el timer y tenés menor error de cuantización, tal como expliqué en el ejemplo "Segunda Parte - PLL y timers (código)":

cosmefulanito04 dijo:
Por otro lado se puede ver que la cantidad de cuentas para generar 1uS es de solo 25, por lo que se obtendrá un error de cuantización de 1/25=0,04 cuentas. Para mejorar ese inconveniente, se podría aumentar el Pclk a 100MHz, logrando así que se necesiten 100 cuentas para obtener 1uS y bajando el error de cuantización a 1/100=0,01 cuentas.
14/11/2013 #67


Me exigen emplear únicamente el SYSTICK (lo siento estoy un poco verde en estos temas, ¿pero entiendo que PCLK es un periférico, no?) y no se que valor he de dar al registro TENMS de SysTick para conseguir 1ms en lugar de los 10ms que están predeterminados, le pregunté al profesor y me respondió escuetamente que debía emplear una frecuencia de 64KHz pero no entendí bien como emplearla ni como declararla en la función.
14/11/2013 #68

Avatar de cosmefulanito04

Mucho sentido no le veo usar el systemtick a frecuencia tan alta... pero si te piden eso, hace eso

La cosa es así, vos tenés 64 muestras que debes muestrear a 1mSeg (1kHz), por lo tanto el tiempo de c/muestra deberá ser de 1mSeg/64, eso te dá casi 15uSeg (los que mencioné arriba, que son esos 64kHz que menciona tu pofesor).

Resumiendo, configurá el System Tick para que lance una interrupción c/15uSeg y en la rutina de interrupción y envia por Dac la muestra (y no voy a subirte el código porque es tu tarea).

Si lo querés hacer perfecto, también deberías tener en cuenta el tiempo de conversión del Dac.
15/11/2013 #69


¡Vale, genial! Ya veo lo que quería decirme el profesor con esa frecuencia jaja, una última cosilla, ¿Cómo calculo el valor del registro de SYSTICK que realiza la cuenta atrás (TENMS) para que en lugar de los 10ms sea de 15us? ¿He de tantearlo o hay alguna forma de calcularlo? Gracias!

Entiendo que es lo que me piden y me gusta resolverlo yo, no trato de que me resuelvas el ejercicio aunque entiendo que pudiese parecerlo, pero no nos explican casi nada en clase y luego de leerme el manual de LPC17xx sigo con bastantes dudas... Si te sirve como prueba subo el ejercicio por el que te pregunte el otro día y como lo resolví yo

Código PHP:
/*----------------------------------------------------------------------------
 * Name:    SYSTICK_interrupt.c
 *----------------------------------------------------------------------------*/

#include "LPC17xx.H"
uint32_t pulsador;  
uint32_t SystemFrequency=100000000;

volatile uint32_t msTicks=1;  // Contadores de Ticks de x ms
uint32_t LED1_18=0;
uint32_t LED1_29=0;
uint32_t contador=0;
uint32_t k=1;


void SysTick_Handler (void)            // Rutina (ISR) de atención...
                                //... a la excepción 15 -del SYSTICK-
{
    if (
pulsador==0){        // pulsador pulsado
        
if(msTicks==1){
            
LED1_29=1;        // enciendo LED P1.29
            
LED1_18=0;        // apago LED P1.18
        
}
        if(
msTicks>=100 && msTicks<200){
            
LED1_29=0;                    // apago LED P1.29
              
LED1_18=1;                    // enciendo LED P1.18
              
}
        if(
msTicks>=200){
              
LED1_18=0;                    // apago LED P1.18
            
msTicks=0;
            }
        }
    else{                    
// pulsador sin pulsar
        
if(msTicks==1){
            
LED1_29=1;        // enciendo LED P1.29
            
LED1_18=0;        // apago LED P1.18
        
}
           if(
msTicks>=200 && msTicks<400){
            
LED1_29=0;                    // apago LED P1.29
              
LED1_18=1;                    // enciendo LED P1.18
              
}    
        if(
msTicks>=400){
              
LED1_18=0;                    // apago el LED P1.18
            
msTicks=0;
            }
        }
    if(
LED1_18==1){
        
LPC_GPIO1->FIOPIN &= ~(1<<18);        // enciendo LED P1.18
        
LPC_GPIO1->FIOPIN &= ~(1<<29);        // apago LED P1.29
        
}
    if(
LED1_18==0){
        
LPC_GPIO1->FIOPIN |= (1<<18);    // apago LED P1.18
        
LPC_GPIO1->FIOPIN |= (1<<29);    // enciendo LED P1.29
        
}
    if(
msTicks==k*100){
        
contador++;
        
k++;                        // Indicador de que ha llegado a 1 segundo
    
}
    
msTicks++;                               // Incrementar contadores cada 10ms  y cada 1s
}

static 
__INLINE uint32_t SysTick_Configuracion(uint32_t prio_SysTick)
{
    
SysTick->CTRL |= (1<<2);                        //Selecciono la fuente de reloj interna
    
SysTick->CTRL |= (1<<0);                        //Habilito la cuenta de SysTick
    
SysTick->CTRL |= (1<<1);                        //Habilito su posibilidad de generar interrupción
    
SysTick->LOAD SysTick->CALIB;    //Genera una interrupción de 10ms, los cuales los coge del registro de Calibración
    
SysTick->VAL 0;
    
NVIC_SetPriority(SysTick_IRQnprio_SysTick);    //Establece la prioridad que le llega como parametro

 
return(0);
}


int main (void)
{
  
LPC_GPIO1->FIODIR |= (1<<18);      // P1.18 definido como salida
  
LPC_GPIO1->FIODIR |= (1<<29);      // P1.29 definido como salida  
  
LPC_GPIO2->FIODIR &= ~(1<<12);  // P2.12 definido como entrada
  
SysTick_Configuracion((1<<__NVIC_PRIO_BITS) - 1); 
  
    
  
// SystemInit ();                // Inicializar relojes " clocks"
  //SysTick_Config (SystemFrequency/100);    // Configurar  SYSTICK

  
while (1pulsador=((LPC_GPIO2->FIOPIN & (1<<12))>>12);

15/11/2013 #70

Avatar de cosmefulanito04

markisrodrigo dijo:
¡Vale, genial! Ya veo lo que quería decirme el profesor con esa frecuencia jaja, una última cosilla, ¿Cómo calculo el valor del registro de SYSTICK que realiza la cuenta atrás (TENMS) para que en lugar de los 10ms sea de 15us? ¿He de tantearlo o hay alguna forma de calcularlo? Gracias!
Fijate que en el mensaje #56 que te deje el método para calcular la cuenta y que registro tenés que modificar, más detalles fijate en la hoja de datos.

Como evidentemente tu tiempo no será en mSeg, sino que en uSeg, en vez de 1000, deberías usar 1000000 en la división:



Ejemplo, 100uS con clock de 100MHz:



markisrodrigo dijo:
...pero no nos explican casi nada en clase y luego de leerme el manual de LPC17xx sigo con bastantes dudas...
Entiendo, te dan mucha teoría y poca práctica.
15/11/2013 #71


¡No me acordé de ese mensaje! Muchísimas gracias, con todo esto ya tengo claro como continuar. Te estoy realmente agradecido cosme.
19/11/2013 #72


Cosmefulanito,
te hago una consulta tengo que convertir un uint32_t en uint8_t, como primer medida tomé tu función obviamente no me funcionó

Código:
void convertir_digitos_u32_serie(uint8_t digitos[],uint32_t value)
{	  
	  uint8_t aux;
    
    for(aux=4;aux>0;aux--)
        {
        digitos[aux]=(value%10)+0x30;
        value=(int)(value/10);
        }
        
    digitos[0]=value+0x30;

}
Después probe directamente así:
Código:
UINT32 value;
UINT8 result[4];

result[0] = (value & 0x000000ff);
result[1] = (value & 0x0000ff00) >> 8;
result[2] = (value & 0x00ff0000) >> 16;
result[3] = (value & 0xff000000) >> 24;
tampoco funcionó, es para presentar el dato en pantalla anteriormente ya había tenido que pasar de uint16 a uint8, pero eso funcionó correctamente.

Gracias como siempre
20/11/2013 #73

Avatar de cosmefulanito04

La función no pasa de u32 a u8 .

La función pasa de u32 a String, es decir un vector u8 (o char según corresponda). Ahora, no recuerdo pasar u32, si u16, por lo tanto de esa función hay que corregir la cantidad de dígitos:

Código PHP:
void convertir_digitos_u32_serie(uint8_t digitos[],uint32_t value)
{      
      
uint8_t aux;
    
    for(
aux=9;aux>0;aux--)
        {
        
digitos[aux]=(value%10)+0x30;
        
value=(int)(value/10);
        }
        
    
digitos[0]=value+0x30;


Entonces ahora el vector "digitos" deberá ser de 10 elementos.

Ejemplo:

Código PHP:

u8 vector_digitos
[10];

convertir_digitos_u32_serie(vector_digitos,32000);

for(
cont=10;cont>0;cont--)
  
envia_dato_uart0(vector_digitos[cont-1]); 
Luego de convertir el u32 a string, por el puerto serie saldrán los siguientes caracteres:

Salida uart dijo:
'0'-'0'-'0'-'0'-'0'-'3'-'2'-'0'-'0'-'0'
Alternativa Ansi-C => sprintf.
28/11/2013 #74


Cosmefulanito, consulta, vos pudiste probar multiples canales de ADC en simultáneo?
Estoy armando un código que trabaje en modo DMA y otro en modo Burst, para ver si puedo eliminar la variación que tengo en la medida. pero cuando compilo acusa este error
ERROR: L6218E: UNDEFINED SYMBOL. Antes ya me pasó y era un tema de librerías pero ahora no lo puedo solucionar.

Gracias
28/11/2013 #75

Avatar de cosmefulanito04

No probé, solo usé un canal en las pruebas.

Tené en cuenta que al trabajar con un multiplexo analógico, solo podes convertir un canal a la vez e incluso en muchos uC c/vez que cambias de canal, necesitas hacer una conversión de descarte.
29/11/2013 #76


Estuve leyendo que en el modo Burst, convierte todos los canales a la vez y así podes obtener las mediciones de las entradas a medir, sin tener que multiplexar. Lo estoy probando, ni bien salga, comento.
30/11/2013 #77


Cosmefulanito una consultoa, etuve volviendo a tu ejemplo ADC-Parte 6, modifiqué la parte de conversión porque quería mostrar un promedio del dato para que varíe menos. Esto me quedó

Código:
case MOSTRAR_CONVERSION_ADC:
					{
						if(convertir_adc(0,125,&valor_adc)>0)	//Convierto en el canal 0, con un pre-escaler=125
						{	valor_adc=valor_adc*0.805860; 
							contador=contador + 1;
						    valoradc=(valor_adc + valoradc)/contador;
							
							if (contador==8)
								{ enviar_string_uart0(" Conversion= \n");
								 envia_u16_string_uart0(valoradc);
								 contador=0;
								}
							valor_adc=0;
						}
					}
El valo 0.805860 es para que cuando le conecte 3300mv me muestre 3300 en lugar de 4095. el tema está en que ahora que le hice el promediado, el valor queda casi constante con una pila de 1.5v. Pero el valor que me muestra es 235. No entiendo porque jaja. No se si se está perdiendo la cuenta o si estoy calculando mientras convierte. Está bien lo que estoy planteando?

gracias
30/11/2013 #78

Avatar de cosmefulanito04

Necesitas usar un vector de por ej. 16 elementos y hacer una cola circular para un promedio.

Después te subo algo que te puede ser útil.
30/11/2013 #79


gracias capo!!

Estoy "debbugueando" para ver porque me muestre ese valor tan errado.
01/12/2013 #80

Avatar de cosmefulanito04

marcos0007 dijo: Ver Mensaje
gracias capo!!

Estoy "debbugueando" para ver porque me muestre ese valor tan errado.
Si no me equivoco le erras en dos cosas:
  • La variable contador no la limitas, esto implicará desborde en algún punto.
  • El promedio siempre lo haces con dos valores, el actual y la sumatoria ya promediada con los valores viejos, por lo tanto en vez de dividir por la variable contador, deberías dividir por 2.

Lo que deberías hacer es un promedio móvil, ejemplo:

Código PHP:
#define MUESTRAS_MAX 16

int main()
{
  ...
  
//--------- Vectores de muestreo --------------//
  
u16 muestra_adc[MUESTRAS_MAX];
  
u8 indice_muestra_adc=0;
  
  
u32 promedio_movil=0;
  
//--------- Vectores de muestreo --------------//
  
....
  
iniciar_adc(0,0);    //Inicio el ADC en el canal 0 sin offset
  // Inicializo timers, puerto serie, etc
  
....
 
  while(
1)
    {
      
      if(
flag_timer0//Configuro el timer0 (o cualquier timer disponible), para que c/cierto tiempo tome una muestra del ADC.
        
{
           if(
convertir_adc(0,250,&valor_adc)>0)    //Convierto en el canal 0, con un pre-escaler=250 
            

               
muestra_adc[indice_muestra_adc]=valor_adc;
               
indice_muestra_adc++;
               if(
indice_muestra_adc==MUESTRAS_MAX)
                 
indice_muestra_adc=0;
            } 
         }
        
         if(
flag_timer1//Configuro el timer1 (o cualquier timer disponible), para que c/cierto tiempo envíe el promedio móvil por uart (ej. c/1 seg).
           
{
              
promediar_datos(muestra_adc,&promedio_movil); //Funcion que promedia las muestras
              
enviar_string_uart0(" Conversion promediada= \n"); 
              
envia_u16_string_uart0((u16)(promedio_movil));
           }
        
    }

La función promedio móvil es simplemento un for:

Código PHP:
void promediar_datos(u16 muestras[],unsigned long int *promedio_movil)
{
    
u8 cont;
    
    *
promedio_movil=0;
    for(
cont=0;cont<MUESTRAS_MAX;cont++)
        *
promedio_movil+=muestras[cont];
                                    
    *
promedio_movil=(u16)(*promedio_movil/MUESTRAS_MAX);

¿Tienes una mejor respuesta a este tema? ¿Quieres hacerle una pregunta a nuestra comunidad y sus expertos? Registrate

Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos

Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO ©2011, Crawlability, Inc.