PicManía by RedRaven |
![]()
Búsqueda personalizada
|
Todo Picmaníaco que se precie ha de comenzar por hacer Experimentos, docenas de ellos, cientos de ellos ... aquí os propongo unos cuantos para ir sacándole punta al lápiz y prepararnos para acometer asuntos de mayor enjundia. |
Experimentos básicos: |
Para la realización de los distintos Experimentos que os propongo en esta sección hace falta un hardware específico. Como no tenéis la obligación de tener mi misma placa de desarrollo Edumic, ni nada que se le parezca, he decidido añadir una página con la descripción de este Hardware de Experimentos para que podáis, si queréis, montarlo y seguir así avanzando en esto de los PIC. Las notas accesorias a cada uno de ellos hacen referencia a esta página. Para la primera fase de estos experimentos vamos a intentar usar como los idiomas de programación PicBasic Pro de microEngineering Labs, Inc.; CCS PIC C de CCS y el ensamblador MPASM de Microchip ... para asuntos de mas enjundia abandonaremos el Basic y nos centraremos en el PIC C aunque algunas rutinas las haremos en ensamblador. Todos los fuentes publicados han sido compilados, o ensamblados según el caso, y programado el .hex correspondiente en el micro que se indica. Así que ... ¡Funcionan!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Experimento básico 1: Wink |
|
Ejemplo en Picbasic Pro para el PIC 16F628: |
||
'**************************************************************** |
||
Ejemplo en CCS PICC para el PIC 16F628 (usando delay()): |
||
//**************************************************************** //* winkc.c //* Ejemplo de programa que hace parpadear un LED //* conectado al PORTB.0 //**************************************************************** #include <16f628.h> // Selecciona el PIC #fuses XT,NOWDT,NOPROTECT,PUT,BROWNOUT // Opciones de configuración #use delay(clock=4000000) // Velocidad del Cristal : 4 Mhz #byte port_b=6 // Dirección del PORTB void main() { set_tris_b(0); // Configura los Pines de Port B como salida port_b=0; while(TRUE) { // Bucle infinito port_b=0; // Apaga todos los Leds delay_ms(500); // Espera medio segundo port_b=1; // Enciende el bit 0. delay_ms(500); // Espera otro medio segundo } } |
||
Ejemplo en CCS PICC para el PIC 16F628 (usando interrupción RTCC): |
||
// winkintc.c #include <16f628.h> // Selecciona el PIC #fuses XT,NOWDT,NOPROTECT,PUT,BROWNOUT // Opciones de configuración #use delay(clock=4000000) // Velocidad del Cristal : 4 Mhz #use standard_io(B) // PORTB en estándar IO digital #use fixed_io(b_outputs=PIN_B0) // B0 como salida en PORTB byte const NInts=7; // Numero de interrupciones para 0.25 Segundos // VARIABLES GLOBALES char C_Ints=0; // Contador de Interrupciones ocurridas char Flag=0; // Flag que cambia cada NInts interrupciones char K=0; // Estado anterior del Flag #int_RTCC // Interrupción por desbordamiento RTCC_isr() { // del TIMER0 RTCC if(C_Ints > NInts){ // Si las ints ocurridas > ints para 0.25 seg. if(Flag==0){ Flag=1; } else{ Flag=0; } C_Ints=0; // Reinicializo Contador de Ints } ++C_Ints; // Incremento el número de interrupciones } // Ocurridas void main(void) { setup_counters(RTCC_INTERNAL,RTCC_DIV_128); // TIMER0: Clock Interno, Presescaler 128 setup_timer_1(T1_DISABLED); // para una RTCC cada 33.3 milisegundos setup_timer_2(T2_DISABLED,0,1); // -> 1 Segundo = 30 RTCC setup_comparator(NC_NC_NC_NC); setup_vref(FALSE); enable_interrupts(INT_RTCC); // Habilito Interrupción RTCC enable_interrupts(global); // Habilito Interrupciones output_low(PIN_B0); // Empiezo apagando el Led do{ // Bucle infinito if(Flag!=K) { // si ha cambiado Flag ... if(Flag==0){ output_low(PIN_B0); } // Si es 0 Apago el Led if(Flag==1){ output_high(PIN_B0); } // si es 1 Enciendo el Led k=Flag; // Guardo estado anterior de Flag } }While(TRUE); } |
||
Ejemplo en MPASM para el PIC 16F628: |
||
;**************************************************************** ;* winkasm.asm ;* Ejemplo de programa que hace parpadear un LED ;* conectado al PORTB.0 ;**************************************************************** LIST p=16F628 ;Decimos al ensamblador qué micro estamos usando include "P16F628.inc" ;Incluimos las definiciones de nuestro micro ERRORLEVEL 0, -302 ;suprime mensajes de "bank selection" al ensamblar __config 0x3D18 ;configuramos (oscilador, tipo etc.) cblock 0x20 ;Comienzo de los registros de propósito general ;RAM en el Bank0 count1 ;Usado en la rutina Delay counta ;ídem countb ;idem endc org 0x0000 ;org coloca el programa en el origen, 0x0000 para el 16F628, ;Por aquí es por donde empieza el programa a ejecutarse movlw 0x07 movwf CMCON ;Deshabilito los comparadores bsf STATUS, RP0 ;Selecciono el Bank 1 para poder acceder a TRISB movlw b'00000000' ;Configuro todo el PortB para que sea de salida movwf TRISB bcf STATUS, RP0 ;Selecciono de nuevo el Bank 0 Loop movlw b'00000001' ;Pongo a '1' el primer bit del PortB movwf PORTB nop ;nop no hace nada (nada mas que incrementar el p.c.) nop ; call Delay ;Llamo a la rutina que espera ... movlw b'00000000' ;Pongo a '0' el primer bit del PortB movwf PORTB call Delay ;Llamo de nuevo a la rutina que espera ... goto Loop ;Salto al comienzo y así hasta el infinito Delay movlw d'250' ;Espero 250 ms (Para un reloj de 4 MHz) movwf count1 d1 movlw 0xC7 movwf counta movlw 0x01 movwf countb Delay_0 decfsz counta, f goto $+2 decfsz countb, f goto Delay_0 decfsz count1 ,f goto d1 retlw 0x00 end |
||
Haciendo Click
sobre la imagen inferior puede verse un momento de la simulación realizada
con el programa anterior haciendo parpadear el Led conectado a PORTB.0.
(La simulación está realizada con el PIC Simulator IDE 5.22 de
Oshon Soft) Nota: En el programa utilizado para la simulación se ha utilizado un delay mínimo para poder ver el cambio de estado del pin PORTB.0 dentro del margen del osciloscopio. |
Y por último podéis ver
exactamente lo que ocurre en el pin utilizando el arma definitiva: un
osciloscopio: |
Experimento básico 2: Barled |
|
Ejemplo en Picbasic Pro para el PIC 16F628: |
||
'**************************************************************** '* barledbasic.bas '* Ilumina consecutivamente los LEDs conectados al '* PORTB 0..7 '* Si PORTA.0 es 1 Va hacia arriba (De PORTB.0 a .7) '* Si PORTA.0 es 0 Va hacia abajo (De PORTB.7 a .0) '**************************************************************** @ DEVICE PIC16F628,WDT_OFF,PWRT_ON,MCLR_ON,BOD_OFF,CPD_OFF,PROTECT_OFF Define OSC 4 BARLED Var PORTB BARLED1 Var PORTB.0 BARLED2 Var PORTB.1 BARLED3 Var PORTB.2 BARLED4 Var PORTB.3 BARLED5 Var PORTB.4 BARLED6 Var PORTB.5 BARLED7 Var PORTB.6 BARLED8 Var PORTB.7 Inicio: CMCON = %00000111 ' Pines PortA a Digital (No comparator) TRISA = %00000001 ' El pin 0 de PORTA a Entrada TRISB = %00000000 ' Todos los pines del PORTB a Salida Gosub WashBarLed ' Pone a Low todos los BARLED Loop: if PORTA.0 = 1 then ' Hacia Arriba De BARLED1 a BARLED8 High BARLED1 : Gosub WashBarLed High BARLED2 : Gosub WashBarLed High BARLED3 : Gosub WashBarLed High BARLED4 : Gosub WashBarLed High BARLED5 : Gosub WashBarLed High BARLED6 : Gosub WashBarLed High BARLED7 : Gosub WashBarLed High BARLED8 : Gosub WashBarLed else ' Hacia Abajo De BARLED8 a BARLED1 High BARLED8 : Gosub WashBarLed High BARLED7 : Gosub WashBarLed High BARLED6 : Gosub WashBarLed High BARLED5 : Gosub WashBarLed High BARLED4 : Gosub WashBarLed High BARLED3 : Gosub WashBarLed High BARLED2 : Gosub WashBarLed High BARLED1 : Gosub WashBarLed Endif Goto Loop WashBarLed: Pause 500 BARLED = %00000000 return End |
||
Ejemplo en MPASM para el PIC 16F628: |
||
;**************************************************************** ;* barledasm.asm ;* Ilumina consecutivamente los LEDs conectados al ;* PORTB 0..7 ;* Si PORTA.0 es 1 Va hacia arriba (De PORTB.0 a .7) ;* Si PORTA.0 es 0 Va hacia abajo (De PORTB.7 a .0) ;**************************************************************** LIST p=16F628 ;Decimos al ensamblador qué micro estamos usando include "P16F628.inc" ;Incluimos las definiciones de nuestro micro ERRORLEVEL 0, -302 ;suprime mensajes de "bank selection" al ensamblar __config 0x3D18 ;configuramos (oscilador, tipo etc.) cblock 0x20 ;Comienzo de los registros de proposito general ;RAM en el Bank0 count1 ;Usado en la rutina Delay counta ;idem countb ;idem endc org 0x0000 ;org coloca el programa en el origen, 0x0000 para el 16F628, ;Por aquí es por donde empieza el programa a ejecutarse movlw 0x07 movwf CMCON ;Deshabilito los comparadores bcf STATUS, IRP bcf STATUS, RP1 bsf STATUS, RP0 ;Selecciono el Bank 1 para poder acceder a TRISA y TRISB movlw 0x00 movwf TRISB ;Configuro todo el PortB para que sea de salida movlw b'00000001' movwf TRISA ;Configuro el bit 0 de PortA para que sea de entrada bcf STATUS, RP1 bcf STATUS, RP0 ;Selecciono de nuevo el Bank 0 Call WshBarled ;Pongo a cero todo el PortB Loop btfss PORTA, 0 ;Salta si el bit 0 de PortA es '1' Call Up btfsc PORTA, 0 ;Salta si el bit 0 de PortA es '0' Call Down goto Loop ;Salto al comienzo y así hasta el infinito Up Call Pb0 ;Poner a '1' el Bit 0 de PortB el resto a '0' Call Pb1 ;Poner a '1' el Bit 1 de PortB el resto a '0' Call Pb2 ;Poner a '1' el Bit 2 de PortB el resto a '0' Call Pb3 ;Poner a '1' el Bit 3 de PortB el resto a '0' Call Pb4 ;Poner a '1' el Bit 4 de PortB el resto a '0' Call Pb5 ;Poner a '1' el Bit 5 de PortB el resto a '0' Call Pb6 ;Poner a '1' el Bit 6 de PortB el resto a '0' Call Pb7 ;Poner a '1' el Bit 7 de PortB el resto a '0' retlw 0x00 Down Call Pb7 ;Poner a '1' el Bit 7 de PortB el resto a '0' Call Pb6 ;Poner a '1' el Bit 6 de PortB el resto a '0' Call Pb5 ;Poner a '1' el Bit 5 de PortB el resto a '0' Call Pb4 ;Poner a '1' el Bit 4 de PortB el resto a '0' Call Pb3 ;Poner a '1' el Bit 3 de PortB el resto a '0' Call Pb2 ;Poner a '1' el Bit 2 de PortB el resto a '0' Call Pb1 ;Poner a '1' el Bit 1 de PortB el resto a '0' Call Pb0 ;Poner a '1' el Bit 0 de PortB el resto a '0' retlw 0x00 Pb0 movlw b'00000001' ;Pongo a '1' el bit 0 de PortB call SendPB ;Manda al Port B, espera, limpia, espera y vuelve retlw 0x00 Pb1 movlw b'00000010' ;Pongo a '1' el bit 1 de PortB call SendPB ;Manda al Port B, espera, limpia, espera y vuelve retlw 0x00 Pb2 movlw b'00000100' ;Pongo a '1' el bit 2 de PortB call SendPB ;Manda al Port B, espera, limpia, espera y vuelve retlw 0x00 Pb3 movlw b'00001000' ;Pongo a '1' el bit 3 de PortB call SendPB ;Manda al Port B, espera, limpia, espera y vuelve retlw 0x00 Pb4 movlw b'00010000' ;Pongo a '1' el bit 4 de PortB call SendPB ;Manda al Port B, espera, limpia, espera y vuelve retlw 0x00 Pb5 movlw b'00100000' ;Pongo a '1' el bit 5 de PortB call SendPB ;Manda al Port B, espera, limpia, espera y vuelve retlw 0x00 Pb6 movlw b'01000000' ;Pongo a '1' el bit 6 de PortB call SendPB ;Manda al Port B, espera, limpia, espera y vuelve retlw 0x00 Pb7 movlw b'10000000' ;Pongo a '1' el bit 7 de PortB call SendPB ;Manda al Port B, espera, limpia, espera y vuelve retlw 0x00 SendPB movwf PORTB ;Mando el contenido de W al PortB call Delay ;Llamo a la rutina que espera ... call WshBarled ;Llamo a la rutina que pone a cero PortB call Delay ;Llamo de nuevo a la rutina que espera ... retlw 0x00 WshBarled movlw b'00000000' ;Pongo a '0' todos los bits de PortB movwf PORTB retlw 0x00 Delay movlw d'250' ;Espero 250 ms (Para un reloj de 4 MHz) movwf count1 d1 movlw 0xC7 movwf counta movlw 0x01 movwf countb Delay_0 decfsz counta, f goto $+2 decfsz countb, f goto Delay_0 decfsz count1 ,f goto d1 retlw 0x00 end |
||
Experimento básico 3: 7 Segmentos |
|
|
|
Ejemplo en Picbasic Pro para el PIC 16F628: |
||
'**************************************************************** '* 7segbasic.bas '* Cuenta de 0 a F en un Display de 7 Segmentos '* conectado directamente a PORTB '* Si PORTA.0 1 Va hacia arriba (De 0 de F) '* Si PORTA.0 0 Va hacia abajo (De F a 0) '**************************************************************** @ DEVICE PIC16F628,WDT_OFF,PWRT_ON,MCLR_ON,BOD_OFF,CPD_OFF,PROTECT_OFF Define OSC 4 '* Variables **************************************************** MyNUM VAR Byte '* Redefiniciones *********************************************** V7SEG Var PORTB '* Constantes *************************************************** ND0 Con %00111111 ND1 Con %00000110 ND2 Con %01011011 ND3 Con %01001111 ND4 Con %01100110 ND5 Con %01101101 ND6 Con %01111101 ND7 Con %00000111 ND8 Con %01111111 ND9 Con %01100111 NDA Con %01110111 NDB Con %01111100 NDC Con %00111001 NDD Con %01011110 NDE Con %01111001 NDF Con %01110001 NDP Con %10000000 NDW Con %00000000 Inicio: CMCON = %00000111 ' Pines PortA a Digital (No comparator) TRISA = %00001111 ' Los pines 0 a 3 del PORTA a Entrada TRISB = %00000000 ' Todos los pines del PORTB a Salida Gosub WV7SEG ' Pone a Low todos los Segmentos Pause 1500 ' Espera 1.5 Segundos antes de comenzar MyNUM = 0 Loop: if PORTA.0 = 1 then Gosub IncMyNUM else Gosub DecMyNUM Endif Gosub WV7SEG Gosub Act7SEG Gosub Pausa Goto Loop WV7SEG: V7SEG = NDW return IncMyNUM: MyNUM = MyNUM + 1 if MyNUM = 16 then MyNUM = 0 return DecMyNUM: if MyNUM = 0 then MyNUM = 16 MyNUM = MyNUM - 1 return Act7SEG SELECT Case MyNUM Case 0 V7SEG = ND0 Case 1 V7SEG = ND1 Case 2 V7SEG = ND2 Case 3 V7SEG = ND3 Case 4 V7SEG = ND4 Case 5 V7SEG = ND5 Case 6 V7SEG = ND6 Case 7 V7SEG = ND7 Case 8 V7SEG = ND8 Case 9 V7SEG = ND9 Case 10 V7SEG = NDA Case 11 V7SEG = NDB Case 12 V7SEG = NDC Case 13 V7SEG = NDD Case 14 V7SEG = NDE Case 15 V7SEG = NDF Case Else V7SEG = NDP END SELECT return Pausa: Pause 333 return End |
||
Ejemplo en MPASM para el PIC 16F628: |
||
;7SEGasm LIST p=16F628 ;Decimos al ensamblador qué micro estamos usando include "P16F628.inc" ;Incluimos las definiciones de nuestro micro ERRORLEVEL 0, -302 ;suprime mensajes de "bank selection" al ensamblar __config 0x3D18 ;configuramos (oscilador, tipo etc.) cblock 0x20 ;Comienzo de los registros de propósito general ;RAM en el Bank0 MiNum ;Mi número contador count1 ;Usado en la rutina Delay counta ;ídem countb ;ídem endc SEG_PORT Equ PORTB ;Redefino Puerto donde conecto el Display 7Segmentos SEG_TRIS Equ TRISB org 0x0000 ;org coloca el programa en el origen, 0x0000 para el 16F628, ;Por aquí es por donde empieza el programa a ejecutarse movlw 0x07 movwf CMCON ;Deshabilito los comparadores bcf STATUS, IRP bcf STATUS, RP1 bsf STATUS, RP0 ;Selecciono el Bank 1 para poder acceder a SEG_TRIS movlw 0x00 movwf SEG_TRIS ;Configuro todo el SEG_PORT para que sea de salida bcf STATUS, RP1 bcf STATUS, RP0 ;Selecciono de nuevo el Bank 0 clrf SEG_PORT ;Limpio Display antes de empezar Inicio movlw 0x00 ;Inicializo MiContador movwf MiNum Main movfw MiNum ;Cargo en W Offset actual Call Display Call Del250 ;Espero 1/2 segundo Call Del250 incf MiNum, f ;Incremento MiNumero movf MiNum, w ;Cargo MiNum en W para testearlo y no pasarme de F sublw 0x10 ;Le resto 10 Hex btfss STATUS, Z ;Si el resultado es cero salto a Inicio goto Main ;En caso contrario a Main goto Inicio Display Call LED_Table ;Cargo W con el Pattern a dibujar movwf SEG_PORT ;Envío el Pattern al PORT_SEG retlw 0x00 LED_Table addwf PCL,f ;Sumo el Offset cargado al Program Counter (Low byte) ;para saltar al retorno que me interesa retlw b'00111111' ;0 retlw b'00000110' ;1 retlw b'01011011' ;2 retlw b'01001111' ;3 retlw b'01100110' ;4 retlw b'01101101' ;5 retlw b'01111101' ;6 retlw b'00000111' ;7 retlw b'01111111' ;8 retlw b'01100111' ;9 retlw b'01110111' ;A retlw b'01111100' ;B retlw b'00111001' ;C retlw b'01011110' ;D retlw b'01111001' ;E retlw b'01110001' ;F ;** Rutinas de Delay ************************************* Del250 movlw d'250' ;delay 250 ms goto Delay Delay movwf count1 d1 movlw 0xC7 ;delay 1mS movwf counta movlw 0x01 movwf countb Delay_0 decfsz counta, f goto $+2 decfsz countb, f goto Delay_0 decfsz count1 ,f goto d1 retlw 0x00 END |
||
Experimento básico 4: 4 x 7 Segmentos multiplexados |
|
|
Ejemplo en Picbasic Pro para el PIC 16F628: |
||
'**************************************************************** '* 7seg_x4.bas '* Cuenta de 0000 a FFFF en cuatro Display's de 7 Segmentos '* mediante Driver '* RB0..RB3 Datos, RB4..RB7 Selector del Display multiplexado '**************************************************************** @ DEVICE PIC16F628,WDT_OFF,PWRT_ON,MCLR_ON,BOD_OFF,CPD_OFF,PROTECT_OFF Define OSC 4 i Var byte j Var byte k Var byte l Var byte Inicio: TRISB = %00000000 ' Todos los pines del PORTB a Salida Pause 1500 ' Espera 1.5 Segundos antes de comenzar Loop: for l=9 to 0 step -1 for k=9 to 0 step -1 for j=9 to 0 step -1 for i=9 to 0 step -1 Gosub Muestra next i next j next k next l Goto Loop Muestra: PORTB = i PORTB.4=1 : PORTB.5=0 : PORTB.6=0 : PORTB.7=0 :Pause 4 PORTB = j PORTB.4=0 : PORTB.5=1 : PORTB.6=0 : PORTB.7=0 :Pause 4 PORTB = k PORTB.4=0 : PORTB.5=0 : PORTB.6=1 : PORTB.7=0 :Pause 4 PORTB = l PORTB.4=0 : PORTB.5=0 : PORTB.6=0 : PORTB.7=1 :Pause 4 return End |
||
Experimento básico 5: Interrupción Externa por RB0 |
|
|
|
Control de Interrupción Externa. Ejemplo en CCS PICC |
||
// ExtInt #include <16f876a.h> // Selecciona el PIC #fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT // Opciones de configuración #use delay(clock=4000000) // Velocidad del Cristal : 4 Mhz #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)// Definición del RS232 int fEXT=0x00; int nEXT=0x00; #int_EXT EXT_isr() { fEXT=0x01; ++nEXT; } void main() { enable_interrupts(int_ext); enable_interrupts(global); nEXT=0x00; printf("\r\n\IntExt waiting ... \r\n"); do { if(fEXT==0x01){ fEXT=0x00; printf("IntExt %u \r\n",nEXT); } } while (TRUE); } |
||
|
|
|
Experimento básico 6: Escribiendo en el LCD lo recibido por la RS-232 |
|
|
Escribiendo en el LCD. Ejemplo en CCS PICC |
||
#include <16f876a.h> #fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT #use delay(clock=4000000) #use standard_io(b) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) #define LCD_DB4 PIN_B4 #define LCD_DB5 PIN_B5 #define LCD_DB6 PIN_B6 #define LCD_DB7 PIN_B7 #define LCD_RS PIN_C0 #define LCD_RW PIN_C1 #define LCD_E PIN_C2 #include "flex_lcd.c" char Keypress=' '; #int_rda void serial_isr() { Keypress=0x00; if(kbhit()){ Keypress=getc(); } } void main() { enable_interrupts(global); enable_interrupts(int_rda); printf("\r\n\LCD driver monitor\r\n"); lcd_init(); do { if(Keypress!=0x00){ lcd_putc(Keypress); putc(Keypress); Keypress=0x00; } } while (TRUE); } |
||
Experimento básico 7: Conectando con un periférico mediante I2C |
|
|
|
da_i2c.c | ||
#include <16f876a.h> #fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT #use delay(clock=4000000) int analogico=0x00; #use i2c(master,sda=PIN_C4, scl=PIN_C3) // Configuración del I2C como Master // y los pines del MSSP en mi 16F876A. void main() { i2c_start(); // Inicio la comunicación I2C i2c_write(0b10010000); // Envío Dirección I2C del PCF8591 i2c_write(0b01000000); // Envío Configuración del PCF8591 para Conv. DA do { i2c_write(++analogico); // Envío Valor digital 0x00->0V, 0xFF->Vcc } while (TRUE); } |
||
Experimento básico 8: Conversión AD de luminosidad y temperatura. |
|
|
|
_ad_temperatura_lm35a_232.c | ||
#include <16f876a.h> #fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT #use delay(clock=4000000) #use standard_io(b) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) int adc_luminosidad=0x00; int adc_temperatura=0x00; int grados_temperatura=0; char Keypress=' '; #int_rda void rda_isr() { Keypress=0x00; if(kbhit()){ Keypress=getc(); } } void toma_adc_y_transmite(void){ // Lectura del canal 0 -> AN0 LDR set_adc_channel(0); delay_ms(1); adc_luminosidad=read_adc(); delay_ms(1); // Lectura del canal 1 -> AN1 LM35a set_adc_channel(1); delay_ms(1); adc_temperatura=read_adc(); delay_ms(1); grados_temperatura = (int) ((adc_temperatura * 391) / 1000); printf(" L = %u T = %u (adc= %u)\n",adc_luminosidad,grados_temperatura,adc_temperatura); } void main() { setup_adc(ADC_CLOCK_INTERNAL); setup_adc_ports(RA0_RA1_ANALOG_RA3_REF); output_low(PIN_B5); enable_interrupts(int_rda); enable_interrupts(global); printf("\n\ AD - LM35a - Monitor\n\n"); do { if(Keypress!=0x00){ switch(Keypress){ case 't': toma_adc_y_transmite(); break; case '0': output_low(PIN_B5); printf(" 0 - Calentador OFF\n"); break; case '1': output_high(PIN_B5); printf(" 1 - Calentador ON\n"); break; } Keypress=0x00; } } while (TRUE); } |
||
|
|
Experimento básico 9: Rastreando un Teclado Matricial 4x4 y enviando a la RS232 |
|
|
KBD_Test en CCS PIC C | ||
#include <16f876a.h> #fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT #use delay(clock=4000000) #use fast_io(b) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) #include "kbd_lib.c" void main(){ char mitecla=0; kbd_init(); printf("\rKeyboard 4x4 monitor\r\r"); do { mitecla=kbd_getc(); if(mitecla!=0){ putc(mitecla); } } while (TRUE); } |
||
|
|
|
Experimento básico 10: Escribiendo una EEPROM externa vía I2C |
|
|
|
|
|
|
El programa queda tal como sigue: |
eeprom_rs232_i2c.c | ||
#include <16f876a.h>
// Definiciones del PIC 16F876A #fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT // Los Fuses de siempre #use delay(clock=4000000) // Oscilador a 4 Mhz #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)// Definición RS232 estándar #use i2c(master,sda=PIN_C4, scl=PIN_C3) // Definición I2C estándar #include <ctype.h> #include <string.h> // CONSTANTES ///////////////////////////////////////////////////////////////// int const lenbuff=32; // Longitud de buffer, Ajustar // a lo que desees (o te sea posible) int const address_EEPROMR=0b10100001; // Dirección I2C de EEPROM (para lectura) int const address_EEPROMW=0b10100000; // Dirección I2C de EEPROM (para escritura) // 1010 000 0 // ---- --- - // | | R/W // | Hard // Fijo int const ddeeeprom=32; // Delay Default EEPROM // VARIABLES EN RAM /////////////////////////////////////////////////////////// int xbuff=0x00; // Índice: siguiente char en cbuff char cbuff[lenbuff]; // Buffer char rcvchar=0x00; // último carácter recibido int1 flagcommand=0; // Flag para indicar comando disponible // Declaración de Funciones /////////////////////////////////////////////////// void presmenu(void); // Presenta el menú void inicbuff(void); // Borra buffer int addcbuff(char c); // añade carácter recibido al buffer void echos(char c); // Eco selectivo sobre RS232 void comando(void); // Procesa comando int ascii2hex(char d); // Convierte un carácter ascii a hex void i2cw1(int i2cdev, int i2cdir, int i2cdat); // Rutina de escritura I2C completa void i2cw2(int i2cdev, int i2cdat); // Rutina de escritura I2C parcial int i2cr(int i2cdev); // Rutina de lectura I2C // INTERRUPCIONES ///////////////////////////////////////////////////////////// #int_rda void serial_isr() { // Interrupción recepción serie USART rcvchar=0x00; // Inicializo carácter recibido if(kbhit()){ // Si hay algo pendiente de recibir ... rcvchar=getc(); // lo descargo y ... addcbuff(rcvchar); // lo añado al buffer y ... echos(rcvchar); // hago eco (si procede). } } // Desarrollo de Funciones //////////////////////////////////////////////////// void presmenu(void){ // Presenta el menú -------------------- delay_ms(25); printf("\r\n" ); printf("** EEPROM I2C OS **\r\n\n" ); // Presenta menú printf("** Control del buffer:\r\n" ); printf("[Enter] Procesa comando\r\n" ); printf("[Escape] Borra todo el buffer\r\n" ); printf("[Delete] Borra último carácter del buffer\r\n" ); printf("\n" ); printf("** Comandos EEPROM:\r\n" ); printf("/? Presenta Menú\r\n" ); printf("/B Formatea (borra) eeprom iniciando <indice> a 0.\r\n" ); printf("/r Lee contenido completo de eeprom y vuelca a RS232.\r\n" ); printf("/w <dat> Escribe <dat> en eeprom a partir de <indice>.\r\n" ); printf("/i <dir> Coloca índice de eeprom a <0xdir> sin borrar contenido.\r\n" ); printf("\n" ); delay_ms(25); } int addcbuff(char c){ // Añade a cbuff ----------------------- switch(c){ case 0x0D: // Enter -> Habilita Flag para procesar flagcommand=1; // Comando en Main break; case 0x08: // Del -> Borra último carácter del Buffer if(xbuff>0) cbuff[--xbuff]=0x00; break; case 0x01B: // Esc -> Borra el Buffer completamente inicbuff(); break; default: cbuff[xbuff++]=c; // Añade carácter recibido al Buffer if(xbuff>lenbuff) xbuff=lenbuff; } } void echos(char c){ // Echo selectivo ---------------------- int i; switch(c){ case 0x0D: printf("\r\n" ); // Si he pulsado la tecla [Intro] break; case 0x08: printf("\r%s \b",cbuff); // Si he pulsado la tecla [Retroceso] break; case 0x1B: printf("\r" ); // Si he pulsado la tecla [Escape] for(i=0;i<lenbuff;i++){ printf(" " ); // Borra display (en la longitud del buffer) } printf("\r" ); break; default: putc(rcvchar); // Echo de cualquier otro carácter } } void inicbuff(void){ // Inicia a \0 cbuff ------------------- int i; for(i=0;i<lenbuff;i++){ // Bucle que pone a 0 todos los cbuff[ i ]=0x00; // caracteres en el buffer } xbuff=0x00; // Inicializo el índice de siguiente // carácter } int ascii2hex(char d){ // Convierte un carácter ascii a hex --- int r=0x00; if(isxdigit(d)){ if(isdigit(d)){ r=d-'0'; } if(isalpha(d)){ d=toupper(d); r=10+(d-'A'); } } return(r); } void i2cw1(int i2cdev, int i2cdir, int i2cdat){ // Rutina de escritura I2C completa i2c_start(); // Inicializo comunicación I2C i2c_write(i2cdev); // Envío Dirección de dispositivo I2C + R/W i2c_write(i2cdir); // Envió address eeprom donde escribir i2c_write(i2cdat); // Envío byte a escribir i2c_stop(); // Cierro comunicación delay_ms(ddeeeprom); // Espero a que escriba correctamente } void i2cw2(int i2cdev, int i2cdat){ // Rutina de escritura I2C parcial i2c_start(); // Inicializo comunicación I2C i2c_write(i2cdev); // Envío Dirección de dispositivo I2C + R/W i2c_write(i2cdat); // Envío byte a escribir i2c_stop(); // Cierro comunicación delay_ms(ddeeeprom); // Espero a que escriba correctamente } int i2cr(int i2cdev){ // Rutina de lectura I2C int r=0x00; i2c_start(); i2c_write(i2cdev); r=i2c_read(); i2c_stop(); delay_ms(ddeeeprom); return(r); } // Programa Principal ///////////////////////////////////////////////////////// void main() { inicbuff(); // Borra buffer al inicio presmenu(); // Presenta el menú enable_interrupts(int_rda); // Habilita Interrupción RDA enable_interrupts(global); // Habilita interrupciones delay_ms(25); do { if(flagcommand) comando(); // Si hay comando pendiente // de procesar ... lo procesa. } while (TRUE); } // Procesador de Comandos ///////////////////////////////////////////////////// void comando(void){ int i,j,u,h; int1 flagvalido=0; // Flag para detectar comandos inválidos char arg[lenbuff]; // Argumento de comando (si lo tiene) disable_interrupts(int_rda); // Deshabilito Interrupción RDA durante procesado flagcommand=0; // Desactivo flag de comando pendiente. for(i=0;i<lenbuff;i++){ // Limpia el argumento (por si lo hay) arg[ i ]=0x00; } // Comando /? if(cbuff[0]=='/'&&cbuff[1]=='?'){ // Comparo inicio del buffer con comando "/?" flagvalido=1; // Marco comando válido presmenu(); // Presenta el menú } // Comando /B if(cbuff[0]=='/'&&cbuff[1]=='B'){ // Comparo inicio del buffer con comando "/B" flagvalido=1; // Marco comando válido printf("\r\nFormateando " ); j=0; for(i=0;i<255;i++){ i2cw1(address_EEPROMW,i,0x00);// Envío Dirección de dispositivo I2C + Escribir // Envío address eeprom donde escribir // Envío byte a escribir (0x00) if(++j>14){ // Monitorizo en bloques de 15 bytes j=0; putc('.'); } } printf("\r\nFormateado Ok.\r\n\r\n" ); } // Comando /r if(cbuff[0]=='/'&&cbuff[1]=='r'){ // Comparo inicio del buffer con comando "/R" flagvalido=1; // Marco comando válido i2cw2(address_EEPROMW,0x00); // Inicializo dirección a partir de la que leer // que fijo desde el primer byte for(i=0;i<16;i++) printf("%X ",i); // Pongo cabecera de direcciones printf("\r\n" ); for(i=0;i<16;i++) printf("== " ); printf("\r\n" ); j=0; i2c_start(); // Realizo la lectura completa de la EEPROM i2c_write(address_EEPROMR); for(i=0;i<255;i++){ u=i2c_read(); printf("%X ",u); // y vuelco en bloques de 15 bytes if(++j>15){ j=0; printf("\r\n" ); } } i2c_stop(); printf("\r\n\r\n" ); } // Comando /w dat if(cbuff[0]=='/'&&cbuff[1]=='w'){ // Comparo inicio del buffer con comando "/w" flagvalido=1; // Marco comando válido i=3; do{ // Extraemos argumento del buffer arg[i-3]=cbuff[ i ]; // a partir del 4º byte y hasta \0. }while(cbuff[++i]!=0x00); // recupero posición inicial <indice> para escribir i2cw2(address_EEPROMW,0x00); // Inicializo dirección a partir de la que leer // que fijo desde el primer byte h=i2cr(address_EEPROMR); // leo el valor de índice ++h; printf("\r\nEscribir %s a partir de %X\r\n\r\n",arg,h); i2cw2(address_EEPROMW,h); // Inicializo dirección a partir de la que leer // que fijo desde el <indice> // escribo argumento a partir de índice i=0; do{ i2cw1(address_EEPROMW,h,arg[ i ]);// Envío Dirección de dispositivo I2C + Escribir // Envío address eeprom donde escribir -> h // Envío byte a escribir -> arg[ i ] ++h; ++i; }while(arg[ i ]!=0x00); // Actualizo indice --h; i2cw1(address_EEPROMW,0x00,h);// Envío Dirección de dispositivo I2C + Escribir // Envío address eeprom donde escribir -> 0x00 // Envío byte a escribir -> h printf("Buffer Escrito.\r\n\r\n" ); } // Comando /i dir if(cbuff[0]=='/'&&cbuff[1]=='i'){ // Comparo inicio del buffer con comando "/i" flagvalido=1; // Marco comando válido i=3; do{ // Extraemos argumento del buffer arg[i-3]=cbuff[ i ]; // a partir del 4º byte y hasta \0. }while(cbuff[++i]!=0x00); h=(16*ascii2hex(arg[0]))+(ascii2hex(arg[1])); // Convierto de Hex-Ascci-2-digitos // al entero correspondiente i2cw1(address_EEPROMW,0x00,h); // Escribo nuevo índice en 0x00 printf("> i=%X hex (%u dec)\r\n",h,h); // Monitorizo lo realizado. } // Retorno error o comando invalido if(!flagvalido) printf("¿%s?\r\n",cbuff); inicbuff(); // Borro buffer. enable_interrupts(int_rda); // Habilita de nuevo Interrupción RDA } |
||
|
![]() |
![]() |
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. |
Esta página fue modificada el 07-08-2010 22:42:20