EJEMPLO DE FUNCIÓN EN ENSAMBLADOR
No es difícil llamar a rutinas en ensamblador desde C51, si se lee este capítulo y el manual del usuario del compilador.
En contadas ocasiones el código generado por el compilador C51 no es adecuado para una determinada aplicación y se necesita recurrir al lenguaje ensamblador.
Si una función escrita en lenguaje ensamblador no recibe parámetros, la llamada a la misma es como la llamada a cualquier función C. Se necesita un prototipo de función extern antes de realizar una llamada a la misma:
Fichero C51:
extern void asm_func(void).
Fichero A51:
ASM_FUNC: MOV A,#10 ; instrucciones en ensamblador 8051
Si se deben pasar parámetros, C51 colocará los primeros parámetros en registros, tal como se apunta en esta sección.
La complicación aparece cuando todos los parámetros no caben en los registros. En este caso el usuario debe declarar un área de memoria en la que poder ubicar los parámetros extra. Así la función en ensamblador debe tener definido un segmento DATA conforme a los convenios sobre nombres esperados por C51.
En el ejemplo que sigue, el segmento
?DT?_WRITE_EE_PAGE?WRITE_EE SEGMENT DATA OVERLAYABLE
hace exactamente eso.
El mejor consejo es escribir un programa C que llame a la función en ensamblador, y compilarlo con la opción SRC para producir su equivalente en ensamblador. Luego debe observarse lo que hace C51 cuando llama la la función en ensamblador todavía sin escribir. Si se utiliza el nombre de segmento generado por C51 no habrá problemas.
Ejemplo de función en ensamblador con muchos parámetros
Llamada a función desde C
Las siguientes líneas deben añadirse al programa C que llama a la función en ensamblador:
#define UCHAR unsigned char /* referencia "extern" a la rutina en ensamblador */ extern UCHAR write_ee_page(char*,UCHAR,UCHAR) ; void dummy(void) { UCHAR number, eeprom_page_buffer, ee_page_length ; char * current_ee_page ; number = write_ee_page (current_ee_page, eeprom_page_buffer, ee_page_length) ; } /* FIN DE dummy */ |
La rutina en ensamblador es:
NAME EEPROM_WRITE ; PUBLIC _WRITE_EE_PAGE ; Esencial!!! PUBLIC ?_WRITE_EE_PAGE?END_ADDRESS ; PUBLIC ?_WRITE_EE_PAGE?END_BUFFER ; ; P6 EQU 0FAH ; Un pin del puerto P6 actúa sobre el watchdog;*************************************************************** ;*<<<<<<<<< Declarar los segmentos CODE y DATA para la Rutina en Ensamblador >>>>>>>>>>>* ;**************************************************************; ?PR?_WRITE_EE_PAGE?WRITE_EE SEGMENT CODE ?DT?_WRITE_EE_PAGE?WRITE_EE SEGMENT DATA OVERLAYABLE ; ; ;************************************************************** ;*<<<<<< Declarar el área de memoria en RAM interna para Variables locales, Etc. >>>>>>* ;************************************************************** ; RSEG ?DT?_WRITE_EE_PAGE?WRITE; ?_WRITE_EE_PAGE?END_ADDRESS: DS 2 ; ?_WRITE_EE_PAGE?END_BUFFER: DS 1 ; ; ; ;************************************************************** ;*<<<<<<<<<<<<<<< Función de escritura de página EEPROM ;************************************************************** ; RSEG ?PR?_WRITE_EE_PAGE?WRITE ; ; _ WRITE_EE_PAGE: CLR EA MOV DPH,R6 ; Dirección de la EEPROM en R7/R6 MOV DPL,R7 ; ; MOV A,R3 ; Longitud del buffer en R3 DEC A ; ADD A,R7 ; Calcular dirección del último byte de la MOV ?_WRITE_EE_PAGE?END_ADDRESS+01H,A ; página en XDATA. CLR A ; ADDC A,R6 ; MOV ?_WRITE_EE_PAGE?END_ADDRESS,A ; ; MOV A,R5 ; La dirección del buffer IDATA en R5 MOV R0,A ; ADD A,R3 ; MOV ?_WRITE_EE_PAGE?END_BUFFER,A ; ; LOOP: MOV A,@R0 ; MOVX @DPTR,A ; INC R0 ; INC DPTR ; MOV A,R0 ; CJNE A,?_WRITE_EE_PAGE?END_BUFFER,LOOP ; ; MOV DPH,?_WRITE_EE_PAGE?END_ADDRESS ; MOV DPL,?_WRITE_EE_PAGE?END_ADDRESS+01H ; DEC R0 ; ; CHECK: XRL P6,#08 ; Refrescar el watchdog del MAX691 MOVX A,@DPTR ; CLR C ; SUBB A,@R0 ; JNZ CHECK ; ; SETB EA ; RET ; Retorna al programa C; END ;