Sei sulla pagina 1di 6

Dispositivos de Control. Gua de Practicas.

Practica 3 Llamado a Funciones en Ensamblador desde C.


Objetivo.

El Alumno aprender a reutilizar las subrutinas que realiza en ensamblador en lenguaje C,


para de esta manera tener su propia biblioteca de rutinas que pueda utilizar en otros programas.

Introduccin.

El lenguaje ensamblador es una de las herramientas ms poderosas que tiene el diseador


de sistemas embebidos, ya que este nos permite manejar de manera ptima el hardware
muchas veces limitado que tenemos.

Las rutinas en ensamblador nos dan informacin y control sobre el tiempo de ejecucin del
cdigo, y los recursos utilizados, como son la memoria tanto de programa como de datos
necesaria para realizar una tarea.

Desgraciadamente, el lenguaje ensamblador es mucho ms complicado de programar, por


lo que desarrollar una aplicacin enteramente en ensamblador puede generarnos un mayor
costo debido a los tiempos de diseo, puesta a punto, y llegada al mercado. En cambio, los
lenguajes de alto nivel como el C, nos proporcionan tiempos de desarrollo y llegada al mercado
ms rpidos, a costa de tener menor control sobre los recursos.

El software de un sistema embebido puede dividirse en 2 partes. La primera es la


aplicacin propiamente dicha (medicin de variables, control de motores, comunicacin de
datos, etc.); esta parte de la aplicacin, normalmente se ve sujeta a limitaciones en cuanto
tiempo de ejecucin, por lo que es ms prctico, y en ocasiones necesario desarrollarla en
ensamblador. La segunda parte del cdigo, es la interfaz de usuario. Normalmente las interfaces
de usuario son muy complejas, ya que deben de presentar la informacin generada por el
sistema de tal forma que sea fcil y agradable de leer, as como pedir datos de entrada o ajustes
al usuario, y evitar que dichos valores sean incorrectos. Debido a que esta seccin del cdigo no
suele estar sujeta a restricciones de tiempo de ejecucin, es preferible desarrollarlas en un
lenguaje de alto nivel, a fin de reducir nuestros tiempos de programacin.

De lo anterior nos es claro que poder mezclar ambos tipos de programacin nos beneficiaria, ya que podramos
obtener las ventajas de cada uno de los lenguajes.

El PSoC Designer nos permite usar subrutinas desarrolladas en ensamblador desde lenguaje C, por medio de la
directiva #pragma fastcall16 que nos permite llamar a funciones en ensamblador desde C.

Conexiones.

Conecta tu LCD al Puerto 2 del PSoC, y tu teclado matricial al Puerto 1 como se hizo en la Practica 2. No se
necesitar ms hardware.

MC. Edgar Mauricio Romero Lpez


Dispositivos de Control. Gua de Practicas.

Desarrollo.

Iniciaremos creando un proyecto en C y le Llamaremos Practica3a. En este Proyecto usaremos el mdulo de

LCD (y el de LED en caso de que el LCD tenga Luz), no utilizaremos la barra y lo conectaremos al puerto 2 con los

mismos parmetros de la prctica anterior. El Teclado Matricial se conectar al puerto 1; este puerto deber configurarse

como Pull-Up.

Teclea el Siguiente Cdigo en el archivo main.


//----------------------------------------------------------------------------
// C main line
//----------------------------------------------------------------------------

#include <m8c.h> // part specific constants and macros


#include "PSoCAPI.h" // PSoC API definitions for all User Modules
#include "Subrutinas.h" // Incluimos nuestras subrutinas

char Unidades, Decenas, Centenas; Tecla;


int Valor;
void main(void)
{
LCD_Start();
LED_Start();
LED_On();
Unidades = '0';
Decenas = '0';
Centenas = '0';
LCD_Position(0,0);
LCD_PrCString("Numero: ");
LCD_Position(1,0);
LCD_PrCString("Valor Hex: ");
while(1){
LCD_Position(0,8);
LCD_WriteData(Centenas);
LCD_WriteData(Decenas);
LCD_WriteData(Unidades);
Tecla = 0;
while (Tecla == 0){
Tecla = ReadKey();
if ((Tecla > '9') | (Tecla <'0')){
if (Tecla =='D'){
Valor = 100*(Centenas-'0')+10*(Decenas-'0')+(Unidades-'0');
LCD_Position(1,11);
LCD_PrHexInt(Valor);
}
Tecla = 0;
}
}
Centenas = Decenas;
Decenas = Unidades;
Unidades = Tecla;
}
}

Lee el cdigo y explica que crees que hace.

Ahora ve al men File y selecciona New File, o Presiona el cono de Archivo Nuevo en la barra de mens. Te
aparecer una ventana pidindote el tipo y nombre del archivo que vas a crear. Selecciona .asm File y dale como
Nombre Subrutinas.

MC. Edgar Mauricio Romero Lpez


Dispositivos de Control. Gua de Practicas.

En este nuevo archivo vamos a crear nuestras subrutinas en ensamblador. Teclea el siguiente cdigo en este
nuevo archivo.
; __________________________________________________________________________
; | Archivo de Subrutinas |
; __________________________________________________________________________

include "m8c.inc" ; part specific constants and macros


include "memory.inc" ; Constants & macros for SMM/LMM and Compiler
include "PSoCAPI.inc" ; PSoC API definitions for all User Modules

Filas: equ 0x0F


Columnas: equ 0xF0
Row4: equ 0b00000111
Row3: equ 0b00001011
Row2: equ 0b00001101
Row1: equ 0b00001110
Col4: equ 0b11100000
Col3: equ 0b11010000
Col2: equ 0b10110000
Col1: equ 0b01110000
KeyPort: equ PRT1DR

export ReadKey
export _ReadKey

area text(ROM, REL)


; --------------------------------------------------------------------------
; Subrutina de Lectura de un Teclado Matricial en el Puerto "KeyPort"
; Regresa en el Acumulador el valor ASCII de la tecla presionada
; Esta subrutina modifica el valor del Acumulador
; Esta subrutina requiere que el puerto este configurado como Pull-Up
; --------------------------------------------------------------------------
.section
macro AsignColValues
mov reg[KeyPort], ~Filas ; Activo todas las Filas
mov A, reg[KeyPort] ; Leo el Puerto
cmp A, Col1
jz Columna1
cmp A, Col2
jz Columna2
cmp A, Col3
jz Columna3
cmp A, Col4
jz Columna4
mov A,0x00
ret
Columna4:
mov A, @3
ret
Columna3:
mov A, @2
ret
Columna2:
mov A, @1
ret
Columna1:
mov A, @0
ret
endm
ReadKey:
_ReadKey:
mov reg[KeyPort],~Columnas ; Activo todas las Columnas
mov A, reg[KeyPort] ; Leo el Puerto
cmp A, Row1
jz Fila1
cmp A, Row2
jz Fila2
cmp A, Row3
jz Fila3
cmp A, Row4

MC. Edgar Mauricio Romero Lpez


Dispositivos de Control. Gua de Practicas.
jz Fila4
mov A,0x00
ret
Fila1: // C1, C2, C3, C4
AsignColValues '1', '2', '3', 'A'
Fila2:
AsignColValues '4', '5', '6', 'B'
Fila3:
AsignColValues '7', '8', '9', 'C'
Fila4:
AsignColValues '*', '0', '#', 'D'
.endsection

Este programa no es muy diferente a como hicimos nuestra subrutina en la prctica anterior. Sin embargo hay

algunas diferencias que hacen posible llamarlas desde C. La primera est en las lneas 21, 22, 58 y 59 del programa.

Las Primeras dos lineas sirven para que todos los archivos del proyecto tengan acceso a la

subrutina ReadKey que hicimos. Aqu puedes ver que la exportamos 2 veces. Una vez con el

nombre ReadKey y otra con el nombre _ReadKey la razon de exportarlo de esta manera, es

que cuando llamamos a una subrutina en C, el compilador agrega de manera automtica el

carcter _ al principio del combre cuando compila el programa. De esta manera, cuando

nosotros usamos la subrutina LED _On() en C, al compilarla y pasarla a ensamblador queda

traducida como call _LED_ON. Exportamos nuestra subrutina con ambos nombres, para poder

llamarla tanto de C como de Ensamblador por medio del mismo nombre, ya que el ensamblador

no agrega el guin bajo al nombre. En las ultimas dos lineas podemos ver que nuestra subrutina

puede ser llamada con cualquiera de los dos nombres, ya que ambas etiquetas tienen el mismo

valor.

Es Recomendable que cada subrutina que creemos se encuentre dentro de las directivas

.section y .endsection de esta manera, si una subrutina en particular no es utilizada, su

cdigo no se agregara a nuestro programa, por lo que usaremos menos memoria de codigo.

Vuelve al men File y selecciona New File, o Presiona el cono de Archivo Nuevo en la barra de mens. Te
aparecer una ventana pidindote el tipo y nombre del archivo que vas a crear. Selecciona .h File y dale como Nombre
Subrutinas. Esto creara un archivo de cabeceras de C. En este le diremos al compilador de C que subrutinas en
ensamblador existen, y como funcionan.
MC. Edgar Mauricio Romero Lpez
Dispositivos de Control. Gua de Practicas.

Teclea las siguientes lneas en este archivo:

// Definicion pragma para las subrutinas en ensamblador


#pragma fastcall16 ReadKey

// Cabeceras de las Subrutinas en ensamblador


extern BYTE ReadKey(void);

La primera lnea le dice al compilador que existe una funcin hecha en ensamblador que utiliza los mtodos
fastcall16 para pasado de argumentos desde y hacia C. La segunda lnea le indica que nuestra subrutina se encuentra
en un archivo diferente a nuestro programa principal (extern), regresa un dato tipo BYTE y no es necesario pasarle
ningn parmetro (void).

Los mtodos de pasado de argumentos mediante fastcall16, establecen la forma en que una subrutina en
ensamblador recibe y entrega parmetros cuando es llamada desde C. Veamos los siguientes ejemplos:

Parmetros de Entrada en
Declaracin en C Resultados en Ensamblador
Ensamblador
void MiFuncion(void) Ninguno Ninguno
void MiFuncion(char Param1) A = Param1 Ninguno
void MiFuncin(char Param1, char Param2) A = Param1 Ninguno
X = Param2
void MiFuncin(int Param1) A = < Param1 (LSB) Ninguno
X = > Param1 (MSB)
void MiFuncion(ptr* Param1) X = < Param1 (LSB) Ninguno
A = > Param1 (MSB)
char MiFuncion(void) Ninguno A = ResultChar
int MiFuncion(void) Ninguno A = < Param1 (LSB)
X = > Param1 (MSB)
ptr* MiFuncion(void) Ninguno X = < Param1 (LSB)
A = > Param1 (MSB)
void MiFuncion(char Param1, int Param2) [SP-3] = Param1 Ninguno
[SP-4] = < Param2 (LSB)
[SP-5] = >Param2 (MSB)
void MiFuncion(int Param1, int Param2) [SP-3] = < Param1 (LSB) Ninguno
[SP-4] = > Param1 (MSB)
[SP-5] = < Param2 (LSB)
[SP-6] = >Param2 (MSB)
void MiFuncion(ptr* Param1, ptr* Param2) [SP-3] = < Param1 (LSB) Ninguno
[SP-4] = > Param1 (MSB)
[SP-5] = < Param2 (LSB)
[SP-6] = >Param2 (MSB)

En la tabla se puede ver que cuando los parmetros de entrada de la funcin son 1 o 2 bytes, se pasan por
medio de los registros internos, cuando los datos son ms de 2 bytes, se pasan por medio del stack, guardando los
parmetros en el orden inverso al que se define en la cabecera de C, y si alguno de los datos es de ms de un byte, se
comienza a guardar primero los bytes mas significativos, y por ltimo los menos significativos. Cuando los valores de
retorno son de ms de 2 bytes, se deben regresar por medio de punteros o variables globales.

Si la rutina se utiliza en ensamblador, es necesario volver el stack al tamao adecuado despus de llamar a una
subrutina. Por ejemplo una subrutina que en C tiene la cabecera:

extern void MiFuncion(int Dato1, int *ptrDato2);

En ensamblador se llamara de la siguiente manera:

MC. Edgar Mauricio Romero Lpez


Dispositivos de Control. Gua de Practicas.

mov A, >ptrDato2 ; MSB ptrDato2


push A
mov A, <ptrDato2 ; LSB ptrDato2
push A
mov A, [Dato1] ; MSB Dato1
push A
mov A, [Dato1+1] ; LSB Dato1
push A
call MiFuncion ; Llamado a la funcin
add SP, -4 ; Regresa el Stack a su tamao original

Compila y corre el programa. Hace lo que esperabas? _______________ Por qu?

Compn el Cdigo del Programa, de tal manera que se adquieran los datos del teclado de forma correcta.

Ahora, crea 3 subrutinas en ensamblador, que puedan llamarse desde C. Las Cadenas de entrada de estas
subrutinas debern poder trabajar con las cadenas, sin importar en que pgina estn.

La primera deber comparar 2 cadenas (null - terminated) y regresar 1 si cadena1 inicia con la cadena2. Deber
estar declarada en C como: extern BYTE StrStartsWith(char *Cadena1, const char *Cadena2);

La segunda deber convertir una cadena (null - terminated) que contenga caracteres, nmeros y smbolos, a una
cadena que contenga solo nmeros smbolos y letras minsculas. Deber estar declarada en C como: extern *Ptr
LowerStr(char *CadenaFuente, char *CadenaDestino);

La ltima deber convertir un arreglo de 3 caracteres numricos ASCII a un nmero binario entre 0 y 999. El byte
2 del arreglo deber contener las unidades, el uno las decenas y el cero las centenas; en caso de que alguno de los
caracters no corresponda a un nmero ASCII, se deber regresar 0xFFFF. Deber estar declarada en C como: extern
WORD StrNum2Byte(char *Numeros);

Documenta debidamente las rutinas ponindole comentarios e indicando al inicio de cada una, que registros
modifica, y sus requerimientos de memoria en caso de tenerlos.

Haz un programa en C para demostrar el funcionamiento de tus funciones. Llama a este nuevo proyecto
Practica3b.

MC. Edgar Mauricio Romero Lpez

Potrebbero piacerti anche