TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: pajaro en 22 de Marzo de 2014, 19:10:25

Título: ::(SOLUCIONADO) :: expansor i2c + lcd420 + pic16 + pic18::
Publicado por: pajaro en 22 de Marzo de 2014, 19:10:25
hola compañeros;

desde hace algun tiempo tengo una libreria para controlar un lcd de 20 x4
con un expansor i2c y asi solo utilizar 2 lineas en el micro.

pero resulta que esta libreria funciona muy bien con la serie pic 16 pero al ponerle un pic18
no funciona nada, no se que esta pasando.
lo he depurado con proteus y lo unico que veo es que no carga el trisc
pero el resto parece hacerlo bien.

creo que necesito mas de dos ojos y una cabeza para encontrar
la solucion al problema.


Código: [Seleccionar]
#include "C:\proyectos\lcd-i2c-pic18f4550\lcd-i2c-pic18F4550.h"
#include <PCF8574.c>
#include <PCF8574_lcd.c>

/*
#int_RTCC
void  RTCC_isr(void)
{

}

#int_TIMER0
void  TIMER0_isr(void)
{

}

#int_EXT
void  EXT_isr(void)
{

}

#int_EXT1
void  EXT1_isr(void)
{

}

#int_EXT2
void  EXT2_isr(void)
{

}

#int_SSP
void  SSP_isr(void)
{

}

*/

void main()
{

   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_CLOCK_DIV_2);
   setup_psp(PSP_DISABLED);
   setup_wdt(WDT_OFF);
   setup_timer_0(RTCC_INTERNAL);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   lcd_init();
/*
   enable_interrupts(INT_RTCC);
   enable_interrupts(INT_TIMER0);
   enable_interrupts(INT_EXT);
   enable_interrupts(INT_EXT1);
   enable_interrupts(INT_EXT2);
   enable_interrupts(INT_SSP);
   enable_interrupts(GLOBAL);
*/
//Setup_Oscillator parameter not selected from Intr Oscillator Config tab

   // TODO: USER CODE!!
   printf("INICIO...");
   printf(lcd_putc,"INICIO...");
   lcd_gotoxy(1,2);
   printf(lcd_putc,"LCD i2c");
}


Código: [Seleccionar]
#include <18F4550.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOBROWNOUT               //No brownout reset
#FUSES BORV20                   //Brownout reset at 2.0V
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOCPD                    //No EE protection
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES IESO                     //Internal External Switch Over mode enabled
#FUSES FCMEN                    //Fail-safe clock monitor enabled
#FUSES PBADEN                   //PORTB pins are configured as analog input channels on RESET
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOEBTRB                  //Boot block not protected from table reads
#FUSES NOCPB                    //No Boot Block code protection
#FUSES MCLR                     //Master Clear pin enabled
#FUSES LPT1OSC                  //Timer1 configured for low-power operation
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES PLL12                    //Divide By 12(48MHz oscillator input)
#FUSES CPUDIV4                  //System Clock by 4
#FUSES USBDIV                   //USB clock source comes from PLL divide by 2
#FUSES VREGEN                   //USB voltage regulator enabled
#FUSES ICPRT                    //ICPRT enabled

#use delay(clock=20000000)
#define I2C_SCL   PIN_B1
#define I2C_SDA   PIN_B0
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#use i2c(Master,Fast,sda=PIN_B0,scl=PIN_B1,force_hw)


Código: [Seleccionar]
//pcf8574.c


#define I2CWRITE     0b00000000
#define I2CREAD      0b00000001

// Esta es una función útil para tomar la dirección física de i2c
// y cambiando los bits dejó para que la dirección puede ser
// simplemente O escribiría con un i2c comando...

int i2c_addr_mask(int device_addr) {
   /* xxxxxIJK --> 00000IJK, then 00000IJK --> 0000IJK0 */
   return((device_addr & 0x07)<<1);
}

// ----------------------------------------------------------------------------

// rutinas para el philips PCF8574/(A) i2c basados en 8 de I/O chip
// i2c_pcf8574_get_io(); Estado de lecturas de 1 o todos 8 entradas
// i2c_pcf8574_set_io(); establecer el estado de todas las 8 salidas
// i2c_device_exists(); prueba de la presencia de dispositivo

// ---- TIPO DE DISPOSITIVO ----
#define PCF8574_ID   0b01000000
#define PCF8574A_ID  0b01110000

int i2c_pcf8574_get_io(int device_type, int device_addr,int port_id) {
                  /*  0 <= port_id <= 8, o  8 para todos  */
   int io_field;
   int addr_mask;
   addr_mask=i2c_addr_mask(device_addr);
   i2c_start();
   i2c_write(device_type | addr_mask | I2CREAD);
   io_field=i2c_read();    /*  este byte contiene el resultado del conversión previa. */
   io_field=i2c_read(0);   /*  devolver datos están big-endian (msbit first)  */
   i2c_stop();
   if (port_id >= 8)
      return(io_field);
   if (BIT_TEST(io_field,port_id))
      return(1);
   else
      return(0);
}

// Nota: en el fin de aplicar "por bit" el control de puerto, será necesario
//       primero leer todos los bits y, a continuación, OR ese valor con
//       el bit Estás tratando de alternar. de lo contrario, sólo
//       terminará sobrescribir adyacentes bits de io y, por tanto, sin
//       querer cambiar otras líneas de io.

int i2c_pcf8574_set_io(int device_type, int device_addr, int io_field) {
   int addr_mask;
   addr_mask=i2c_addr_mask(device_addr);
   i2c_start();
   i2c_write(device_type | addr_mask | I2CWRITE);
   i2c_write(io_field);
   i2c_write(io_field);
   i2c_stop();
   return(io_field);
}

// Nota: debido a una metida de pata de producción, algunos PCB emsamblados
//       fueron entregado con la versión "A" del dispositivo pcf8574; mientras  
//       las partes responsables de hecho fueron torturados por verse obligados
//       a consumir grandes ingeridos un laxante popular, sin embargo, era
//       necesario implementar un esquema mediante el cual el FW pudo detectar
//       qué pcf8574 era verdadero en version. por lo tanto lo siguiente...
//       llamada a la función usando ya sea PCF8574_ID o PCF8574A_ID y prueba
//       el valor devuelto. Esta función no es realmente pcf8574 específicos;
//       la se puede utilizar para probar presencia de cualquier tipo de  
//       dispositivo i2c en cualquier dirección física i2c.

short int i2c_device_exists(int device_type, int device_addr) {
   short int result=FALSE;
   int addr_mask;
   int testbyte;
   addr_mask=i2c_addr_mask(device_addr);
   testbyte=(device_type | addr_mask | I2CWRITE); // modo escritura
   i2c_start();
   if (i2c_write(testbyte))  // si se establece el bit de error ACK,
                             //destino está ausente
        result=FALSE;
   else
        result=TRUE;
   i2c_stop();
   return(result);
}






Código: [Seleccionar]
PCF8574_lcd.c

//expansor i2c       LCD20x4
//-------------     --------------
//Pin   4  x0        Pin   4   RS
//Pin   5  x1        Pin   5   RW
//Pin   6  x2        Pin   6   E
//Pin   7  x3        Pin  --   --
//Pin   9  x4        Pin  11   DB4
//Pin  10  x5        Pin  12   DB5
//Pin  11  x6        Pin  13   DB6
//Pin  12  x7        Pin  14   DB7
//

void lcd_init(void);
void lcd_write(char dat);
void lcd_nibble(char nibble);
void lcd_putc(char c);
void lcd_gotoxy(char y, char x);
void lcd_clear(void);
 
static char lcd_DBUS;


#define  lcd_RS  lcd_DBUS,0
#define  lcd_RW  lcd_DBUS,1
#define  lcd_E   lcd_DBUS,2
/*
#define  lcd_RS  lcd_DBUS,0
#define  lcd_E   lcd_DBUS,1
#define  lcd_RW  lcd_DBUS,2
*/

// añado yo modifico
#define lcd_line_1 0x80 // LCD RAM address for the 1 line 0x00
#define lcd_line_2 0xC0 // LCD RAM address for the 2 line 0x40
#define lcd_line_3 0x94 // LCD Ram address for the 3 line 0x14
#define lcd_line_4 0xD4 // LCD Ram address for the 4 line 0x54

// añado yo modifico
/*
#define LCD_DATO 1
#define LCD_COMANDO 0

#define LCD_CLEAR 0x01
#define LCD_HOME 0x02
#define LCD_MOVCURSO 0x06
*/
#define LCD_DISPLAY_OFF 0x08
/*
#define LCD_DISPLAY_ON 0x0C
#define LCD_CURSOR_ON 0x0E
#define LCD_CURSOR_BLINK 0x0F

#define LCD_CURSOR_SHIFT_RIGHT 0x10
#define LCD_CURSOR_SHIFT_LEFT 0x14
#define LCD_DISPLAY_SHIFT_RIGHT 0x18
#define LCD_DISPLAY_SHIFT_LEFT 0x1C
*/

//****************************************************************************
// Definicion de dispositivos
// PCF8574 Slave address + Write
// Interface de 4 bits, despliegue de 2 líneas y caracteres de 5x7 puntos.
//****************************************************************************
#define addr_slave 0x40 // PCF8574 Slave address + Write

//****************************************************************************
// Ejecuta la inicializaci?n software completa del LCD. La configuraci?n es:
// Interface de 4 bits, despliegue de 2 líneas y caracteres de 5x7 puntos.
//****************************************************************************
void lcd_init(void)
{
    lcd_DBUS = 0x00;
    i2c_start();              // inicia bus i2c
    i2c_write(addr_slave);    // PCF8574 Slave address + Write
    i2c_write(lcd_DBUS);      // manda dato
    i2c_stop();               // para bus i2c
    delay_ms(45);       // > 40 ms
    lcd_nibble(0x30);   // Function Set: 8-bit
    delay_ms(5);        // > 4.1 ms
    lcd_nibble(0x30);   // Function Set: 8-bit
    delay_ms(1);        // > 100 ?s
    lcd_nibble(0x30);   // Function Set: 8-bit
    delay_ms(1);        // > 40 ?s
    lcd_nibble(0x20);   // Function Set: 4-bit
    delay_ms(1);        // > 40 ?s
    lcd_nibble(0x20);   // Function Set: 4-bit, 2lines, 4x7font
    lcd_nibble(0x80);   //
    lcd_write(0x0C);    // Display ON/OFF Control
    lcd_write(0x01);    // Clear Display
    delay_ms(2);
    lcd_write(0x06);    // Entry Mode Set
}
 
//****************************************************************************
// Envía una instruccion al LCD.
// Pre-condición: Estado de línea lcd_RS
//  - Si lcd_RS = 0, 'dat' va al Registro de Comandos
//  - Si lcd_RS = 1, 'dat' va a la DDRAM o CGRAM
//****************************************************************************
void lcd_write(char dat)
{
    lcd_nibble(dat);        // Nibble alto
    lcd_nibble(dat<<4);     // Nibble bajo
}
 
//****************************************************************************
// Envía el nibble alto de 'nibble' al LCD.
//****************************************************************************
void lcd_nibble(char nibble)
{
    i2c_start();
    i2c_write(addr_slave);        // PCF8574 Slave address + Write
    lcd_DBUS = (nibble&0xF0)|(lcd_DBUS&0x0F);
    i2c_write(lcd_DBUS);
    bit_set(lcd_E);
    i2c_write(lcd_DBUS);
    bit_clear(lcd_E);
    i2c_write(lcd_DBUS);
    i2c_stop();
}
 
//****************************************************************************
// Envía una instrucción de dato al LCD.
//****************************************************************************
void lcd_putc(char c)
{
    bit_set(lcd_RS);
    lcd_write(c);
}
 
//****************************************************************************
// Ubica el cursor del LCD en la columna c de la línea r.
//****************************************************************************
void lcd_gotoxy(char x, char y)
{
      switch(y){
        case 1: y = lcd_line_1; break;
        case 2: y = lcd_line_2; break;
        case 3: y = lcd_line_3; break;
        case 4: y = lcd_line_4; break;
        default: y = lcd_line_1; break;
      }
    bit_clear(lcd_RS);
    lcd_write(y+x-1);
}
 
//****************************************************************************
// Limpia la pantalla del LCD y regresa el cursor al inicio.
//****************************************************************************
void lcd_clear(void)
{
    bit_clear(lcd_RS);
    lcd_write(0x01);
    delay_ms(2);        // > 1.5 ms
}
void lcd_p(void)
{
    bit_clear(lcd_RS);
    lcd_write(0x0F);
    delay_ms(2);        // > 1.5 ms
}

void lcd_cmd(int cmd){
    bit_clear(lcd_RS);
    lcd_write(cmd);
    delay_ms(2);        // > 1.5 ms
}


Título: Re: expansor i2c + lcd420 + pic16 + pic18
Publicado por: pajaro en 23 de Marzo de 2014, 09:42:14
Hola compañeros

Me respondo a mi mismo,
el asistente de CCS no asigna los pines de los puertos i2c automaticamente
una vez selecionado el micro, asi que se los tuve que asignar yo, por eso no funcionaba
y porque olvide la instrucion de incio del lcd :: lcd_init();
ahora funciona
ambos errores estan solucionados en el fuente.

Tema terminado.
un cordial saludo.