TODOPIC
Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: Thulsa Doom en 10 de Julio de 2010, 15:43:32
-
Hola a todos, pues tengo un problema al utilizar un teclado en un proyecto que estoy realizando,
antes de nada he de decir que soy novato en la programación de microcontroladores en lenguaje C
la practica consta de un teclado + un LCD y los dos conectados al puerto B de un microcontrolador PIC16F876.
La programación la realizo con el compilador CCS C.
Lo que pretendo hacer, es que mientras no pulse ninguna tecla del teclado, un led que está en el puerto C en el pin 0 esté parpadeando, y en el display se despliegue un mensaje de por ejemplo, "LCD Activado".
Cuándo pulse el teclado, aparezca en el display, "Pulsar tecla 1", "Pulse tecla 2" y así sucesivamente hasta terminar de introducir el código que tengo guardado en la memoria eeprom.
Si el código es correcto, me va a una subrutina si no, me despliega un mensaje de error.
el programa que he hecho es este:
#include <16F876.h>
#fuses XT,NOWDT,NOPROTECT
#use delay(clock = 4000000)
#use standard_io (A)
#use standard_io (B)
#define use_portb_lcd TRUE
#include <lcd.c>
#define use_portb_kbd TRUE
#include <kbd.c>
#include <stdlib.h>
#rom 0x2100={'1','2','3'}
void keyboard();
void main(){
char k;
int i;
char data[3], clave[3];
lcd_init();
kbd_init();
port_b_pullups(TRUE);
while(TRUE){
i=0;
printf(lcd_putc,"\fLCD activado\n");
while(i<=2){
k=kbd_getc();
if (k!= 0)
{data[i]=k;
i++;
printf(lcd_putc,"\fPulsar tecla%u\n"i+1);
}
}
for (i=0;i<=2;i++){
clave[i]=read_eeprom(i);}
if ((data[0]==clave[0])&&(data[1]==clave[1])&&(data[2]==clave[2]))
keyboard();
else printf(lcd_putc,"\fClave erronea");
delay_ms(1500);
}
}
void keyboard(){
lcd_gotoxy(1,1);
printf(lcd_putc,"\fTeclado activado");
while(TRUE){
output_low(PIN_C0);
output_low(PIN_C1);
output_high(PIN_C2);
delay_ms(700);
output_low(PIN_C2);
delay_ms(700);
}
}
Hasta ahí todo bien, pero como intente introducir un led que parpadee o algo más, el programa parece que nada más iniciarse se queda esperando en el bucle while (1<=2) y no sale de ahí.
si pongo un led que parpadee dentro de ese bucle por ejemplo así:
#include <16F876.h>
#fuses XT,NOWDT,NOPROTECT
#use delay(clock = 4000000)
#use standard_io (A)
#use standard_io (B)
#define use_portb_lcd TRUE
#include <lcd.c>
#define use_portb_kbd TRUE
#include <kbd.c>
#include <stdlib.h>
#rom 0x2100={'1','2','3'}
void keyboard();
void main(){
char k;
int i;
char data[3], clave[3];
lcd_init();
kbd_init();
port_b_pullups(TRUE);
while(TRUE){
i=0;
printf(lcd_putc,"\fLCD activado\n");
while(i<=2){
k=kbd_getc();
if (k!= 0)
{data[i]=k;
i++;
printf(lcd_putc,"\fPulsar tecla%u\n"i+1);
}
output_high(PIN_C0);
delay_ms(300);
output_low(PIN_C0);
delay_ms(300);
}
for (i=0;i<=2;i++){
clave[i]=read_eeprom(i);}
if ((data[0]==clave[0])&&(data[1]==clave[1])&&(data[2]==clave[2]))
keyboard();
else printf(lcd_putc,"\fClave erronea");
delay_ms(1500);
}
}
void keyboard(){
lcd_gotoxy(1,1);
printf(lcd_putc,"\fTeclado activado");
while(TRUE){
output_low(PIN_C0);
output_low(PIN_C1);
output_high(PIN_C2);
delay_ms(700);
output_low(PIN_C2);
delay_ms(700);
}
}
el código de parpadeo de led no se ejecuta, ponga donde ponga ese código o solo se ejecuta una vez y luego se queda esperando a que introduzca números en el teclado.
si hago otro tipo de bucle para que este corriendo todo el rato, si me funciona el led pero no funciona el teclado.
Me gustaría a ver si alguien me puede explicar el funcionamiento de la librería kbd.c o si hay otra manera de hacer ésto que quiero
la verdad es que me está costando mucho entender el teclado, con el lcd no tengo problemas pero el teclado se me resiste.
Pido disculpas si no me he explicado con claridad, si eso me preguntan lo que no entiendan de esto que quiero hacer y yo intentaré ser más claro.
-
Debes configurar el puerto C como salida
set_tris_c(0x00);
Quiza sea eso nada mas.
-
Siento el retraso en responder pero por causas personales no he podido.
Esto que me comentas no funciona, por lo que veo es cosa del bucle del teclado, al parecer se queda esperando a que pulse las teclas del teclado para operar e ignora el resto del código, tiene que haber una manera de integrar la escucha del teclado sin afectar al resto como el código del lcd, lo que no tengo ni idea a ver si alguien me pude orientar, o si saben de algún manual o documento que me explique el proceso
-
Hola Thulsa Doom, yo creo que en gran parte el problema que tienes (aunque no necesariamente el único), es que al programa le falta este fuse: #FUSES NOLVP . Yo te recomendaría que miraras el programita ya probado que te adjunto y a partir de allí lo vas ampliando según tus necesidades. Este es un programa sencillo que viene con una de las boards de entrenamiento del CCS y lo que hace es que si presionas una tecla aparece el caracter correspondiente en la pantalla. Ahi están las conexiones (compartidas algunas) para el Puerto B del Teclado y el LCD.
/*
Conexiones del LCD:
RB0 enable
RB1 rs
RB2 rw
RB4 D4
RB5 D5
RB6 D6
RB7 D7
Conexiones de Teclado (3x4)
COL0 RB5
COL1 RB6
COL2 RB7
ROW0 RB1
ROW1 RB2
ROW2 RB3
ROW3 RB4
*/
#include <16F876.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES XT //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
#FUSES PUT //Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES BROWNOUT //Reset when brownout detected
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES NODEBUG //No Debug mode for ICD
#use delay(clock=4000000)
#define LCD_TYPE 2
#define use_portb_lcd TRUE
#define use_portb_kbd TRUE
#include <lcd.c>
#include <kbd.c>
void main()
{
char k;
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_CLOCK_DIV_2);
setup_spi(SPI_SS_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_ccp1(CCP_OFF);
disable_interrupts(GLOBAL);
port_b_pullups(TRUE);
lcd_init();
kbd_init();
lcd_putc("\fListo...\n");
while (TRUE)
{
k = kbd_getc();
if(k != 0)
if(k == '*')
lcd_putc('\f');
else
lcd_putc(k);
}
}
Saludos!
-
Hola Thulsa Doom, yo creo que en gran parte el problema que tienes (aunque no necesariamente el único), es que al programa le falta este fuse: #FUSES NOLVP . Yo te recomendaría que miraras el programita ya probado que te adjunto y a partir de allí lo vas ampliando según tus necesidades. Este es un programa sencillo que viene con una de las boards de entrenamiento del CCS y lo que hace es que si presionas una tecla aparece el caracter correspondiente en la pantalla. Ahi están las conexiones (compartidas algunas) para el Puerto B del Teclado y el LCD.
/*
Conexiones del LCD:
RB0 enable
RB1 rs
RB2 rw
RB4 D4
RB5 D5
RB6 D6
RB7 D7
Conexiones de Teclado (3x4)
COL0 RB5
COL1 RB6
COL2 RB7
ROW0 RB1
ROW1 RB2
ROW2 RB3
ROW3 RB4
*/
#include <16F876.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES XT //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
#FUSES PUT //Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES BROWNOUT //Reset when brownout detected
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES NODEBUG //No Debug mode for ICD
#use delay(clock=4000000)
#define LCD_TYPE 2
#define use_portb_lcd TRUE
#define use_portb_kbd TRUE
#include <lcd.c>
#include <kbd.c>
void main()
{
char k;
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_CLOCK_DIV_2);
setup_spi(SPI_SS_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_ccp1(CCP_OFF);
disable_interrupts(GLOBAL);
port_b_pullups(TRUE);
lcd_init();
kbd_init();
lcd_putc("\fListo...\n");
while (TRUE)
{
k = kbd_getc();
if(k != 0)
if(k == '*')
lcd_putc('\f');
else
lcd_putc(k);
}
}
Saludos!
Hola, pues he probado el código y tal y como está escrito si funciona, pero tengo el mismo problema que con el que he puesto al principio, si quiero poner otra rutina complementaria al teclado, el teclado deja de funcionar, la verdad es que no se de que manera puedo integrar un teclado a un programa
subo la modificación que he hecho para que vean como funciona.
/*
Conexiones del LCD:
RB0 enable
RB1 rs
RB2 rw
RB4 D4
RB5 D5
RB6 D6
RB7 D7
Conexiones de Teclado (3x4)
COL0 RB5
COL1 RB6
COL2 RB7
ROW0 RB1
ROW1 RB2
ROW2 RB3
ROW3 RB4
*/
#include <16F876.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES XT //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
#FUSES PUT //Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES BROWNOUT //Reset when brownout detected
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES NODEBUG //No Debug mode for ICD
#use delay(clock=4000000)
#define LCD_TYPE 2
#define use_portb_lcd TRUE
#define use_portb_kbd TRUE
#include <lcd.c>
#include <kbd.c>
void main()
{
char k;
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_CLOCK_DIV_2);
setup_spi(SPI_SS_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_ccp1(CCP_OFF);
disable_interrupts(GLOBAL);
port_b_pullups(TRUE);
lcd_init();
kbd_init();
lcd_putc("\fListo...\n");
while (TRUE)
{
k = kbd_getc();
if(k != 0)
if(k == '*')
lcd_putc('\f');
else
lcd_putc(k);
output_high(PIN_C0);
delay_ms(500);
output_low(PIN_C0);
delay_ms(500);
}
}
lo único que he hecho es agregar un led que parpadea en el pin C0
-
Hola Thulsa Doom, me gustaría preguntarte si lo del teclado funciona de vez en cuando, o no funciona totalmente. Lo que ocurre es que con el código para prender los leds que le estás agregando, tienes ocupado el micro durante un segundo completo en el cual no te va a responder a ninguna otra orden, ya que en este programa todas las órdenes funcionan en secuencia una detrás de otra. Como la orden que captura la tecla tan solo está activa (a 4MHz) algunos microsegundos (ver KBD.c), es muy difícil que al presionar y soltar una tecla coincida con esa orden con los leds trabajando. Puedes hacer el ensayo dejando presionada una tecla cualquiera (que no sea el asterisco '*') durante algo más de un segundo y si aparece en la pantalla entonces ya sabes lo que está ocurriendo.
Si quisieras que el teclado te responda de inmediato cuando toques una tecla aún cuando estén prendiendo los leds, no te queda otro remedio que programar bien sea la entrada del teclado por medio de una interrupción, o programar la interrupción de un timer de modo que active alguna variable que prenda y apague el led durante el tiempo que lo requieras.
Un saludo!
-
Vale, entendido, es eso lo que está pasando, el problema que tengo es que soy autodidacta en esto de aprender a programar micros y no he llegado al tema de las interrupciones, primero quiero entender bien las diferentes prácticas que se me presentan para luego pasar al siguiente nivel.
un saludo y gracias, si tienes alguna sugerencia más será bienvenida
-
Hola, no hay ningún problema con ser autodidacta; de hecho yo lo he sido en muchas áreas y me ha hido bien hasta ahora, sin querer decir que sea experto en alguna de ellas. Creo que como vas, vas muy bien. En este foro puedes encontrar algunos ejemplos de como manejar los leds por medio de una interrupción de un temporizador, o incluso de como manejar el teclado por la interrupción RB, para lo que te recomendaría inicialmente estudiar el ejemplo del CCS C: EX_PBUTT.C.
Saludos!
-
Hola,
La solución como te han indicado pasa por añadir una interrupción que gestione el led para que el teclado se siga comprobando y la LCD se refresque adecuadamente.
No te preocupes por ser autodidacta, porque muchos lo somos tambien y hemos empezado poco a poco.
Vamos a introducir una solución sencilla de entender en tu programa, para que el led arranque parpadeando y al pulsar el 5 ( por ejemplo) deje de parpadear.
La implementación de la lectura de un código de seguridad y lo demás ya te encargarás de conseguirlo tú siguiendo tu propia curva de aprendizaje.
Lo vamos a hacer de esta manera:
- Vamos a implementar una interrupción cada 30 ms para que no nos interrumpa ( en la medida de lo posible ) el refresco de la LCD de forma crítica y para que dé tiempo suficiente de actuación a la rutina antirrebotes del teclado ( que supongo lleva implementada en una librería tipo flex_kbd.c o kbd.c ).
- Como queremos que el parpadeo se vea, tendremos un contador de interrupciones que haremos que cambie el estado del led ( lo apague o lo encienda ) cada 120ms, es decir cada 4 interrupciones de 30ms.
- Tembien tenemos una variable de tipo booleana para indicarnos si el parpadeo está habilitado o no. Al pulsar la tecla 5 lo deshabilitaremos.
Comenzamos definiendo las variables a usar:
int n_interrupciones=0; //Contador de interrupciones
int1 estado_led=FALSE; //Estado del led a parpadear
int1 led_enable; //Habilitar parpadeo led
A continuación la rutina de la interrupcióndel timer0.
Si es la 4ª interrupción que se produce, es que ha pasado 120ms;
Simplemente comprobamos que el led tiene habilitado el parpadeo, y en caso positivo, si estaba apagado, lo encendemos o viceversa.
#INT_TIMER0
void interrupcion(void)
{
set_timer0(21); //carga TMR0 y desborda cada 30mseg
n_interrupciones++; //Incrementa contador irqs
if (n_interrupciones==4) //Si 4= 120 ms
{
// Han pasado 120ms
n_interrupciones=0; //restablezco contador de interrupciones
if (led_enable){ //Se ha habilitado el parpadeo del led?
if (estado_led){ //Si el led estaba encendido
output_low(PIN_C0); //Lo apagamos
estado_led=FALSE; //Ponemos marca de estado actual (apagado)
}
else { //Si el led estaba apagado
output_high(PIN_C0); //Lo encendemos
estado_led=TRUE; //Ponemos marca de estado actual (encendido)
}
}
}
}
En nuestra rutina main, añadimos la configuración inicial del timer y habilitamos las interrupciones pertinentes:
//Configuración del timer0 Divisor por 128 y timer cargado a 21 para obtener
//un desbordamiento cada 30 ms con un cuarzo de 4MHz
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_128);
set_timer0(21);
enable_interrupts(GLOBAL); //Habilita interrupciones globales
enable_interrupts(INT_TIMER0); //Activamos interrupción TIMER0
Y modificamos el bucle principal:
led_enable=TRUE; //Habilitamos parpadeo del led
while (TRUE)
{
k = kbd_getc();
if(k != 0)
if(k == '*')
lcd_putc('\f');
else {
lcd_putc(k);
if (k=='5') led_enable=FALSE; //Si pulsamos el 5 deja de parpadear
}
}
Y con esto al encender el aparato, el led comienz a parpadear. Podemos escribir lo que nos dé la gana pero al pulsar la tecla "5" el led deja de parpadear.
El código final te quedaría así:
/*
Conexiones del LCD:
RB0 enable
RB1 rs
RB2 rw
RB4 D4
RB5 D5
RB6 D6
RB7 D7
Conexiones de Teclado (3x4)
COL0 RB5
COL1 RB6
COL2 RB7
ROW0 RB1
ROW1 RB2
ROW2 RB3
ROW3 RB4
*/
#include <16F876.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES XT //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
#FUSES PUT //Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES BROWNOUT //Reset when brownout detected
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES NODEBUG //No Debug mode for ICD
#use delay(clock=4000000)
#define LCD_TYPE 2
#define use_portb_lcd TRUE
#define use_portb_kbd TRUE
#include <lcd.c>
#include <kbd.c>
int n_interrupciones=0; //Contador de interrupciones
int1 estado_led=FALSE; //Estado del led a parpadear
int1 led_enable; //Habilitar parpadeo led
#INT_TIMER0
void interrupcion(void)
{
set_timer0(21); //carga TMR0 y desborda cada 30mseg
n_interrupciones++; //Incrementa contador irqs
if (n_interrupciones==4) //Si 4= 120 ms
{
// Han pasado 120ms
n_interrupciones=0; //restablezco contador de interrupciones
if (led_enable){ //Se ha habilitado el parpadeo del led?
if (estado_led){ //Si el led estaba encendido
output_low(PIN_C0); //Lo apagamos
estado_led=FALSE; //Ponemos marca de estado actual (apagado)
}
else { //Si el led estaba apagado
output_high(PIN_C0); //Lo encendemos
estado_led=TRUE; //Ponemos marca de estado actual (encendido)
}
}
}
}
void main()
{
char k;
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_CLOCK_DIV_2);
setup_spi(SPI_SS_DISABLED);
//Configuración del timer0 Divisor por 128 y timer cargado a 21 para obtener
//un desbordamiento cada 30 ms con un cuarzo de 4MHz
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_128);
set_timer0(21);
enable_interrupts(GLOBAL); //Habilita interrupciones globales
enable_interrupts(INT_TIMER0); //Activamos interrupción TIMER0
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_ccp1(CCP_OFF);
port_b_pullups(TRUE);
lcd_init();
kbd_init();
lcd_putc("\fListo...\n");
led_enable=TRUE; //Habilitamos parpadeo del led
while (TRUE)
{
k = kbd_getc();
if(k != 0)
if(k == '*')
lcd_putc('\f');
else {
lcd_putc(k);
if (k=='5') led_enable=FALSE; //Si pulsamos el 5 deja de parpadear
}
}
}
Y lo he probado.. :mrgreen:
Salu2
-
Hola, siento responder tan tarde, pero por causas de trabajo no he podido ni probar el código.
beuno, doy las gracias por la ayuda y estudiaré el ejercicio hasta que comprenda el proceso.
saludos
-
para cuestiones de simulacion me toco hacer esto para poder probar :(
(http://a.imageshack.us/img820/8261/teclado.jpg)
http://a.imageshack.us/img820/8261/teclado.jpg
pero en la real no será necesario verdad? el teclado lo pondria en el puerto B y con las pull up internas sin diodos..asi a secas??
-
Hola,
Yo habitualmente uso un teclado 3x4 en el mismo puerto (normalmente el B) y conectado a su vez un LCD 2x16 en el mismo puerto con los pullups activados en el puerto y sin diodos ni nada más.
Salu2
-
;-) ok, gracias
-
Yo lo tengo asi y va perfecto
(http://img69.imageshack.us/img69/6554/dibujoka.jpg) (http://img69.imageshack.us/i/dibujoka.jpg/)
-
que raro yo asi no puedo simular
-
¿Será la versión?, creo que la mía es la 7.5
-
Seguramente es la versión! :? Después de todo es un simulador ;-)
Saludos!
-
Yo tampoco puedo simularlo en el mismo puerto, y sin embargo en la práctica me funciona perfectamente.
Últimamente estoy muy descontento con Proteus :)
Salu2
-
aaa eso me tranquiliza entonces por lo pronto con los diodos y las resistencias simula, las que tampoco me funcionó fuerono las pull ups que proteus.
-
Vaya noticias, pues yo por todos estos problemas he estado pensando en pillarme un entrenador para pics por que no se fío mucho del proteus.
el que me ha gustado es el PIC SCHOOL que he tenido noticias de amigos que lo tienen y están contentos, si me recomiendan otro lo miraré.
(si esto se considera publicidad y está prohibido, lo quito de inmediato)