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

Temas similares

18/12/2011 #1


ayuda enviar datos al pic18f4550 por usb
hola que tal buen dia hace dias publique en este foro una pregunta de como podia hacer un teclado con un pic gracias a un usuario me dijo algo sobre el chip 18f4550, despues de investigar por largas horas, por fin tengo mi teclado funcionando gracias al ejemplo de css, este es el codigo en c

Código:
#include <18F4550.h>
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)
#DEFINE USB_HID_DEVICE  TRUE
#define USB_EP1_TX_ENABLE  USB_ENABLE_INTERRUPT   //turn on EP1 for IN bulk/interrupt transfers
#define USB_EP1_TX_SIZE 8
#define USB_EP1_RX_ENABLE  USB_ENABLE_INTERRUPT   //turn on EP1 for IN bulk/interrupt transfers
#define USB_EP1_RX_SIZE 8
#include <pic18_usb.h>
#include <usb_kbd_HID.h>  //USB Configuration and Device descriptors for this UBS device
#include <usb.c>                                 //handles usb setup tokens and get descriptor reports
#include <ctype.h>
#use FAST_io(b)

/////////////////////////////////////////////////////////////////////////////
//
// Definiciones para facil manejo en la programaciòn.
// Se asigna el un nombre a un determinado pin, y se 
// y se asignan nombres para dos instrucciones del
// compilador.
/////////////////////////////////////////////////////////////////////////////

#define LED1    PIN_E0
#define LED2    PIN_E1
#define LED_ON  output_high
#define LED_OFF output_low

//#define PIN_SOURCE PIN_B1

/////////////////////////////////////////////////////////////////////////////
//
// RAM
// Variables nescesarias para el funcionamiento del programa
/////////////////////////////////////////////////////////////////////////////

//int8 connected; 
int8 enumerated;
int8 rx_msg[USB_EP1_RX_SIZE];
int8 tx_msg[8]={2,0,0,0,0,0,0,0};
//char NextChar='0';
int1 hay_dato=0; // Variable Binaria que se utiliza para indicar que se ah presionado una tecla
int8 dato; // Variable que en la cual se guardaran los datos a mandar a la PC

/////////////////////////////////////////////////////////////////////////////
//
// usb_debug_task()
//
// When called periodically, displays debugging information over serial
// to display enumeration and connection states.  Also lights LED2 and LED3
// based upon enumeration and connection status.
//
/////////////////////////////////////////////////////////////////////////////

void usb_debug_task(void) {

   enumerated=usb_enumerated();

   if(enumerated){
      LED_ON(LED1);
                 }
   else{
      LED_OFF(LED1);
       }
}

/////////////////////////////////////////////////////////////////////////////
//
// usb_keyboard_task()
//
// Sends a packet of keyboard data.  The protocol was specified in the HID
// report descriptor (see usb_desc_kbmouse.h), and is:
//     tx_msg[0]   = HID report id (2)
//     tx_msg[1]   = modifier (an 8bit bitmap of shift, tab, alt keypress)
//     tx_msg[2]   = const 0
//     tx_msg[3:7] = an array of held down keys.  a=4, b=5, etc.
//                   if msg[2:7]={0} then no keys are held down
//
//     rx_msg[1] = HID report id (2)
//     rx_msg[0] = 5bit bitmap of led status
//
/////////////////////////////////////////////////////////////////////////////

void usb_keyboard_task(void) {
   //static char Char_Tx;
   disable_interrupts(global); 
   if(hay_dato==1){
      hay_dato=0;
      tx_msg[3]=dato;
      usb_put_packet(1,tx_msg,sizeof(tx_msg),USB_DTS_TOGGLE);
      delay_ms(10);
                  }
   else{

      tx_msg[3]=0;
      usb_put_packet(1,tx_msg,sizeof(tx_msg),USB_DTS_TOGGLE);
      delay_ms(5);
       }
   enable_interrupts(global);
}


/////////////////////////////////////////////////////////////////////////////
//
// usb_rx_task()
//
// Listens to EP1 for any incoming packets.  The only report ID that is
// configurd to send us data is 2 (keyboard LED status, see above)
//
/////////////////////////////////////////////////////////////////////////////

void usb_rx_task(void){

   if (usb_kbhit(1)){
      usb_get_packet(1, rx_msg, sizeof(rx_msg));
   }
}

/////////////////////////////////////////////////////////////////////////////
//
// recibe por interrupción ext
//
/////////////////////////////////////////////////////////////////////////////

#INT_RB
void ext_handler(void){
      
    //RB 7 Detectado
    if(input(pin_B7))
    {
      if(input(pin_B7)  && input(pin_B3) )
      {
      hay_dato=1;
      dato=0x27; // se introdujo 0
      LED_ON(LED2);
      }
      else if(input(pin_B7) && input(pin_B2) )
      {
      
       hay_dato=1;
       dato=0x1E; // se introdujo 1
      LED_OFF(LED2);
      }
      else if(input(pin_B7)  && input(pin_B1) )
      {
      hay_dato=1;
      dato=0x1F; // se introdujo 2
      LED_ON(LED2);
      }
      else if(input(pin_B7) && input(pin_B0))
  
      {
      hay_dato=1;
      dato=0x20;// se introdujo 3
      LED_OFF(LED2);
      }
      
      
   } // Fin IF
    
    //RB 6 Detectado
    if(input(pin_B6))
    {
      if(input(pin_B6) && input(pin_B3))
      {
      hay_dato=1;
      dato=0x21; // se introdujo 4
      LED_ON(LED2); 
      }
      else if(input(pin_B6)  && input(pin_B2) )
      {
      hay_dato=1;
      dato=0x22; // se introdujo 5
      LED_OFF(LED2);    
      }
      else if(input(pin_B6) && input(pin_B1) )
      {
      hay_dato=1;
      dato=0x23; // se introdujo 6
      LED_ON(LED2);     
      }
      else if(input(pin_B6)  && input(pin_B0))
      {
      hay_dato=1;
      dato=0x24; // se introdujo 7
      LED_OFF(LED2);
      }
      
    } // Fin IF  
    
    //RB 5 Detectado
       if(input(pin_B5))
                          {
      if(input(pin_B5) && input(pin_B3))
      {
      hay_dato=1;
      dato=0x25; // se introdujo 8
      LED_ON(LED2); 
      }
      else if(input(pin_B5)&& input(pin_B2))
      {
      hay_dato=1;
      dato=0x26;// se introdujo 9
      LED_OFF(LED2); 
      }
      else if (input(pin_B5) && input(pin_B1) )
      {
      hay_dato=1;
      dato=0x52; // se introdujo Flecha arriba
      LED_ON(LED2);
      }
     else if(input(pin_B5)&& input(pin_B0))
      {
      hay_dato=1;
      dato=0x51; // se introdujo Flecha Abajo
      LED_OFF(LED2); 
      }
      
    } // Fin IF  
 
   
   
    //RB 4 Detectado
    if(input(pin_B4))
    {
       
     if(input(pin_B4) && input(pin_B3))
      {
      hay_dato=1;
      dato=0x4F; // se introdujo Flecha derecha
      LED_ON(LED2); 
      }
      else if(input(pin_B4) && input(pin_B2))
      {
      hay_dato=1;
      dato=0x50; // se introdujo Flecha Izquierda
      LED_OFF(LED2); 
      }
      else if (input(pin_B4) && input(pin_B1))
      {
      hay_dato=1;
      dato=0x58; // se introdujo Enter
      LED_ON(LED2);
      }
      else if(input(pin_B4) && input(pin_B0))
      {
      hay_dato=1;
      dato=0x2A; // Se introdujo Borrar
      LED_OFF(LED2);
      }
      
    } // Fin IF  

}

void main() {
   hay_dato=0; // Inicializamos a cero
   delay_ms(500); // Retardo de 500 milisegundos
   LED_OFF(LED1); // Apagamos el led que indicarà que la PC ah enumerado nuestro dispositivo
   LED_OFF(LED2); // Este led es opcional solo es para indicar que si esta entrando a las interrupciones
   usb_init_cs(); // Esta funcòn es nececsaria para inicializar la comunicaciòn USB
   set_tris_b(0xF0); // Asignamos como salidas RB0,RB1,RB2,RB3 y como entradas a RB4,RB5,RB6,RB7
   SET_TRIS_D( 0xFF ); // Asignamos como entadas al puerto D
   output_b(0); // Ponemos en cero el puerto B
   output_d(0); // Ponemos en cero el puerto D
   port_b_pullups (FALSE); // Deshabilitamos las resistencias de Pull Up internas del puerto B
   enable_interrupts(INT_RB); //Habilitamos las interrupciones por cambio de estado en RB4 RB5 RB6 RB7.
   enable_interrupts(global); //Habilitamos las interrupciones 
   
 while (TRUE)  //Ciclo infinito
          {
      usb_task();   // Funcion de inicio de USB
      usb_debug_task(); // Funcion de inicio de USB

      if (usb_enumerated()) //Si el Host ah enumerado el dispositivo entrara a esta condicion infinita
          {
         usb_keyboard_task(); // Esta funciion es la que manda el dato a la PC
         usb_rx_task(); // Esta funcion es para recibir informacion de la PC
          
          // Comenzamos a recorrer un bit por las salidas RB0 -> RB3 hasta que una tecla sea oprimida actuara la interrupcion
          // y preguntamos por las teclas que no estan dentro del teclado matricial ya que estas no entraran en las interrupciones.
         output_bit( PIN_B3, 1);
           if (input(pin_D7)) // 
         {
         hay_dato=1;
         dato=0x0A; // Se introdujo Menu
         LED_ON(LED2);
         }//FIN IF
             
         
          delay_ms(20);
          output_bit( PIN_B3, 0);
          output_bit( PIN_B2, 1);
           if (input(pin_D6)) // 
         {
         hay_dato=1;
         dato=0x4B; // Se introdujo PAGE UP
         LED_OFF(LED2);
         }//FIN IF
          delay_ms(20);
          output_bit( PIN_B2, 0);
          output_bit( PIN_B1, 1);
          if (input(pin_D5)) // 
         {
         hay_dato=1;
         dato=0x4E; // Se introdujo PAGE DOWN
         LED_ON(LED2);
         }//FIN IF
          delay_ms(20);
          output_bit( PIN_B1, 0);
          output_bit( PIN_B0, 1);
            if (input(pin_D4)) // 
         {
         hay_dato=1;
         dato=0x11; // Se introdujo N
         LED_OFF(LED2);
         }//FIN IF
          
          delay_ms(20);
          output_bit( PIN_B0, 0);
          if (input(pin_D3)) // 
         {
         hay_dato=1;
         dato=0x2C; // Se introdujo space
         LED_OFF(LED2);
         }//FIN IF
            
                
                            } // Fin IF
   } // Fin While
} // Fin programa Principal
todo bien es una matriz de botones, ahora mi prgunta por la cual vuelvo a recurrir a esta gran comunidad, como puedo activar un led???, por ejemplo si emulo la pulsacion de la tecla caps lock desde windows(eso es posible con la api de win32), el chip encienda un led bueno no se si me di entender pero aquellos que puedan echarme una ayudita les estare muy agradecido muchas gracias
19/12/2011 #2

Avatar de gcgiron

antoniocaro dijo: Ver Mensaje
hola que tal buen dia hace dias publique en este foro una pregunta de como podia hacer un teclado con un pic gracias a un usuario me dijo algo sobre el chip 18f4550, despues de investigar por largas horas, por fin tengo mi teclado funcionando gracias al ejemplo de css, este es el codigo en c

Código:
#include <18F4550.h>
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)
#DEFINE USB_HID_DEVICE  TRUE
#define USB_EP1_TX_ENABLE  USB_ENABLE_INTERRUPT   //turn on EP1 for IN bulk/interrupt transfers
#define USB_EP1_TX_SIZE 8
#define USB_EP1_RX_ENABLE  USB_ENABLE_INTERRUPT   //turn on EP1 for IN bulk/interrupt transfers
#define USB_EP1_RX_SIZE 8
#include <pic18_usb.h>
#include <usb_kbd_HID.h>  //USB Configuration and Device descriptors for this UBS device
#include <usb.c>                                 //handles usb setup tokens and get descriptor reports
#include <ctype.h>
#use FAST_io(b)
 
/////////////////////////////////////////////////////////////////////////////
//
// Definiciones para facil manejo en la programaciòn.
// Se asigna el un nombre a un determinado pin, y se 
// y se asignan nombres para dos instrucciones del
// compilador.
/////////////////////////////////////////////////////////////////////////////
 
#define LED1    PIN_E0
#define LED2    PIN_E1
#define LED_ON  output_high
#define LED_OFF output_low
 
//#define PIN_SOURCE PIN_B1
 
/////////////////////////////////////////////////////////////////////////////
//
// RAM
// Variables nescesarias para el funcionamiento del programa
/////////////////////////////////////////////////////////////////////////////
 
//int8 connected; 
int8 enumerated;
int8 rx_msg[USB_EP1_RX_SIZE];
int8 tx_msg[8]={2,0,0,0,0,0,0,0};
//char NextChar='0';
int1 hay_dato=0; // Variable Binaria que se utiliza para indicar que se ah presionado una tecla
int8 dato; // Variable que en la cual se guardaran los datos a mandar a la PC
 
/////////////////////////////////////////////////////////////////////////////
//
// usb_debug_task()
//
// When called periodically, displays debugging information over serial
// to display enumeration and connection states.  Also lights LED2 and LED3
// based upon enumeration and connection status.
//
/////////////////////////////////////////////////////////////////////////////
 
void usb_debug_task(void) {
 
   enumerated=usb_enumerated();
 
   if(enumerated){
      LED_ON(LED1);
                 }
   else{
      LED_OFF(LED1);
       }
}
 
/////////////////////////////////////////////////////////////////////////////
//
// usb_keyboard_task()
//
// Sends a packet of keyboard data.  The protocol was specified in the HID
// report descriptor (see usb_desc_kbmouse.h), and is:
//     tx_msg[0]   = HID report id (2)
//     tx_msg[1]   = modifier (an 8bit bitmap of shift, tab, alt keypress)
//     tx_msg[2]   = const 0
//     tx_msg[3:7] = an array of held down keys.  a=4, b=5, etc.
//                   if msg[2:7]={0} then no keys are held down
//
//     rx_msg[1] = HID report id (2)
//     rx_msg[0] = 5bit bitmap of led status
//
/////////////////////////////////////////////////////////////////////////////
 
void usb_keyboard_task(void) {
   //static char Char_Tx;
   disable_interrupts(global); 
   if(hay_dato==1){
      hay_dato=0;
      tx_msg[3]=dato;
      usb_put_packet(1,tx_msg,sizeof(tx_msg),USB_DTS_TOGGLE);
      delay_ms(10);
                  }
   else{
 
      tx_msg[3]=0;
      usb_put_packet(1,tx_msg,sizeof(tx_msg),USB_DTS_TOGGLE);
      delay_ms(5);
       }
   enable_interrupts(global);
}
 
 
/////////////////////////////////////////////////////////////////////////////
//
// usb_rx_task()
//
// Listens to EP1 for any incoming packets.  The only report ID that is
// configurd to send us data is 2 (keyboard LED status, see above)
//
/////////////////////////////////////////////////////////////////////////////
 
void usb_rx_task(void){
 
   if (usb_kbhit(1)){
      usb_get_packet(1, rx_msg, sizeof(rx_msg));
   }
}
 
/////////////////////////////////////////////////////////////////////////////
//
// recibe por interrupción ext
//
/////////////////////////////////////////////////////////////////////////////
 
#INT_RB
void ext_handler(void){
 
    //RB 7 Detectado
    if(input(pin_B7))
    {
      if(input(pin_B7)  && input(pin_B3) )
      {
      hay_dato=1;
      dato=0x27; // se introdujo 0
      LED_ON(LED2);
      }
      else if(input(pin_B7) && input(pin_B2) )
      {
 
       hay_dato=1;
       dato=0x1E; // se introdujo 1
      LED_OFF(LED2);
      }
      else if(input(pin_B7)  && input(pin_B1) )
      {
      hay_dato=1;
      dato=0x1F; // se introdujo 2
      LED_ON(LED2);
      }
      else if(input(pin_B7) && input(pin_B0))
 
      {
      hay_dato=1;
      dato=0x20;// se introdujo 3
      LED_OFF(LED2);
      }
 
 
   } // Fin IF
 
    //RB 6 Detectado
    if(input(pin_B6))
    {
      if(input(pin_B6) && input(pin_B3))
      {
      hay_dato=1;
      dato=0x21; // se introdujo 4
      LED_ON(LED2); 
      }
      else if(input(pin_B6)  && input(pin_B2) )
      {
      hay_dato=1;
      dato=0x22; // se introdujo 5
      LED_OFF(LED2);    
      }
      else if(input(pin_B6) && input(pin_B1) )
      {
      hay_dato=1;
      dato=0x23; // se introdujo 6
      LED_ON(LED2);     
      }
      else if(input(pin_B6)  && input(pin_B0))
      {
      hay_dato=1;
      dato=0x24; // se introdujo 7
      LED_OFF(LED2);
      }
 
    } // Fin IF  
 
    //RB 5 Detectado
       if(input(pin_B5))
                          {
      if(input(pin_B5) && input(pin_B3))
      {
      hay_dato=1;
      dato=0x25; // se introdujo 8
      LED_ON(LED2); 
      }
      else if(input(pin_B5)&& input(pin_B2))
      {
      hay_dato=1;
      dato=0x26;// se introdujo 9
      LED_OFF(LED2); 
      }
      else if (input(pin_B5) && input(pin_B1) )
      {
      hay_dato=1;
      dato=0x52; // se introdujo Flecha arriba
      LED_ON(LED2);
      }
     else if(input(pin_B5)&& input(pin_B0))
      {
      hay_dato=1;
      dato=0x51; // se introdujo Flecha Abajo
      LED_OFF(LED2); 
      }
 
    } // Fin IF  
 
 
 
    //RB 4 Detectado
    if(input(pin_B4))
    {
 
     if(input(pin_B4) && input(pin_B3))
      {
      hay_dato=1;
      dato=0x4F; // se introdujo Flecha derecha
      LED_ON(LED2); 
      }
      else if(input(pin_B4) && input(pin_B2))
      {
      hay_dato=1;
      dato=0x50; // se introdujo Flecha Izquierda
      LED_OFF(LED2); 
      }
      else if (input(pin_B4) && input(pin_B1))
      {
      hay_dato=1;
      dato=0x58; // se introdujo Enter
      LED_ON(LED2);
      }
      else if(input(pin_B4) && input(pin_B0))
      {
      hay_dato=1;
      dato=0x2A; // Se introdujo Borrar
      LED_OFF(LED2);
      }
 
    } // Fin IF  
 
}
 
void main() {
   hay_dato=0; // Inicializamos a cero
   delay_ms(500); // Retardo de 500 milisegundos
   LED_OFF(LED1); // Apagamos el led que indicarà que la PC ah enumerado nuestro dispositivo
   LED_OFF(LED2); // Este led es opcional solo es para indicar que si esta entrando a las interrupciones
   usb_init_cs(); // Esta funcòn es nececsaria para inicializar la comunicaciòn USB
   set_tris_b(0xF0); // Asignamos como salidas RB0,RB1,RB2,RB3 y como entradas a RB4,RB5,RB6,RB7
   SET_TRIS_D( 0xFF ); // Asignamos como entadas al puerto D
   output_b(0); // Ponemos en cero el puerto B
   output_d(0); // Ponemos en cero el puerto D
   port_b_pullups (FALSE); // Deshabilitamos las resistencias de Pull Up internas del puerto B
   enable_interrupts(INT_RB); //Habilitamos las interrupciones por cambio de estado en RB4 RB5 RB6 RB7.
   enable_interrupts(global); //Habilitamos las interrupciones 
 
 while (TRUE)  //Ciclo infinito
          {
      usb_task();   // Funcion de inicio de USB
      usb_debug_task(); // Funcion de inicio de USB
 
      if (usb_enumerated()) //Si el Host ah enumerado el dispositivo entrara a esta condicion infinita
          {
         usb_keyboard_task(); // Esta funciion es la que manda el dato a la PC
         usb_rx_task(); // Esta funcion es para recibir informacion de la PC
 
          // Comenzamos a recorrer un bit por las salidas RB0 -> RB3 hasta que una tecla sea oprimida actuara la interrupcion
          // y preguntamos por las teclas que no estan dentro del teclado matricial ya que estas no entraran en las interrupciones.
         output_bit( PIN_B3, 1);
           if (input(pin_D7)) // 
         {
         hay_dato=1;
         dato=0x0A; // Se introdujo Menu
         LED_ON(LED2);
         }//FIN IF
 
 
          delay_ms(20);
          output_bit( PIN_B3, 0);
          output_bit( PIN_B2, 1);
           if (input(pin_D6)) // 
         {
         hay_dato=1;
         dato=0x4B; // Se introdujo PAGE UP
         LED_OFF(LED2);
         }//FIN IF
          delay_ms(20);
          output_bit( PIN_B2, 0);
          output_bit( PIN_B1, 1);
          if (input(pin_D5)) // 
         {
         hay_dato=1;
         dato=0x4E; // Se introdujo PAGE DOWN
         LED_ON(LED2);
         }//FIN IF
          delay_ms(20);
          output_bit( PIN_B1, 0);
          output_bit( PIN_B0, 1);
            if (input(pin_D4)) // 
         {
         hay_dato=1;
         dato=0x11; // Se introdujo N
         LED_OFF(LED2);
         }//FIN IF
 
          delay_ms(20);
          output_bit( PIN_B0, 0);
          if (input(pin_D3)) // 
         {
         hay_dato=1;
         dato=0x2C; // Se introdujo space
         LED_OFF(LED2);
         }//FIN IF
 
 
                            } // Fin IF
   } // Fin While
} // Fin programa Principal
todo bien es una matriz de botones, ahora mi prgunta por la cual vuelvo a recurrir a esta gran comunidad, como puedo activar un led???, por ejemplo si emulo la pulsacion de la tecla caps lock desde windows(eso es posible con la api de win32), el chip encienda un led bueno no se si me di entender pero aquellos que puedan echarme una ayudita les estare muy agradecido muchas gracias
Pues una posible solución seria creando una interfase en visual basic o con otro lenguaje de programación por medio del módulo USB del PIC.

Aquí en el foro hay unos tutoriales muy buenos de Jonattan Moyano.
20/12/2011 #3


nosaben si existealguna dll para este proposito?? veo que estas funcion usb_rx_task() es para recibir datos del pc, entonces si con una dll puedo hacer eso seria mucho mas facil
01/05/2012 #4


hola que tal me interesa ver tu codigo ya que yo ando en lo mismo y quiero saber precisamente como activar varias cosas por medio del teclado
m podrias pasar tu esquematico para poder simularlo de el pic entradas y salidas usb y todo eso
muchas gracias y estamos en contacto

hola que tal me interesa ver tu codigo ya que yo ando en lo mismo y quiero saber precisamente como activar varias cosas por medio del teclado
m podrias pasar tu esquematico para poder simularlo de el pic entradas y salidas usb y todo eso
muchas gracias y estamos en contacto
03/06/2012 #5


ola amigos esoi comenzando con este pic y el primer programa que devo hacer es un letrero de bienvenida pero en la lcd si alguien me puede ayudar muchas gracias..
03/06/2012 #6


Algunas recomendaciones para principiantes en el foro:


06) En nuestra comunidad NO se aplica la ley del mínimo esfuerzo: "No hacer nada y conseguirlo todo".

08) No coloques tu pregunta en el primer lugar que te aparezca, busca un tema similar a lo que estas consultando.

14) Este es un foro de electrónica, no un sitio para que te resuelvan la tarea de la escuela.

2.7 Los usuarios no pueden revivir o reactivar temas publicando información inútil o sin sentido, o llevando a cabo cualquier otra acción para deliberadamente mantener arriba en el índice del foro dicho tema.

-----------------------

Control de dispositivos a través del módulo USB del PIC18F2550

Saludos...
Respuesta
¿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.