PicManía by RedRaven
 

Búsqueda personalizada

El Rincón del CCS C - Parte

 

  El lenguaje C es el que uso por defecto para el 90% de mis programas. Aquí os muestro algunos ejemplos de cómo hacer cosas con este idioma. Todos ejemplos que se muestran en esta sección se han realizado usando el PCW PICC de CCS (Veriones 3.242 a 4.096 según depende)

Más CCS C : 1 2 3 4
Índice Parcial:
 


Leer y Escribir en la EEPROM interna del PIC variables int 16 bits (2 bytes)

 

  • Empecemos por el principio: read_eeprom(address) y write_eeprom(address, byte) trabajan con int8, un byte de 8 bits. Para leer y escribir int16, dos bytes de 8 bits cada uno, hay que fabricarse unas funciones "puente" de este estilo:

  Funciones read_eeprom(address) y write_eeprom(address, byte)  
  void write_eeprom_16bits(int address, long* val){
  int pLow, pHigh;
  pLow = val;
  pHigh = val>>8;
  write_eeprom(address,pHigh);
  delay_ms(12);
  ++address;
  write_eeprom(address,plow);
  delay_ms(12);
}

long read_eeprom_16bits(int address){
  int pLow, pHigh;
  long result;
  pHigh = read_eeprom(address);
  ++address;
  pLow = read_eeprom(address);
  result=(pHigh<<8);
  result+=pLow;
  return result;
}
 
     
 
Con ellas he escrito un programa de Test que en el reset guarda un valor de 16 bits en la variable x, llama a la función write_eeprom_16bits y se queda a la espera "escuchando" la RS232 ...

al recibir la tecla 'r' realiza la funciona inversa, lee sobre la variable y, también de 16 bits, desde la misma dirección en la que antes escribimos con read_eeprom_16bits y monitoriza el resultado.

Todo este recorrido esta salpicado de printf's para poder ver todo el proceso paso a paso:
 
 
El programa completo tal como quedó para poder monitorizar todos los pasos es:
 
 
  eeprom_16bits plus rs232  
  #include <18f4550.h>
#fuses HS,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOPBADEN, NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

char Keypress = 0x00;
char Command = 0x00;

long x,y;

#int_rda
  void serial_isr() {

  Keypress=0x00;
  if(kbhit()){
    Keypress=getc();
    if(Keypress!=0x00){
      if(Keypress=='r'){
        Command=Keypress;
      }
      putchar(keypress);
      keypress=0x00;
    }
  }
}

void write_eeprom_16bits(int address, long* val){

  int pLow, pHigh;
  printf("write_eeprom_16bits( address=%u, val=%lx)\r\n",address,val);
  pLow = val;
  pHigh = val>>8;
  printf("write_eeprom( address=%u, val=%x)\r\n",address,pHigh);
  write_eeprom(address,pHigh);
  delay_ms(12);
  ++address;
  printf("write_eeprom( address=%u, val=%x)\r\n",address,pLow);
  write_eeprom(address,plow);
  delay_ms(12);
}

long read_eeprom_16bits(int address){

  int pLow, pHigh;
  long result;
  printf("read_eeprom_16bits( address=%u)\r\n",address);
  pHigh = read_eeprom(address);
  printf("read_eeprom( address=%u) = %x\r\n",address,pHigh);
  ++address;
  pLow = read_eeprom(address);
  printf("read_eeprom( address=%u) = %x\r\n",address,pLow);
  result=(pHigh<<8);
  result+=pLow;
  return result;
}


void main(){

  disable_interrupts(global);

  setup_adc_ports(NO_ANALOGS);
  setup_adc(ADC_OFF);
  setup_spi(FALSE);
  setup_psp(PSP_DISABLED);
  setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
  setup_timer_0(RTCC_OFF);
  setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
  setup_timer_2(T2_DISABLED,0,1);
  setup_timer_3(T3_DISABLED);
  setup_comparator(NC_NC_NC_NC);
  setup_vref(FALSE);
  port_b_pullups(FALSE);
  set_tris_e(0b00010000);
  set_tris_c(0b10000000);

  delay_ms(1000);

  output_High(PIN_E0);
  output_High(PIN_E1);
  output_High(PIN_E2);
  printf("\r\n");
  printf("18F4550 in RRBOARAD2\r\n");
  printf("Test EEPROM with 18 bits\r\n\n");
  delay_ms(500);
  output_Low(PIN_E0);
  output_Low(PIN_E1);
  output_Low(PIN_E2);

  Command=0x00;
  enable_interrupts(int_rda);
  enable_interrupts(global);

  x=0x1f2f;
  y=0;

  printf("initial 16 bits x = %lx (%lu), y = %lx (%lu)\r\n",x,x,y,y);
  write_eeprom_16bits(0,x);
  printf("\r\n");

  while(TRUE) {
    if(Command=='r'){
      Command=0x00;
      printf("\r\n\n");
      y=read_eeprom_16bits(0);
      printf("final 16 bits x = %lx (%lu), y = %lx (%lu)\r\n",x,x,y,y);
    }
  }
}
 
     
 

 


Funciones especiales para Leer y Escribir la EEPROM interna del PIC

  

  • Las funciones estándar para leer y escribir en la EEPROM interna del CCS C son   read_eeprom(address) y write_eeprom(address, byte) que trabajan con int8, un byte de 8 bits. Para leer y escribir otros tipos de variables, como int1, un bit, int16, dos bytes de 8 bits cada uno, o int32 y float, 4 bytes de 8 bits, hay que fabricarse unas funciones "puente".
  • En la librería Lib_Int_EEPROM se definen las funciones necesarias para realizar estos cometidos:
     
    • void write_int1_eeprom(address, int8 bitPosition, int1 data)
    • int1 read_int1_eeprom(address, int8 bitPosition)
    • void write_int16_eeprom(address, int16 data)
    • int16 read_int16_eeprom(address)
    • void write_int32_eeprom(address, int32 data)
    • int32 read_int32_eeprom(address)
    • void write_float_eeprom(address, float data)
    • float read_float_eeprom(address)
 
 
Lib_Int_EEPROM
 
 
  ////////////////////////////////////////////////////////////////////////////////
//// lib_int_eeprom.c ////
////////////////////////////////////////////////////////////////////////////////
//// ////
//// void write_int1_eeprom(address, int8 bitPosition, int1 data) ////
//// Call to write one bit of data ////
//// ////
//// int1 read_int1_eeprom(address, int8 bitPosition) ////
//// Call to read one bit of data ////
//// ////
//// void write_int16_eeprom(address, int16 data) ////
//// Call to write a 16 bit integer ////
//// ////
//// int16 read_int16_eeprom(address) ////
//// Call to read a 16 bit integer ////
//// ////
//// void write_int32_eeprom(address, int32 data) ////
//// Call to write a 32 bit integer ////
//// ////
//// int32 read_int32_eeprom(address) ////
//// Call to read a 32 bit integer ////
//// ////
//// void write_float_eeprom(address, float data) ////
//// Call to write a floating point number ////
//// ////
//// float read_float_eeprom(address) ////
//// Call to read a floating point number ////
//// ////
////////////////////////////////////////////////////////////////////////////////

#ifndef INTERNAL_EEPROM_UTILITIES
#define INTERNAL_EEPROM_UTILITIES

// Used to adjust the address range
#ifndef INT_EEPROM_ADDRESS
#define INT_EEPROM_ADDRESS int8
#endif

////////////////////////////////////////////////////////////////////////////////
//// Internal EEPROM Functions
////////////////////////////////////////////////////////////////////////////////

// Purpose: Write one bit to internal eeprom --------------------------------
// Inputs: 1) An eeprom address
// 2) The bit position (LSB == 0)
// 3) The bit to write
// Outputs: None

void write_int1_eeprom(INT_EEPROM_ADDRESS address, int8 bitPosition, int1 data){

  int8 stored_data;

  stored_data = read_eeprom(address);

  if(data){
    bit_set(stored_data, bitPosition);
  }else{
    bit_clear(stored_data, bitPosition);
  }
  write_eeprom(address, stored_data);
}


// Purpose: Read one bit from internal eeprom -------------------------------
// Inputs: 1) An eeprom address
// 2) The bit position (LSB == 0)
// Outputs: The bit read from internal eeprom

int1 read_int1_eeprom(INT_EEPROM_ADDRESS address, int8 bitPosition){

  return bit_test(read_eeprom(address), bitPosition);
}


// Purpose: Write a 16 bit number to internal eeprom ------------------------
// Inputs: 1) An eeprom address
// 2) The 16 bit number to write to internal eeprom
// Outputs: None

void write_int16_eeprom(INT_EEPROM_ADDRESS address, int16 data){

  int8 i;

  for(i = 0; i < 2; ++i){
    write_eeprom(address + i,*(&data + i));
  }
}


// Purpose: Read a 16 bit number from internal eeprom -----------------------
// Inputs: An eeprom address
// Outputs: The 16 bit number read from internal eeprom

int16 read_int16_eeprom(INT_EEPROM_ADDRESS address){

  int8 i;
  int16 data;

  for(i = 0; i < 2; ++i){
    *(&data + i) = read_eeprom(address + i);
  }
  return(data);
}


// Purpose: Write a 32 bit integer to internal eeprom -----------------------
// Inputs: 1) An eeprom address
// 2) The 32 bit number to write to internal eeprom
// Outputs: None

void write_int32_eeprom(INT_EEPROM_ADDRESS address, int32 data){

  int8 i;

  for(i = 0; i < 4; ++i){
    write_eeprom(address + i,*(&data + i));
  }
}


// Purpose: Read a 32 bit integer from internal eeprom ----------------------
// Inputs: An eeprom address
// Outputs: The 32 bit integer read from internal eeprom

  int32 read_int32_eeprom(INT_EEPROM_ADDRESS address){

  int8 i;
  int32 data;

  for(i = 0; i < 4; ++i){
    *(&data + i) = read_eeprom(address + i);
  }
  return data;
}


// Purpose: Write a floating point number to internal eeprom ----------------
// Inputs: 1) An eeprom address. Four eeprom locations will be used.
// 2) The floating point number to write to internal eeprom
// Outputs: None

#separate
void write_float_eeprom(INT_EEPROM_ADDRESS address, float data){

  int8 i;

  for(i = 0; i < 4; ++i){
    write_eeprom(address + i,*(&data + i));
  }
}


// Purpose: Read a floating point number from internal eeprom ---------------
// Inputs: An eeprom address
// Outputs: The floating point number read from the internal eeprom

#separate
float read_float_eeprom(INT_EEPROM_ADDRESS address){

  int8 i;
  float data;

  for(i = 0; i < 4; ++i){
    *(&data + i) = read_eeprom(address + i);
  }
  return data;
}

#endif
 
 
  Descargar lib_int_eeprom.c  
 


 

Rutina de conversión de Números Arábigos a Números romanos.
Para que nuestro PIC hable en Latín Clásico.
 

Cita. In illio tempor Caesare dixit ad milites suos: ¡Milites! Si deambulandun per la via publicam vieribus mulieribus quid dixieribus "... morenus ...". Non facendum caso, putaverant sunt. Fin de la cita.

Fórmula Magistral: Tómese un tercio de RRBOARD2, añádasele otro tercio de DS1307 desatado y por último mézclese con una pizca de Flex_LCD y tendremos un Reloj. (Sí, eso, un simple reloj, nada mas que un reloj, un reloj a secas, como millones de relojes que hay por el mundo)

Pero si además le construimos una rutina que sea capaz de convertir de Números Arábigos a Números Romanos tendremos exactamente lo que dice el PIC cuando se conecta a la corriente: Romanus Horae ad RR2 targetatis..
 

 
  Titulo  
  ------

const int8 Numeros[] = { 1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000};
char H_in_RomanusNumericum[12];
char M_in_RomanusNumericum[12];
char S_in_RomanusNumericum[12];

------

void dec_to_roman(int8 LI, char* ptr){

  char tmp[12];
  char* ptmp = (char*) tmp;
  strcpy(ptr,"");
  // transformo de la tabla Arábiga a la Románica Latinitatis
  // { 1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000};
  // { 'I', 'IV', 'V', 'IX', 'X', 'XL', 'L', 'XC', 'C', 'CD', 'D', 'CM', 'M'};
  for(i=12;i!=255;i--){
    while(LI >= Numeros[i]){
      LI = LI - Numeros[i];
      Switch(i){
        case 0:
           strcpy(ptmp,"I\0");
           break;
        case 1:
           strcpy(ptmp,"IV\0");
           break;
        case 2:
           strcpy(ptmp,"V\0");
           break;
        case 3:
           strcpy(ptmp,"IX\0");
           break;
        case 4:
           strcpy(ptmp,"X\0");
           break;
        case 5:
           strcpy(ptmp,"XL\0");
           break;
        case 6:
           strcpy(ptmp,"L\0");
           break;
        case 7:
           strcpy(ptmp,"XC\0");
           break;
        case 8:
           strcpy(ptmp,"C\0");
           break;
        case 9:
           strcpy(ptmp,"CD\0");
           break;
        case 10:
           strcpy(ptmp,"D\0");
           break;
        case 11:
           strcpy(ptmp,"CM\0");
           break;
        case 12:
           strcpy(ptmp,"M\0");
           break;
      }
      ptr=strcat(ptr,ptmp);
    }
  }
}

-----

ds1307_get_time(hrs,min,sec);
dec_to_roman(hrs, (char*) H_in_RomanusNumericum);
dec_to_roman(min, (char*) M_in_RomanusNumericum);
dec_to_roman(sec, (char*) S_in_RomanusNumericum);

   
 
 

 

 
 
Y para que veáis que esta rutina funciona correctamente qué mejor que mis dumps y fotos ...
 


 


 

Manejando un Array de bits (simulado en CCS C que no lo implementa) I
Para que nuestro PIC no desperdicie memoria.
 
He montado una estructura que puede manejar un Array de 8, 16 o 32 bits para no complicarlo demasiado. Con igual pretensión no le he colocado tampoco el control de errores por parámetros incongruentes (como intentar leer el bit nº 12 habiendo definido un array de sólo 8 bits)

Para empezar defino el tamaño del array a utilizar mediantes los defines (Comentando o descomentando el que necesito)

#define bits_array_8
//#define bits_array_16
//#define bits_array_32


En función de estos defines creo en la RAM el tipo de variable correspondiente:

#ifdef bits_array_8
   int8  bits_array=0;
#endif

#ifdef bits_array_16
   int16 bits_array=0;
#endif
#ifdef bits_array_32
   int32 bits_array=0;
#endif


Al final lo que tengo es una variable llamada bits_array con el tamaño necesario.

Y ahora me defino dos funciones, una para poner a un valor dado el bit que desee y otra para leerlo:

int1 get_array_bit(int8 pbit){
   int1 r;
   r=bit_test(bits_array,pbit);
   return r;
}

int1 set_array_bit(int1 vbit, int8 pbit){
   int1 r;
   r=bit_test(bits_array,pbit);
   if(vbit==0)
      bit_clear(bits_array,pbit);
   else
      bit_set(bits_array,pbit);
   return r;
}


De forma que get_array_bit me devuelve el valor del bit en la posición pbit, que al ser un parámetro puede ser incluido en un bucle for{] por ejemplo.

Y set_array_bit en la que coloco al valor vbit en la posición pbit; esta función me devuelve además el valor anterior que tenía el bit de la posición pbit, asi puedo comparar, si lo deseo, si el bit ha cambiado o no. Al igual que en la función anterior el parámetro puede ser incluido en un bucle for{].

Lo he probado y funciona perfectamente.  Mr. Green

         if(isdigit(Command)){             // Bit
            xbit=Command-'0';
            set_array_bit(1,xbit);
            printf("Despues de Poner : %u %x\r\n",get_array_bit(xbit),bits_array);
         }

 

 
 
Manejando un Array de bits (simulado en CCS C que no lo implementa) I
Para que nuestro PIC no desperdicie memoria.
 
Tras una propuesta del amigo Manolo Nocturno he modificado las funciones anteriores y ya están funcionando de forma mas rápida y elegante.

El asunto está en calcular el bit a manejar mediante operaciones posicion/8 para obtener la parte entera o byte donde está alojado el bit a utilizar y posicion%8 para obtener el resto o posición del bit dentro del byte. Como estos cálculos no parecen funcionar dentro, embebidas, de las mismas instrucciones de bit_set, bit_clear o bit_test lo único que he hecho ha sido hacer estas operaciones fuera, forzándolas a devolver el resultado como int8 especificándolo así y después utilizar las funciones tal cual están.

int1 get_array_bit(int8 pbit){

   int1 r;
   int8 a,b;
   a = (int8) pbit/8;
   b = (int8) pbit%8;
   r=bit_test(bits_array[a],b);
   return r;
}

int1 set_array_bit(int1 vbit, int8 pbit){

   int1 r;
   int8 a,b;
   a = (int8) pbit/8;
   b = (int8) pbit%8;
   r=bit_test(bits_array[a],b);
   bit_clear(bits_array[a],b);
   if(vbit==1) bit_set(bits_array[a],b);
   return r;
}


Para declarar la variable Array de bytes (los contenedores de los bits) he utilizado la declaración siguiente:

#define bytes_for_bits 5                     // 5 * 8 = 40 bits (0..39)
int8 bits_array[bytes_for_bits];            // Array de 40 bits dividido en bytes_for_bits bytes


Y para poder monitorizar todos los bits dentro de bits_array me he contruido una función que me convierte en string de bits ASCII el byte que le envíe, devolviéndome un puntero a dicho string:

char* int8_to_bits_string(int8 val){
   char s[]="00000000";
   char* ptr;
   int8 i;
   for(i=0;i<8;i++) s[ i ]=bit_test(val,i)+'0';
   s[8]='\0';
   ptr=&s[0];
   return ptr;
}


Y para comprobar que todo va como debe ir me he construido en el main() un modo de ir poniendo a 1 cada uno de los bits cada vez que le pulso algo a través del canal serie, y con cada pulsación me muestra el estado de los cuarenta bits. Y cuando llega al bit 39 se reinicializa el índice comenzando de nuevo desde el 0 pero si está ya puesto a 1 lo coloca ahora a 0.

El trozo de código del main es:

         if(Command=='1'){                 // Next Bit a 1 si 0 ó a 0 si 1
            if(get_array_bit(nextbit)==0)
               set_array_bit(1,nextbit);
            else
               set_array_bit(0,nextbit);
            printf(">Set bit %2u ",nextbit);
            for(i=0;i<bytes_for_bits;i++){
               ptr=int8_to_bits_string(bits_array[ i ]);
               strcpy(s,ptr);
               printf("%s",s);
            }
            printf("\r\n");
            if(++nextbit==bytes_for_bits * 8 ) nextbit=0;
         }


Y como todo está construido alrededor del define bytes_for_bits podemos cambiarle el valor y montar el número de bits que queramos, siempre múltiplo de 8.
 

 
 
 

 



Nota: Esta página Web esta repleta de imágenes, textos, logotipos y demás material extraídos de los mas variados medios de los que no soy ni autor ni depositario de los correspondientes derechos de autor, uso y/o reproducción. Si Ud. es depositario de dichos derechos y desea que el material correspondiente sea eliminado de esta Web no dude en ponerse en contacto conmigo mediante e-mail y será inmediatamente retirado. Gracias.
 
Visitas
Totales : 60185 Hoy: 3 Activas: 1 Vistas: 60185

Esta página fue modificada el 07-08-2010 15:42:21

           
 DmSoft WAMP Escribir Unreal