Problema en código de teclado + LCD en XC8

Hola,
Tengo un problema al montar mi circuito con Proteus ya que en una PIC SCHOOL si que me funciona.
El pic es pic16f886 y mediante un teclado matricial 4x4 quiero que salgan las teclas pulsadas.
El problema es que yo creo que lo tengo mal conectado.

Código:
#ifndef LCD_H

#define	LCD_H


#ifdef 	__cplusplus
extern "C" 
{

#endif

////////////// cuerpo del header///////////////////////


#define DispRS    RA3

#define DispRW    RA2

#define DispE     RA1
#define LCD_DAT_PORT PORTB

// Register selection
#define CMD_REG         0x00    // Command register
#define DATA_REG    0x01    // Data register
#define LCD_WRITE    0x00    // Writes to LCD
#define LCD_READ    0x01    // Reads from LCD


// LCD specific defines
#define LCD_CLR    0x01    // Clears display
#define LCD_HOME    0x02    // Returns home


// Entry mode set
#define LCD_DEC        0x04    // Decrements DDRAM address
#define LCD_SHIFT_R    0x05    // Shifts display to the right
#define LCD_INC        0x06    // Increments DDRAM address cursor from left to right?
#define LCD_SHIFT_L    0x07    // Shifts display to the left


// Display ON/OFF
#define LCD_DISPOFF    0x08    // Display off
#define LCD_DISPON    0x0C    // Display on
#define LCD_CRS_OFF    LCD_DISPON | 0x00    // Cursor does not display
#define LCD_CRS_ON    LCD_DISPON | 0x02    // Cursor displays
#define LCD_BL_OFF    LCD_DISPON | 0x00    // Cursor does not blink
#define LCD_BL_ON    LCD_CRS_ON | 0x01    // Cursor blinks



// Cursor and Display Shift
#define LCD_SH_C_L    0x10    // Shifts the cursor position to the left (Address Counter is decremented by 1)
#define LCD_SH_C_R    0x14    // Shifts the cursor position to the right (Address Counter is incremented by 1)
#define LCD_SH_D_L    0x18    // Shifts the entire display to the left. The cursor follows the display shift
#define LCD_SH_D_R    0x1C    // Shifts the entire display to the right. The cursor follows the display shift


// Function Set
#define LCD_FN_SET    0x28                // Function set. Data 4-bit
#define LCD_1L_5x8    LCD_FN_SET | 0x00    // Displays 1 line. Character font: 5x 8 dots
#define LCD_1L_5x10    LCD_FN_SET | 0x04    // Displays 1 line. Character font: 5x10 dots
#define LCD_2L_5x8    LCD_FN_SET | 0x08    // Displays 2 line. Character font: 5x 8 dots


// LCD defines for calling lcd_xy with line number, position and cursor status
#define LCD_LN1        0x80 //0x00    // DDRAM address of the 1st line
#define LCD_LN2        0xC0//0x40    // DDRAM address of the 2nd line


#define LCD_CG_SET    0x40    // Sets CG RAM address
#define LCD_DD_SET    0x80    // Sets DDRAM address
#define LCD_BUSY        0x80    // Busy flag


#define LCDNCHARS    16        // Define number of chars per line


// Function prototypes
void lcd_init(void);        // LCD initialization
void lcd_send_cmd(unsigned char data);    // Writes instruction to LCD
void lcd_send_dat(unsigned char data);    // Writes data to LCD



//////////////////////////////////////////////////////
#ifdef	__cplusplus
}
#endif

#endif	/* LCD_H */

Código:
//FICHERO AUTOGENERADO DE BITS DE CONFIGURACIÓN DEL MICROPROCESADOR
//#include <xc.h>

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG1
#pragma config FOSC = INTRC_NOCLKOUT// Oscillator Selection bits (INTOSC oscillator: CLKOUT function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF       // RE3/MCLR pin function select bit (RE3/MCLR pin function is MCLR)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = OFF       // Brown Out Reset Selection bits (BOR enabled)
#pragma config IESO = OFF       // Internal External Switchover bit (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled)
#pragma config LVP = OFF        // Low Voltage Programming Enable bit (RB3 pin has digital I/O, HV on MCLR must be used for programming)

// CONFIG2
#pragma config BOR4V = BOR40V   // Brown-out Reset Selection bit (Brown-out Reset set to 4.0V)
#pragma config WRT = OFF        // Flash Program Memory Self Write Enable bits (Write protection off)

Os dejo los codigos que uso para esto.
La conexión la e realizado de la misma manera que la realizo en la protoboard y no me funciona.
No e utilizado nunca el Proteus y nose si me faltara algo
Muchas gracias
 

Adjuntos

  • pic.jpg
    pic.jpg
    106.9 KB · Visitas: 5
Hola,
Mi programa basicamente consiste en que cuando pulse una tecla, esta tecla aparezca en el LCD.
Como no quiero que este todo el rato testeando si a cambiado algun bit del puerto B, quiero hacerlo con interrupciones pero no me funciona.
Pongo aqui el código haber si podeis hechar una mano
Muchas gracias

Código:
#include <stdio.h> 
#include <stdlib.h>
#include <xc.h>
#include "lcd.h"
#include <pic16f886.h>


/* Dos definiciones para determinar un retardo */

#define _XTAL_FREQ 4000000 // necesario para macros __delay_ms()

#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))
typedef unsigned char uint8_t;

unsigned char c;
char const KEYS[4][4] = {{'1','2','3','A'},
                         {'4','5','6','B'},
                         {'7','8','9','C'},
                         {'E','0','F','D'}};

void lcd_init()
{
    DispE = 0;
        DispRS = 0;
        __delay_ms(30);

        lcd_send_cmd(0x03);
        lcd_send_cmd(0x03);
        lcd_send_cmd(0x03);

        lcd_send_cmd(0x02);
        lcd_send_cmd(LCD_FN_SET);
        lcd_send_cmd(LCD_DISPOFF);
        lcd_send_cmd(LCD_CLR);
        lcd_send_cmd(LCD_DISPON);
}

void pulseEnable()
{
    DispE = 0;
    __delay_us(1);
    DispE = 1;
    __delay_us(1);
    DispE = 0;
    __delay_us(100);
}

void lcd_send_dat(unsigned char c)
{
        DispE = 0;
        DispRS = 1; //1 para mandar dato
        LCD_DAT_PORT = c >> 4; //ALTO

    pulseEnable();
        __delay_us(200); //5ms para comando, 200us para dato
            LCD_DAT_PORT = c;//( c & 0x0F ); //BAJO
    pulseEnable();
        __delay_us(200);
}

void lcd_send_cmd(unsigned char c)
{
        DispE = 0;
        DispRS = 0; //0 para mandar comando
        LCD_DAT_PORT = c >> 4; //ALTO
    pulseEnable();
        __delay_ms(5); //5ms para comando, 200us para dato
            LCD_DAT_PORT = c;//( c & 0x0F ); //BAJO
    pulseEnable();
        __delay_ms(5);
}

void writeString(const char *msg)
{
    while(*msg!='\0')
        lcd_send_dat(*msg++);
}

char teclado(void){
        unsigned char i,j;
	
	i=0;
	for(j=0;j<4;j++){
		if(PORTBbits.RB4==0){break;}
		i++;
		if(PORTBbits.RB5==0){break;}
		i++;
		if(PORTBbits.RB6==0){break;}
		i++;
		if(PORTBbits.RB7==0){break;}
		i++;
		PORTB<<=1;	//Trasladamos el 0 a siguiente Pin.
	}
	return(KEYS[i][j]);
            }

int main(int argc, char** argv) {
  
    ANSEL = 0X00 ;      //Deshabilitar ADC: Puertos digitales
    ANSELH = 0X00 ;     //Deshabilitar ADC: Puertos digitales
    TRISA = 0xf1;
    PORTA = 0x00;
    TRISB = 0xF0;
    PORTB = 0x00;

   INTCON = 0X88;

//Inicializar
        lcd_init();

    while(1)
    {
        
            lcd_send_cmd(LCD_LN1);      //1ª Línea
            lcd_send_cmd(LCD_HOME);     // Cursor a la posición 0
            lcd_send_cmd(LCD_CLR);      //Borra display
            

                if(INTCONbits.RBIF==1){
                c=teclado();
		lcd_send_dat(c);	// Visualizamos tecla pulsada.
		while(PORTBbits.RB4==0 || PORTBbits.RB5==0 || PORTBbits.RB6==0 || PORTBbits.RB7==0){} //Esperamos a que se suelte.-
		PORTB=0x00;
		INTCONbits.RBIF = 0; //Borramos bandera
	}


       
    }
    return (EXIT_SUCCESS);
}
 
Hola.
No veo el bloque de interrupción... es necesario declarar cuando se activa interrupciones, de lo contrario al compilar el código, ocupa el espacio del vector de interrupción... va a suceder un bucle innecesario y también provoca que la pila se llene, perdiendo direcciones de retorno y/o datos en el proceso...

void interrupt isr(void)
{
...
// Aquí y fuera NO...
INTCONbits.RBIF = 0;
}

Tambíen, mientraz un flag esté activo, siempre va a saltar al vector de interrupción... y las líneas debajo de if(INTCONbits.RBIF==1){... dificilmente se van a ejecutar.

Ten en cuenta que la interrupción por cambio de estado en el puerto B es eso, cada vez que cambia de estado ya sea de 0 a 1 o de 1 a 0.

Es necesario rehacer la idea... modifica el código...
Saludos.
 
Gracias, pero lo que yo quiero es que no este muestreando siempre y eso se hace con la interrupcion. Pero claro nose que es lo que declarar a la interrupción para que no muestree, nose si me entiendes.
Llevo varios días con esto y probando varias cosas y me estoy volviendo un poco loco.
 
por lo que entiendo... quieres leer el teclado solo cuando alguna tecla esté presionada y no siempre?
Eso se soluciona con interrupción, solo que de una u otra forma se tiene que verificar algo para saber si hay o no una tecla presionada... Por ejemplo, describo como funcionaría en el código:

Código:
#include <xc.h>

struct{
    unsigned char Key;
    unsigned IsPress:1;
    unsigned :7;
}STA = {0, 0};

void interrupt scanKey(void){
    if(INTCONbits.RBIF){
        //-- Lee el teclado
        //-- Recorre cada fila/columna para saber que tecla está presionada
        //-- Guarda en STA.Key
        //-- STA.IsPress = 1 -> Si hay una tecla activa

        PORTB = 0;  // Inhabilita el teclado
        INTCONbits.RBIF = 0;
    }
}

void main(void) {
    OPTION_REGbits.nRBPU = 0;   // PullUp Interno para 4 pines de entrada
    TRISB = 0x0F;               // 4 bits parte baja -> entradas
    INTCON = 0x88;              // Activa interrupciones

    //-- Importante:
    //-- Se mantiene inactivo al puerto del teclado
    PORTB = 0; // Con cero, los 4 bits de salida son cero
    //-- Con eso se asegura que cuando precione cualquier tecla, siempre se envíe
    //-- un cero a los pines de entrada, se cual sea...
    //-- y cuando se produzca la interrupción, recien ahí se escanea el teclado
    //-- esto se aprovecha por la lentitud de los cambios de estado al pulsar una tecla.

    while(1){
        if(STA.IsPress){    // Cuando hay una tecla
           STA.IsPress = 0;
           // Lee STA.Key -> Para saber la tecla presionada

           //--> Posible lugar para el antidebounce, ya que no se recomienda
           // poner en la interrupción
        }

        // Resto del código....
        // ....
    }
}

Es una idea... falta poner en práctica y asegurar un par de cosas...
Saludos
 
El problema sigue estando en que continuamente muestrea las filas, así que el problema es ese, en proteus esos pines no hacen otra cosa que cambiar de bajo a alto.
Y solo e conseguido que durante el tiempo que pulso una tecla en la primera columna de la izquierda salga el número 4 en todas las teclas.
Yo tengo el puerto B configurado de esta manera
TRISB = 0xF0;
Si le configuro de la otra forma no me funciona
 
Hola,
Ahora mismo el problema que tengo es que me escribe solo en el LCD y siempre un 1 o un 4 al accionar la tecla 7.
Dejo el código sin las interrupciones haber si alguien me puede echar una mano, gracias

Código:
#include <stdio.h> 
#include <stdlib.h>
#include <xc.h>
#include "lcd.h"
#include <pic16f886.h>


/* Dos definiciones para determinar un retardo */

#define _XTAL_FREQ 4000000 // necesario para macros __delay_ms()

#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))
typedef unsigned char uint8_t;

unsigned char tecla;
char const KEYS[4][4] = {{'1','2','3','A'},
                         {'4','5','6','B'},
                         {'7','8','9','C'},
                         {'E','0','F','D'}};

void lcd_init()
{
    DispE = 0;
        DispRS = 0;
        __delay_ms(30);

        lcd_send_cmd(0x03);
        lcd_send_cmd(0x03);
        lcd_send_cmd(0x03);

        lcd_send_cmd(0x02);
        lcd_send_cmd(LCD_FN_SET);
        lcd_send_cmd(LCD_DISPOFF);
        lcd_send_cmd(LCD_CLR);
        lcd_send_cmd(LCD_DISPON);
}

void pulseEnable()
{
    DispE = 0;
    __delay_us(1);
    DispE = 1;
    __delay_us(1);
    DispE = 0;
    __delay_us(100);
}

void lcd_send_dat(unsigned char c)
{
        DispE = 0;
        DispRS = 1; //1 para mandar dato
        LCD_DAT_PORT = c >> 4; //ALTO

    pulseEnable();
        __delay_us(200); //5ms para comando, 200us para dato
            LCD_DAT_PORT = c;//( c & 0x0F ); //BAJO
    pulseEnable();
        __delay_us(200);
}

void lcd_send_cmd(unsigned char c)
{
        DispE = 0;
        DispRS = 0; //0 para mandar comando
        LCD_DAT_PORT = c >> 4; //ALTO
    pulseEnable();
        __delay_ms(5); //5ms para comando, 200us para dato
            LCD_DAT_PORT = c;//( c & 0x0F ); //BAJO
    pulseEnable();
        __delay_ms(5);
}

void writeString(const char *msg)
{
    while(*msg!='\0')
        lcd_send_dat(*msg++);
}

char teclado(void){
        unsigned char i,j;
	
	i=0;
	for(j=0;j<4;j++){
		if(PORTBbits.RB4==0){
                __delay_ms(20);
                break;}
		i++;
		if(PORTBbits.RB5==0){
                __delay_ms(20);
                break;}
		i++;
		if(PORTBbits.RB6==0){
                __delay_ms(20);
                break;}
		i++;
		if(PORTBbits.RB7==0){
                __delay_ms(20);
                break;}
		i++;
		PORTB<<=1;	//Trasladamos el 0 a siguiente Pin.
	}
	return(KEYS[i][j]);
            }

int main(int argc, char** argv) {
  
    ANSEL = 0X00 ;      //Deshabilitar ADC: Puertos digitales
    ANSELH = 0X00 ;     //Deshabilitar ADC: Puertos digitales
    TRISA = 0xf1;
    PORTA = 0x00;
    TRISB = 0xF0;
    PORTB = 0x00;

   INTCON = 0X00;

//Inicializar
        lcd_init();
        lcd_send_cmd(LCD_LN1);
    while(PORTBbits.RB4 ==0 && PORTBbits.RB0 ==0 )
    {
        
                 //1ª Línea
           
            
            writeString("X=");
            

               if(1 ){
                   
                
                
                tecla=teclado();
		lcd_send_dat(tecla);
                
                __delay_ms(20);
		
		
	}


       
    }
    return (EXIT_SUCCESS);
}
 
Buen día, colegas. Odio molestar pero me vendría bien un poco de ayuda con un proyecto que estoy realizando.
Después de tanta búsqueda no encuentro una buena guía para hacer funcionar mi teclado 4x4 en XC8.
Realice una pequeña librería, si es que puedo llamarla de esa forma para el control de Keypad pero como en cualquier persona que está iniciando a hacer algoritmos, tengo errores.
No estoy seguro si mi error es en algún puerto de la librería.
La idea que quiero es almacenar un dígito, mostrarlo en LCD y posteriormente hacer una operación aritmética con este, pero no puedo avanzar.

Dejaré el código y la librería por si hay alguien que se apiade de esta pobre alma.
C:
#define _XTAL_FREQ 4000000

#include <xc.h>
#include <stdint.h>
#include <stdio.h>
#include "LCD.h"
#include "ADC.h"
#include "keypad.h"

void main(void) {
    uint16_t  dato;
    float volt;
    unsigned char buffer[10];

    ADC_init();
    LCD_init();

    while(1)
    {     
        LCD_cmd(LCD_HOME);
        dato= ADC_read(0);
        volt = (float)(((30.00/1024) * dato));
        sprintf(buffer, "Voltaje %.2f", volt);
        LCD_write_text(buffer);

  if (volt >= 20)
        {
        LCD_cmd(LCD_LINEA4);
        LCD_write_text("  Vol +20");
           unsigned char customChar [8] = {
    0b00000,
    0b01010,
    0b01010,
    0b00000,
    0b01110,
    0b10001,
    0b10001,
    0b00000
};
        LCD_custom_char(0, customChar);
        LCD_cmd(LCD_LINEA4);
        LCD_char(0);
        }
        }

Keypad.h
C:
/*
* File:   keypad.h
* Author: Xav
*
* Created on 1 de junio de 2020, 05:03 PM
*/
#ifndef KEYPAD_H
#define    KEYPAD_H

#ifdef    __cplusplus
extern "C" {

#endif

#ifdef    __cplusplus
}
#endif

#endif    /* KEYPAD_H */
    /******************************************************************
    *
    *                   Bit´s más significativos
    *
    ***************************************************************/
    TRISBbits.TRISB4 = 1;
    TRISBbits.TRISB5 = 1;           /*  puerto b como entrada*/
    TRISBbits.TRISB6 = 1;
    TRISBbits.TRISB7 = 1;
    
    PORTBbits.RB4 = 1;
    PORTBbits.RB5 = 1;              /*  puerto b en activo alto*/
    PORTBbits.RB6 = 1;              /*  puerto b en activo alto*/
    PORTBbits.RB7 = 1;             

    /*************************************************************
    *                     
    *                   Bit´s menos significativos
    *
    ***************************************************************/
    TRISBbits.TRISB0 = 0;
    TRISBbits.TRISB1 = 0;           /*  Puerto b como salida*/
    TRISBbits.TRISB2 = 0;
    TRISBbits.TRISB3 = 0;

    PORTBbits.RB0 = 0;
    PORTBbits.RB1 = 0;              /* Puerto b en activo bajo */
    PORTBbits.RB2 = 0;
    PORTBbits.RB3 = 0;

uint8_t leer_keypad(void)
{
    const uint8_t keypad_array[17] =
      /* 1  4  7   *  2  5  8  0  3  6  9   #   A   B   C   D      */
        {1, 4, 7, 14, 2, 5, 8, 0, 3, 6, 9, 15, 10, 11, 12, 13, 255};

    uint8_t key = 0, columna;

    for (columna = 0b00000001; columna < 0b00010000; columna <<= 1)
    {
        PORTB = ~(columna << 4);
        if (PORTBbits.RB0 == 0) break; key++;
        if (PORTBbits.RB1 == 0) break; key++;
        if (PORTBbits.RB2 == 0) break; key++;
        if (PORTBbits.RB3 == 0) break; key++;
    }
    PORTB = 0xFF;

    return keypad_array[key];
}
 
Atrás
Arriba