SDCC: Driver para ADC PIC16f87x.
Página 1 de 1. • Compartir •
SDCC: Driver para ADC PIC16f87x.
Todavía un primer "boceto" hecho a partir del adc para pic18f* pero simplificado... aunque en realidad las funciones son bastante diferentes, no lo he probado, pero ahí vá:
EDITO:
Arreglados algunos fallos y probado que funciona en un pic16f876a, tanto el archivo para descargar como el código mostrado han sido actualizados.
Faltaría confirmar que funciona en otros pics y sinó ver como solucionarlo.
Archivo para descargar: adc_sdcc_sgr.h
Y aquí se puede echar un ojo al código:
EDITO:
Arreglados algunos fallos y probado que funciona en un pic16f876a, tanto el archivo para descargar como el código mostrado han sido actualizados.
Faltaría confirmar que funciona en otros pics y sinó ver como solucionarlo.
Archivo para descargar: adc_sdcc_sgr.h
Y aquí se puede echar un ojo al código:
- Código:
/*****************************************************************************
******************************************************************************
**** ****
**** --- DRIVER ADC para PIC16F --- ****
**** ****
******************************************************************************
******************************************************************************
FUNCIONES DISPONIBLES:
------------------------------------------------------------------------------
adc_init( FOSC_32, A5_R0, INT_OFF); iniciar módulo ADC, donde:
FOSC_32:
Frecuencia de adc, en este caso 1/32 de la del oscilador del pic
A5_R0:
Definir entradas analógicas y Vref, en este caso todas las 5 del pic16f876a como analógicas y ninguna como Vref, Vref serán Vdd y GND (ver las posibles combinaciones en el driver y datasheet del pic a usar.
INT_OFF:
Interrupciones ADC deshabilitadas, la otra posiblidad es INT_ON.
adc_read(1); Leer canal ADC.
adc_close(); cerrar módulo ADC.
******************************************************************************
*****************************************************************************/
/* flag de interrupciones on/off */
#define INT_OFF 0x00
#define INT_ON 0x01
/* frequencia de oscillador */
#define FOSC_2 0x00
#define FOSC_4 0x04
#define FOSC_8 0x01
#define FOSC_16 0x05
#define FOSC_32 0x02
#define FOSC_64 0x06
#define FOSC_RC 0x07
/* configuracion de entradas y Vref(PCFG en ADCON1) */
#define A8_R0 0x00
#define A7_R1 0x01
#define A5_R0 0x02
#define A4_R1 0x03
#define A3_R0 0x04
#define A2_R1 0x05
#define A0_R0 0x06
#define A6_R2 0x08
#define A6_R0 0x09
#define A5_R1 0x0a
#define A4_R2 0x0b
#define A3_R2 0x0c
#define A2_R2 0x0d
#define A1_R0 0x0e
#define A1_R2 0x0f
void adc_init(unsigned char fosc, unsigned char pcfg, unsigned char config)
{
ADCON0 = 0;
ADCON0 = (fosc & 0x03) << 6; // establecer frecuencia
ADCON1 = (pcfg & 0x0F) | 0x080; // establecer entradas
if (fosc & 0x04)
ADCS2 = 1;
if (config & INT_ON) // establecer interrupciones
{
ADIF = 0;
ADIE = 1;
PEIE = 1;
}
ADON = 1; // habilitar módulo ADC
}
void adc_close(void) // deshabilitar módulo ADC
{
ADON = 0;
ADIE = 0;
}
unsigned int adc_read(unsigned char canal)
{
unsigned int valor;
ADCON0 &= 0xC7; // borrar anteriores selecciones
ADCON0 |= (canal & 0x07) << 3; // establecer canal seleccionado
GO = 1; // iniciar conversión
while (GO); // esperar que termine
valor = ADRESH << 8 | ADRESL; // leer valor
return valor;
}
Última edición por arcachofo el Vie 26 Dic 2008 - 1:35, editado 1 vez

arcachofo- Participante Activo

- Cantidad de envíos: 90
Fecha de inscripción: 26/11/2008
SDCC: Driver para ADC PIC16f87x. Versión en ASM
Pues ahí vá una nueva versión del driver ADC, esta vez está escrita en ASM y dividiendo la función adc_read(canal) en dos: adc_open(canal) y adc_read() , así se disminuye el tamaño del ejecutable generado en caso de leer varias veces el mismo canal, también he sacado las funciones de interrupciones por adc: adc_int_on() y adc_int_off(). Dividiendo las funciones también se ahorran lineas ya que solo se insertan las que se usan.
Al estar escrito directamente en asm y todo lo optimizado que he podido, el tamaño del código generado es mucho menor, casi la mitad en comparación con el driver escrito en C.
EDITO:
Las funciones han cambiado un poco:
adc_init( fosc, channel ); //las posibles opcines las puedes ver en los #defines
ejemplo:
adc_init( FOSC_4, A2_R2 ); // fosc/4 y 2 entradas adc + 2 Vref (RA2 como - y RA3 como +)
adc_init( FOSC_64, A1_R0 ); //fosc/64 y 1 entrada adc + ninguna Vref
Para ver las distintas combinaciones de entradas adc y Vref ver el datasheet.
He separado la apertura y la lectura del canal, para ahorrar código y aumentar velocidad en caso de leer varias veces el mismo canal; tambien uso algunos #defines para disminuir instrucciones, en vez de poner el número del canal hay que ponerlo como: CH_1, CH_2, CH_3... etc.:
adc_open( CH_1 ); // abrir canal 1
adc_read(); // lee canal previamente abierto
adc_close(); //deshabilita módulo adc
Al estar escrito directamente en asm y todo lo optimizado que he podido, el tamaño del código generado es mucho menor, casi la mitad en comparación con el driver escrito en C.
EDITO:
Las funciones han cambiado un poco:
adc_init( fosc, channel ); //las posibles opcines las puedes ver en los #defines
ejemplo:
adc_init( FOSC_4, A2_R2 ); // fosc/4 y 2 entradas adc + 2 Vref (RA2 como - y RA3 como +)
adc_init( FOSC_64, A1_R0 ); //fosc/64 y 1 entrada adc + ninguna Vref
Para ver las distintas combinaciones de entradas adc y Vref ver el datasheet.
He separado la apertura y la lectura del canal, para ahorrar código y aumentar velocidad en caso de leer varias veces el mismo canal; tambien uso algunos #defines para disminuir instrucciones, en vez de poner el número del canal hay que ponerlo como: CH_1, CH_2, CH_3... etc.:
adc_open( CH_1 ); // abrir canal 1
adc_read(); // lee canal previamente abierto
adc_close(); //deshabilita módulo adc
- Código:
/*
This code is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// frequencia de oscillador: bit5=_ADCON1.ADCS2, bit6=_ADCON0.ADCS0, bit7=_ADCON0.ADCS1
#define FOSC_2 0x00
#define FOSC_4 0x20
#define FOSC_8 0x40
#define FOSC_16 0x60
#define FOSC_32 0x80
#define FOSC_64 0xA0
#define FOSC_RC 0xE0
// configuracion de entradas y Vref(PCFG0-3 en _ADCON1)
#define A8_R0 0x00
#define A7_R1 0x01
#define A5_R0 0x02
#define A4_R1 0x03
#define A3_R0 0x04
#define A2_R1 0x05
#define A0_R0 0x06
#define A6_R2 0x08
#define A6_R0 0x09
#define A5_R1 0x0a
#define A4_R2 0x0b
#define A3_R2 0x0c
#define A2_R2 0x0d
#define A1_R0 0x0e
#define A1_R2 0x0f
// selección de canal: usados bits 3-5 = ADCON0.CHS0-CHS2
#define CH_0 0x00
#define CH_1 0x08
#define CH_2 0x10
#define CH_3 0x18
#define CH_4 0x20
#define CH_5 0x28
#define CH_6 0x30
#define CH_7 0x38
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void adc_init(unsigned char fosc, unsigned char channel)
{
fosc;
channel;
_asm
BANKSEL STK01
MOVWF STK01 ;// fosc
// Ajustar _ADCON1
RLF STK01,W
ANDLW 0x40 ;// selecciona bit 6 de fosc (5º rotado)
IORWF STK00,W ;// Une channel y bit 6 de fosc (5º rotado)
BANKSEL ADCON1
MOVWF ADCON1 ;// Establece configuración de entradas y frecuencia (ADCS2)
BSF ADCON1,7 ;// Establece justificado a la derecha
// Ajustar _ADCON0
MOVF STK01,W ;// fosc
ANDLW 0xC0 ;// selecciona bits 6-7 de fosc (W)
BANKSEL ADCON0;
MOVWF ADCON0 ;// Establece frecuencia en _ADCON0 (ADCS0, ADCS1)
BSF ADCON0,0 ;// Habilita módulo ADC
_endasm;
}
void adc_open (unsigned char channel)
{
channel;
_asm
BANKSEL ADCON0
BCF ADCON0,3 ;// Borra anteriores selecciones
BCF ADCON0,4
BCF ADCON0,5
IORWF ADCON0,F ;// Establece canales abiertos (chanel en W)
_endasm;
}
unsigned int adc_read()
{
_asm
BANKSEL ADCON0
BSF ADCON0,2 ;// Inicia conversión
BTFSC ADCON0,2 ;// Espera que termine
GOTO $-1
BANKSEL ADRESL
MOVF ADRESL,W
BANKSEL STK00
MOVWF STK00
BANKSEL ADRESH
MOVF ADRESH,W
_endasm;
}
void adc_int_on()
{
_asm
BANKSEL PIE1
BSF PIE1,6 ;// Activa interrupciones ADC
BSF INTCON,6 ;// Activa inerrupciones periféricos
BANKSEL PIR1;
BCF PIR1,6 ;// Borra flag interrupciones ADC
_endasm;
}
void adc_int_off()
{
_asm
BANKSEL PIE1
BCF PIE1,6 ;// Desactiva interrupciones ADC
BANKSEL PIR1
BCF PIR1,6 ;// Borra flag interrupciones ADC
_endasm;
}
void adc_close()
{
adc_int_off();
_asm
BCF ADCON0,0 ;// Deshabilita módulo ADC
_endasm;
}

arcachofo- Participante Activo

- Cantidad de envíos: 90
Fecha de inscripción: 26/11/2008
Permiso de este foro:
No puedes responder a temas en este foro.





