Acceder arduino desde ensamblador 8086

Hola,

Tengo un arduino escupiendo datos en ASCII por el puerto de serie, me gustaría acceder a ellos desde un programa hecho en ensamblador (8086), no sé si alguno puede echarme una mano.
Tengo que hacer un driver?

Saludos

¿Vas a recibir los datos del Arduino desde un programa hecho en ensamblador? Eres un tio valiente. ¿Desde que S.O. lo vas a hacer?

pues mi idea es poner un arduino con un sensor, enviar esos datos por el serie y desde un pc (me da igual el sistema operativo) leer usando ensamblador.

Hombre... para leer un puerto serie en ensamblador necesitas apoyarte en el S.O., que es quien te va a proporcionar los servicios adecuados. Cualquier lenguaje de alto nivel va a abstraer toda la capa de comunicación con el puerto serie en funciones o métodos a los que llamar. Cuando preguntas si lo que tienes que hacer es un driver, está bastante claro que no lo tienes muy claro. Lo primero que has de saber es que S.O. vas a usar, porque puede ser un driver, o un modulo de kernel, o, lo mas normal, un programa residente o un daemon. Lo que no acabo de entender es el motivo por el que quieres hacerlo con ensamblador, y de verás que siento curiosidad.
Lo dicho. Dependiendo de en que S.O. vas a correr tu programa, las opciones varian (y mucho). con todo, lo mas sencillo seria tirar de un lenguaje de alto nivel.

El motivo es para presentarlo en la universidad como practica en la universidad.
Que no lo tengo claro está claro, por eso pregunto :slight_smile:

El sistema operativo Windows. Lo que me gustaría saber es el primer paso, hacia donde enfocarme. ¿Se puede hacer solo con interrupciones? ¿con system calls? ¿haciendo un driver?

En un lenguaje de alto nivel, pues hombre ya sé que es sencillo por eso lo intento hacer en ensamblador.

import serial
[x for x in serial.read() if x == 'c']

Ok. Creo que una solucion elegante podria ser instalar una rutina de servicio de interrupcion para el puerto serie. La idea es que, cuando hay actividad en esa interrupcion, se ejecuta la ISR que tu has instalado. Al menos, eso funcionaba en msdos (hace mucho que no programo para windows a tan bajo nivel). Si quieres hacerlo aun a mas bajo nivel, debes reprogramar el controlador de interrupciones. Basicamente, este chip se ocupa de decir que INT se dispara cuando hay corriente en una linea IRQ. Tradicionalmente, la IRQ 4 suele asignarse a COM1 y por omision, esta IRQ dispara la int 12H (no te lo hago seguro, lo digo de memoria). Asi, a bote pronto, no se me ocurre mucho mas, pero cuenta conmigo para lo que pueda ayudarte.

Si quieres hacer algo de bajo nivel,pero Windows....Usar comunicación serie con la API de Windows?? Puede ser más interesante que hacerlo en ensamblador.... :wink:

http://dev.emcelettronica.com/serial-port-communication-excel-vba

http://www.codeguru.com/cpp/i-n/network/serialcommunications/article.php/c5425

Yo no lo he hecho nunca.... ;D

gracias!!!! por interrupciones sería perfecto! no sabía que podía comunicarme con el puerto de serie así.
según veo en

IRQ3 -> 0B Puertos serie COM2/COM4
IRQ4 ->0C Puertos serie COM1/COM3

Voy a ver si encuentro en que registros escribe cuando recibe datos del puerto de serie, si es que lo hace así :slight_smile:

Entonces tendría que hacer una isr, para sustituir la isr:

INTER SEGMENT AT 0 ; segmetno en la tabla de vectores para manejar los vectores como si fueran variables.
org 4*0C ; con esto marco un offset inicial, asÌ la variable empieza en el offset donde esta la isr del puerto de serie. Sin inicializar para no machacar el valor que hay
vector_ip dw (?) ; primero esta el offset, luego la direccion de segmento
vector_cs dw (?)
INTER ENDS

cambia proc
cli;
mov ax,vector_ip
mov guarda_ip,ax
mov ax,vector_cs
mov guarda_cs,ax ; guardo lo que hay

mov vector_ip,offset rutina ; redirecciono a mi rutina
mov vector_cs,cs ;
sti
ret
cambia endp

rutina proc far
;obtener datos del arduino/serie, de un registro?
; poner datos leídos en una cadena
mov dx, offset cadena
mov ah,9 ; para visualizar cadenas con la interrupción 21h
int 21h ; hay que pasarle en DX la dirección de la cadena (no lo
rutina endp

Voy bien? Qué pasa cuando se lanza la isr? se guarda en algún registro la info del puerto de serie? supongo que será algo más complejo y habrá que trabajar con la velocidad, paridad, etc, no?

he dado con está web Control de los puertos en Lenguaje ensamblador

parece que hace justo lo que quiero pero más sencillo :slight_smile: a ver si puedo probarlo y os digo, muchas gracias!!

Los registros son 3F8 y 3E8 para COM1 y COM2.

Para instalar la rutina de interrupcion, recuerdo que la int 21 de MSdos (probablemente heredada en el API de Windows) tienes dos funciones que te resultaran muy interesantes, que son IsrIst (instala una rutina de servicio en un vector de interrupcion) y SyExitStay (termina el programa, dejando residente un fragmento del codigo). Si te interesa, te puedo buscar los parametros de las funciones.

Hola,

Muchas gracias por las respuestas.

Respecto a los registros, en la página Control de los puertos en Lenguaje ensamblador he visto este fragmento de código:

mov ah,0 ;servicio 00 de INT 14h: inicializar puerto
mov a1,83 ;configuración: 1200 baudios, no paridad,
;un bit de parada, 8 bits de datos
mov dx,00 ;Seleccionar puerto COM1
int 14 ;interrupción del BIOS
mov ah,4c ;servicio 4ch de INT 21h: terminar
int 21 ;interrupción servicio del DOS

Según la página si pongo el serivicio 02:
mov ah, 02
en AL tendré el dato que venga del puerto de serie.

donde debo usar los registros 3F8 y 3E8 ?

Si utilizas la funcion de la interrupcion, no necesitas acceder directamente al puerto. De hecho, es la interrupcion la que accede a esos puertos para devolverte el valor leido en AL.

Veamos: en el fragmento de codigo que has puesto, estas empleando el BIOS. Como ya soy muy viejo, tengo libros muy antiguos que tratan de todo eso, y no he podido resistirme a la morriña y los he abierto de nuevo. La interrupcion 14H del BIOS tiene las siguientes funciones:

00H->prepara el puerto de comunicaciones
01H->envia un caracter por el puerto de comunicaciones
02H->Lee un caracter del puerto de comunicaciones
03H->Busca el estado del puerto de comunicaciones
04H->Preparacion ampliada del puerto de comunicaciones
05H->Lee o escribe el registro de control del Modem
En AH se carga el numero de la funcion, en AL elparametro de entrada (caracter a escribir, valores de configuracion de velocidad+paridad+etc) y en DX el numero de puerto(0 para com1, 1 para com2). La funcion te devuelve el estado en AH y el dato leido en AL (mas o menos). Una vez cargados en AH y AL los valores y en DX el numero de puerto, se llama a la INT 14H. La llamada que hace tu codigo de programa a la Int 21 es para terminar el programa.
Saludos

Hola, muchas gracias por todo

Finalmente salió :

MOV AH,00 ;inicializar el puerto
MOV AL,11110011b ; velocidad 9600, N,un bit de stop, 8 bit de datos....
MOV DX,00 ; puerto com1
INT 14H
Esperar:
mov dx,00
mov ah,02h
int 14h
test ah,01h; si el bit 1(dato listo) esta puesto a cero no hay dato listo

en esta página están todas las configuraciones del puerto:

jz Esperar ;salta y vuelve a verificar

parece que he cantado victoria antes de tiempo. Leer datos funciona sin problemas pero escribir nada de nada, siempre me da un 80H, que significa un time out

El código es el siguiente
enviar proc
MOV AH,00 ;inicializar el puerto
MOV AL,11101011b ; velocidad 9600, N,un bit de stop, 8 bit de datos....
MOV DX,00 ; puerto com1
INT 14H
MOV AH, 1 ; enviar
MOV AL, 'S' ; envio un caracter
MOV DX, 00 ; puerto com1
INT 14H
RET
enviar endp

El código de recibir es el siguiente (funciona bien):

recibir proc
push bx
MOV AH,00 ;inicializar el puerto
MOV AL,11110011b ; velocidad 9600, N,un bit de stop, 8 bit de datos....
MOV DX,00 ; puerto com1
INT 14H

Esperar:
mov dx,0000
mov ah,03h
int 14h
test ah,01h; si el bit 1(dato listo) esta puesto a cero no hay dato listo
jz Esperar ;salta y vuelve a verificar
mov dx,0000
mov ah,02h
int 14h
mov car, al
pop bx
ret
recibir endp