Proyecto Electronico .com

Diseños con leds, alarmas, compuertas lógicas, antenas y proyectos de electrónica en general


ZFM-206SA ZFM-201SA conectado a raspberry pi o pc serial.

ZFM20 conectado a la PC a través del puerto serial.

Llamo módulo ZFM20 a cualquiera de la serie, aunque puede ser ZFM-201SA o ZFM-206SA

Esta es la experiencia utilizando el módulo de la serie ZFM20, debido a la necesidad de un compañero de conectar dicho módulo a su Raspberry Pi utilizando el lenguaje Python, como no tenía una conecté el ZFM20 a mi computadora personal (PC)
No soy experto en programación, pero conozco algo de lenguajes como C y ensamblador, esta fué mi primera experiencia con Python.

El módulo ZFM20 funciona mejor con 5 Voltios, para alimentarlo utilizo un transformador de 9 voltios AC y un regulador 7805, además aprovecho para tomar un voltaje negativo necesario para el puerto RS-232 de la PC.


Fuente para zfm20


En la alimentación negativa utilizo un diodo zener de 5.6 voltios para conservar voltajes parecidos entre positivo y negativo, aunque no es un valor indispensable porque el 1 lógico de RS232 puede ser de -3 a -12 voltios.


Para adaptar el módulo con la computadora construí un adaptador de TTL a RS232 simple, con dos transistores y me funcionó perfectamente:

adaptador ttl a rs232


Debemos notar que la salida(TX) del ZFM20 se conecta con la entrada(RX) del RS232
y la entrada(RX) a la salida(TX) del RS232.

ZFM20 conectado a la Raspberry pi, comunicación serial (TTL).

Para conectar el modulo de identificación de huellas dactilares ZFM20 a la Raspberry pi debemos
asegurarnos de tener bien claro la ubicación de cada patilla para no dañar algo.


Estos son los datos que utilizo para conectarlo:

de serial raspberry pi a zfm20raspberry pi gpio serial

Además recordar que en Linux este puerto de la Raspberry pi es: /dev/ttyAMA0.

Protocolo de comunicación serial del ZFM20.

El modulo de identificación de huellas dactilares ZFM20 utiliza comunicación serial asincrónica, semiduplex.
La velocidad de comunicación por defecto es de 57600bps, siendo ajustable de 9600 a 115200bps, aunque al principio es algo dificil, y podemos hacer nuestras pruebas a 57600bps.
El formato de la trama es de 10 bits, 1 bit de inicio, 8 bits de datos y un bit de parada (no bit de verificación).

En Linux (Ubuntu) cuando el puerto está correctamente configurado :
baudrate=57600, bytesize=8,# parity="N", stopbits=1



 

 
El paquete de instrucciones es una cadena de 12 o más bytes.

Es enviado en el siguiente orden:

HeaderAddressPackage identifierPackage lengthPackage contentsChecksum
2 bytes4 bytes1 byte2 bytesVariable2 bytes

Header
Es el encabezado propio de este módulo, siempre será: 0xEF01H (EF01H)
Enviando primero el Byte 0xEF y de segundo el byte 0x01.

Address
Es la identificación de cada módulo, por defecto tiene 0xFFFFFFFF, puede ser cambiado con una instrucción pero si solo vamos a utilizar uno podemos dejar esa misma.
Son 4 bytes y es enviado primero el byte más significativo.

Package identifier
El identificador del paquete indica si es una cadena de instrucciones (0x01), paquete de respuesta del módulo(0x07).
Paquete de datos(0x02): vienen solo después de algun paquete que previamente lo indique, y el paquete final de una serie de paquetes de datos(0x08).

Package length
Indica el tamaño del paquete de datos que se envía, incluyendo solamente el contenido de Package contents y checksum, como en el contenido debe ir por lo menos una instrucción y checksum son dos bytes el mínimo es 3.

Package contents
En el contenido pueden ir comandos, resultados, comandos con datos, parámetros,etc.

Checksum
Es la suma del contenido de todos los datos en Package contents, package identifier y package length byte por byte.
Si el resultado supera el tamaño en los 2 bytes (0xFFFF) serán ignorados los bytes más significativos del resultado (overflow).

Ejemplo de comunicación con Python

Para verificar que hay comunicación utilizamos la instrucción llamada handshake (0x17)

Donde Instruction code y Control code conforman Package contents
Y asumimos que Address utiliza el valor por defecto 0xFFFFFFFF.

2 bytes4 bytes1 byte2 bytes1 byte1 byte2 bytes
HeaderAddressPackage identifierPackage lengthInstruction codeControl codeChecksum
0xEF010xFFFFFFFF0x010x00040x170x000x001C


La respuesta correcta de comunicación sera esta:

2 bytes4 bytes1 byte2 bytes1 byte2 bytes
HeaderAddressPackage identifierPackage lengthConfirmation codeChecksum
0xEF010xFFFFFFFF0x070x00030x000x000A

Confirmation code es 0x00 cuando la comunicación es correcta,
y es 0x01 cuando hubo error en el paquete o 0x1D cuando hay error del puerto.
Puede devolver 0x21 cuando se ha utilizado la instrucción SetPwd (0x12) y no se ha verificado el password (VfyPwd 0x13).

Aunque por lo general si el error es por Address erroneo o puerto no accesible lo que ocurre es que no obtenemos respuesta alguna.

Vamos a probar con el módulo de Python pySerial.     http://pyserial.sourceforge.net/
Utilizando Ubuntu 12.04 y Python 2.7.3

#!/usr/bin/python
#
import serial
ser = serial.Serial('/dev/ttyS0', 57600, timeout=2)
print ser      # Despliega datos del puerto serial 

ser.write(chr(0xEF))  # header_highbits
ser.write(chr(0x01)) # header_lowbits
ser.write(chr(0xFF))  # byte addr 1 H
ser.write(chr(0xFF))  # byte addr 2
ser.write(chr(0xFF))  # byte addr 3
ser.write(chr(0xFF))  # byte addr 4 L
ser.write(chr(0x01)) # Package identifier 
ser.write(chr(0)) # length_highbits
ser.write(chr(0x04)) # length_lowbits
ser.write(chr(0x17)) # Instruction code 
ser.write(chr(0)) # Control code 
ser.write(chr(0)) # checksum_highbits
ser.write(chr(0x001C)) # checksum_lowbits

print "\nRespuesta de ZFM20xx\n"
cadena = ser.read(12)  # leer 12 bytes (espera=timeout)
for i in range(12):
	print(hex(ord(cadena[i]))),

ser.close()     # cierra puerto serial

raw_input("\n Presione Enter para salir")


Recuerde que debe tener el módulo de Python pyserial instalado   apt-get install python-serial
Copiamos el código en un archivo, por ejemplo prueba1.py
En Linux necesitamos privilegios (sudo en Ubuntu) o le damos privilegios al puerto com a utilizar,
en mi caso /dev/ttyS0, en la RaspBerry pi es /dev/ttyAMA0,
si utiliza un adaptador USB a serial debe de averiguar el puerto
Información útil: www.iearobotics.com ct11.html

En el ejemplo no utilizo sudo porque mi puerto COM1 (ttyS0) ya tiene los privilegios, info: www.ubuntu-es.org serial


Ejemplo codigo python


Obtener respuesta es nuestro primer paso, para poder probar las demás instrucciones del modulo de identificación de huellas dactilares ZFM20.
Me hice un paquete de funciones donde voy estudiando las diferentes instrucciones de este módulo o sensor.
Funciona, aunque algún programador Python puede encontrar formas mejores de emplear el código.

zfm20.py

Utilizando las funciones de zfm20.py

Colocamos el archivo zfm20.py en alguna carpeta donde podamos abrir la consola facilmente.
y podemos usar la consola interactiva de Python.
Llamando todos las funciones de zfm20.py

>>from zfm20 import *
>>ser.isOpen()
>>handshake(0xFFFFFFFF)
>>getRandomCode(0xFFFFFFFF)
>>VfyPwd(0xFFFFFFFF,0)
>>cerrar_puerto()
>>exit()

De esta manera podemos ir probando funciones para nuestro programa.
En la consola se ve así:
probando funciones del zfm20.py


from zfm20 import * importamos todas las funciones en zfm20.py ser.isOpen() es una función de pySerial que devuelve True si el puerto (ser) se encuentra abierto, o False si se encuentra cerrado.

handshake(0xFFFFFFFF) es la función de zfm20.py para verificar la comunicación, se le indica la dirección de módulo que por defecto es 0xFFFFFFFF.

getRandomCode(0xFFFFFFFF) le pide al módulo que genere un número aleatorio (random).

VfyPwd(0xFFFFFFFF,0) es para verificar el password que por defecto es 0 (0x00000000)

cerrar_puerto() no debemos olvidar de cerrar el puerto antes de salir de nuestro programa o rutina.

exit() nos salimos de la consola interactiva de Python.

La función SetPwd(address,pwd) debe manejarse con cuidado, ya que cuando se le da un password hay que verificarlo cada vez que encendemos el módulo ZFM, de no ser así solo responde la instrucción handshake, que devuelve el código de error 0x21 (verificar password).
para eleminar el password hay que poner 0, SetPwd(0xFFFFFFFF,0) que está por defecto en nuestra función. No sin antes verificar el pasword que habiamos puesto con VfyPwd(address,pwd)

Para guardar cada huella se debe seguir un procedimiento, que es capturar la imagen de huella con genImg(), esa imagen se transforma en un buffer con img2Tz(), luego se captura una nueva imagen de la huella, para ser convertida en el otro buffer (solo existen buffer1 y 2). La función regModel() crea un modelo (template) en base a las dos imágenes y lo devuelve en ambos buffers.

Con la función store() guardamos el modelo de huella en la memoria flash del módulo,
si es necesario conocer de quien es cada huella hay que crear un índice de huellas, con el número de cada huella (página), y no se debe utilizar la función deletChar() porque nos cambia el valor del índice de las huellas. Por ejemplo si tenemos 10 huellas, quedan numeradas de 0 a 9, al borrar la huella 6, la huella 7 pasa a ser la 6, la 8 será la 7, etc.
Para borrar es mejor remplazar huellas con la función store()

Para comparar las huellas guardadas en la memoria flash del módulo ZFM20 con una huella que coloquemos en el sensor primero hay que capturar la huella con genImg(), luego la convertimos en cualquiera de los 2 buffer con img2Tz(), entonces utilizamos search() al cual hay que indicarle en cual buffer colocamos la huella, en cual página comenzar la búqueda y a partir de esta cuantas páginas o huellas buscar.

Este es un ejemplo de funciones que relizé para estos procedimientos:
Las funciones a utilizar:
>guardar_nueva_huella(address,pagina)

>comparar_huella(address, buffer_id, start_page, few_pages) 




#!/usr/bin/python 

from zfm20 import *

def capturar_huella(address = 0xFFFFFFFF,buffer_id= 2):
	
	print "\n Intentando leer Huella: "
	err = genImg(address)
	if err == 0:
		error = img2Tz(0xFFFFFFFF,buffer_id) # img2Tz(address,buffer_id)	
		if err == 0:
			print "img2Tz conversion correcta"
			return 0
		else:
			print "\n img2Tz Error de conversion " + (hex(err))
			return -1
	else: 
		print "genImg error" + hex(err)	
		return -1 
###  fin capturar_huella()  ###

def guardar_nueva_huella(address = 0xFFFFFFFF,pagina = 0x0003):
	leer_sino = raw_input("\n\n Leer huella 1-? s/n ")
	if leer_sino == "s":
		capturar_huella(0xFFFFFFFF,2) # address=0xFFFFFFFF,buffer_id=1 o 2)
	else:
		print "pasar, salir"
		return -1
	leer_sino = raw_input("\n\n Leer huella de nuevo ? s/n ")

	if leer_sino == "s":
		capturar_huella(0xFFFFFFFF,1) # address=0xFFFFFFFF,buffer_id=1 o 2)
		err,score = match(0xFFFFFFFF)
		if err == 0:
			print " Huellas SI coinciden"
			print " matching score: "+(hex(score))
			err = regModel(0xFFFFFFFF) # generate a template
			if err == 0:
				store(0xFFFFFFFF,1,pagina) # store(address,buffer_id,page_id)
			else:
				print "\n error guardando - store: " + (hex(err))
				return -1
		elif err == 8:
			print " Huellas NO coinciden"
		else:
			print "\n match Error  " + (hex(err))
			return -1
	else:
		print "salir"
		return -1
###  fin guardar_nueva_huella()  ###
def comparar_huella(address = 0xFFFFFFFF,buffer_id=2,start_page=0,few_pages = 0x0):

	raw_input("\n\n Presione Enter para leer huella: ")
	err = capturar_huella(address,buffer_id)
	if err == 0:
		err,pageId,score = search(address,buffer_id,start_page,few_pages)
		if err == 0:
			print "Huella coincide con pagina:" + str(hex(pageId))
			print "Matching Score:" + str(hex(score))
		elif err == 9: print "Huella no encontrada"
		else:
			print "Error de comparacion: " + str(hex(err)) 
			return -1
		return err
	else:
		print "Error de captura o  conversion" 
		return -1

###  fin comparar_huella()  ###

No olvidemos cerrar con la función cerrar_puerto()



La mayoría de los datos obtenidos de estos manuales:
ZFM user manualV15.pdf

https://github.com/adafruit/Adafruit-Fingerprint-Sensor-Library/tree/master/documentation




Esto fué modificado por el compañero con solo las funciones que utiliza y creó un objeto.
Lo subo cuando esté más depurado.
...

TAG: Detector de huella digital ZFM20 conectado a la PC a través del puerto serial RS232
RaspBerry pi, ZFM-206SA ZFM-201SA


TI2-CAW

.Arriba.


.Menú: Proyectos de electronica.

proyectos de electronica